You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PixiJS:仿射投影与双线性投影的网格纹理映射实现问询

问题描述

我在PixiJS中有一个复合形状(如图:复合形状图),需要将纹理通过网格变形投影到该形状上,预期效果如图:投影效果目标图。

尝试使用PIXI.SimplePlane时,发现框架默认采用仿射变换(affine transformation),但我需要的是**四边形双线性投影(quad bi-linear projection)**的效果。

PixiJS提供的投影插件仅支持4个控制点,而我需要至少10到15个。如果无法使用该插件,是否可以通过自定义shader实现?

附带测试代码如下:

let pattern64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAEACAIAAABK8lkwAAAACXBIWXMAAAAnAAAAJwEqCZFPAAAFIGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDAgNzkuMTYwNDUxLCAyMDE3LzA1LzA2LTAxOjA4OjIxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjItMTAtMDdUMTk6MDI6NTErMDM6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMjItMTAtMDdUMTk6MDI6NTErMDM6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDIyLTEwLTA3VDE5OjAyOjUxKzAzOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo0Mjc0YWNkZS05OTYwLTQ3YTQtOTQyOS1kMGQ0MmZkNzAwZDIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDI3NGFjZGUtOTk2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";

const app = new PIXI.Application({ width: 512, height: 324, antialias: true });
document.body.appendChild(app.view);

app.loader.add('pattern', pattern64).load(inits);

function inits() {
    const graphics = new PIXI.Graphics();

    let path = [34, 100, 176, 100, 176, 224, 34, 224];
    graphics.lineStyle(0);
    graphics.beginFill(0xBCBCBC, 1);
    graphics.drawPolygon(path);
    graphics.endFill();

    path = [176, 100, 258, 60, 258, 264, 176, 224];
    graphics.lineStyle(0);
    graphics.beginFill(0xCDCDCD, 1);
    graphics.drawPolygon(path);
    graphics.endFill();

    path = [258, 60, 422, 104, 422, 220, 256, 264];
    graphics.lineStyle(0);
    graphics.beginFill(0x606060, 1);
    graphics.drawPolygon(path);
    graphics.endFill();

    path = [422, 104, 478, 104, 478, 220, 422, 220];
    graphics.lineStyle(0);
    graphics.beginFill(0x909090, 1);
    graphics.drawPolygon(path);
    graphics.endFill();

    app.stage.addChild(graphics);

    const texture = app.loader.resources.pattern.texture;
    const plane = new PIXI.SimplePlane(texture, 5, 3);
    app.stage.addChild(plane);

    let buffer = plane.geometry.getBuffer('aVertexPosition');

    //manually set just for this demo
    buffer.data[0] = 34;
    buffer.data[1] = 100;
    buffer.data[2] = 176;
    buffer.data[3] = 100;
    buffer.data[4] = 258;
    buffer.data[5] = 60;
    buffer.data[6] = 422;
    buffer.data[7] = 104;
    buffer.data[8] = 478;
    buffer.data[9] = 104;

    buffer.data[10] = 34;
    buffer.data[11] = 162;
    buffer.data[12] = 176;
    buffer.data[13] = 162;
    buffer.data[14] = 258;
    buffer.data[15] = 162;
    buffer.data[16] = 422;
    buffer.data[17] = 162;
    buffer.data[18] = 478;
    buffer.data[19] = 162;

    buffer.data[20] = 34;
    buffer.data[21] = 224;
    buffer.data[22] = 176;
    buffer.data[23] = 224;
    buffer.data[24] = 258;
    buffer.data[25] = 264;
    buffer.data[26] = 422;
    buffer.data[27] = 220;
    buffer.data[28] = 478;
    buffer.data[29] = 220;

    buffer.update();
}
body { margin: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/6.5.5/browser/pixi.js"></script>

解决方案:自定义Shader实现多控制点双线性网格投影

完全可以通过自定义Shader实现需求,核心思路是修改PIXI.SimplePlane的默认着色器逻辑,将每个网格单元的纹理采样从仿射变换替换为双线性投影计算。

实现步骤

  1. 扩展网格着色器:保留原有网格顶点结构,在片元着色器中针对每个四边形网格单元,基于四个角落的顶点UV和位置实现双线性投影采样。
  2. 传递网格元信息:为每个网格单元传递四个顶点的位置和UV信息,或在着色器中通过顶点索引计算相邻顶点。
  3. 双线性投影计算:在片元着色器中,根据当前像素在网格单元内的相对位置,通过双线性插值计算对应的纹理坐标。

完整代码示例

let pattern64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAEACAIAAABK8lkwAAAACXBIWXMAAAAnAAAAJwEqCZFPAAAFIGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDAgNzkuMTYwNDUxLCAyMDE3LzA1LzA2LTAxOjA4OjIxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjItMTAtMDdUMTk6MDI6NTErMDM6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMjItMTAtMDdUM
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 03:15:41