使用 opengl es 2.0 在 glsl 中进行透视变形时如何正确映射纹理

How to correctly map texture when doing perspective warping in glsl using opengl es 2.0

我正在尝试使用顶点着色器和片段着色器创建一个四角透视效果。

我设置顶点位置信息来绘制类似形状的透视图,然后在其上映射我的纹理。但是不知何故纹理没有正确映射。

这里有两张图可以说明问题。

我从这个 post 中找到一些信息 texture2DProj 也许是正确的答案,但我不太明白它是如何工作的。我试着做这样的事情,

    varying lowp vec4 TexCoordOut;
    uniform sampler2D Texture;

    void main(void) {
        gl_FragColor = texture2DProj(Texture, TexCoordOut);
    }

对于 TexCoordOut 我传入

{1, 0, 0, 1}
{1, 1, 0, 1}
{0, 1, 0, 1}
{0, 0, 0, 1}

到顶点着色器,并将其变为片段着色器。但是结果是一样的

我只知道如何将 texture2Dvec2 一起使用,如何让我的纹理坐标的其他两个分量与 texture2DProj 一起使用?

我怀疑问题是您的输入坐标呈现的是 2D 形状,而不是 3D 形状(即所有 4 个顶点的 Z 值都是恒定的)。

与其渲染 2D 形状,不如渲染一个在 3D 中倾斜的正方形,变化的插值将为您进行正确的透视划分。然后您可以使用正常的 texture2D() 操作。

在这种情况下你可能不想要投影纹理 - 你可以 - 但它不必要地复杂(你仍然需要为纹理坐标生成一个适当的 "w" 值以使透视划分工作,所以您也可以对每个顶点执行此操作,并使用不同的插值器来完成繁重的工作。

如果你真的想使用texture2DProj那么你可以将W坐标从位置复制到纹理坐标。例如:

uniform mat4 uPrj;
attribute vec2 aXY;
attribute vec2 aST;
varying vec4 st;
void main(void) {
    vec4 pos=uPrj*vec4(aXY,0.0,1.0);
    gl_Position=pos;
    st=vec4(aST,0.0,pos.w);

    st.xy*=pos.w; // Not sure if this is needed with texture2DProj
}

但是,我通过将四边形拆分为较小的四边形网格,然后将每个小四边形拆分为两个三角形,从而解决了透视中的纹理问题。然后你可以像这样使用 GLSL 代码:

uniform mat4 uPrj;
attribute vec2 aST;  // Triangles in little squares in range [0,1].
varying vec2 st;
void main(void) {
    vec2 xy=aST*2.0-1.0; // Convert from range [0,1] to range [-1,-1] for vertices.
    gl_Position=uPrj*vec4(xy,0.0,1.0);
    st=aST;
}

以上代码运行速度足够快(甚至可能比 texture2DProj 更快),因为片段着色器运行相同的像素数,片段着色器可以使用更简单的 texture2D 方法(不需要片段投影)。

您可以为每个四边形重复使用 aST 中的三角形网。这是我在 JavaScript:

中制作 aST 的方法
        var nCell = 32;
        var nVertex = nCell * nCell * 6;
        var arST = prog._arST = new Float32Array(nVertex * 2);
        var k = 0;
        for (var j = 0; j < nCell; j++) {
            var j0 = j / nCell;
            var j1 = (j + 1) / nCell;
            for (var i = 0; i < nCell; i++) {
                var i0 = i / nCell;
                var i1 = (i + 1) / nCell;
                arST[k++] = i0;
                arST[k++] = j0;
                arST[k++] = i1;
                arST[k++] = j0;
                arST[k++] = i0;
                arST[k++] = j1;
                arST[k++] = i0;
                arST[k++] = j1;
                arST[k++] = i1;
                arST[k++] = j0;
                arST[k++] = i1;
                arST[k++] = j1;
            }
        }
        gl.bindBuffer(gl.ARRAY_BUFFER, prog._bufferST);
        gl.bufferData(gl.ARRAY_BUFFER, prog._arST, gl.STATIC_DRAW);