Opengl es OpenGL ES 2.0中梯形的透视校正纹理

Opengl es OpenGL ES 2.0中梯形的透视校正纹理,opengl-es,opengl-es-2.0,Opengl Es,Opengl Es 2.0,我画了一个有纹理的梯形,但是结果并不像我预期的那样 在两个三角形相交的对角线处出现不连续,而不是作为一个完整的四边形出现 此图演示了这个问题: (注意:最后一幅图像并非100%忠实的表现,但它应该能够表达观点。) 梯形是使用OpenGL ES 2.0(在iPhone上)中的GL_TRIANGLE_STRIP绘制的。它完全面向屏幕绘制,并且没有倾斜(即,您看到的不是3D草图!) 我逐渐了解到我需要在顶点和/或片段着色器中执行“透视校正”,但我不清楚如何执行 我的代码包括一些简单的模型/视图/投影

我画了一个有纹理的梯形,但是结果并不像我预期的那样

在两个三角形相交的对角线处出现不连续,而不是作为一个完整的四边形出现

此图演示了这个问题:

(注意:最后一幅图像并非100%忠实的表现,但它应该能够表达观点。)

梯形是使用OpenGL ES 2.0(在iPhone上)中的
GL_TRIANGLE_STRIP
绘制的。它完全面向屏幕绘制,并且没有倾斜(即,您看到的不是3D草图!)

我逐渐了解到我需要在顶点和/或片段着色器中执行“透视校正”,但我不清楚如何执行

我的代码包括一些简单的模型/视图/投影矩阵数学,但目前没有一个会影响我的纹理坐标值更新:根据用户事实的评论,前面的陈述是不正确的

此外,我在ES 2.0规范中发现了这个花絮,但不理解它的含义:

不支持透视校正提示,因为OpenGL ES 2.0要求对所有属性进行透视插值。

如何正确绘制纹理


编辑:在下面添加了代码:

// Vertex shader
attribute vec4 position;
attribute vec2 textureCoordinate;

varying vec2 texCoord;

uniform mat4 modelViewProjectionMatrix;

void main()
{
    gl_Position = modelViewProjectionMatrix * position;
    texCoord = textureCoordinate;
}


(我在这里有点夸张,因为您的图片并没有准确显示我对梯形纹理的期望,所以您的案例中可能发生了其他情况-但一般问题是众所周知的)

纹理(默认情况下)不会在梯形上正确插值。当图形为三角形绘制时,将选择一条对角线作为边,而该边直接穿过纹理的中间,但不穿过梯形的中间(请将图形沿对角线分割-两个三角形非常不相等)

要实现这一点,您需要提供的不仅仅是2D纹理坐标-您需要提供3D(或者更确切地说,投影)纹理坐标,并在片段着色器中执行透视分割、后插值(或者使用纹理查找功能,该功能也将执行相同的操作)

下面显示了如何使用老式GL函数为梯形提供纹理坐标(出于演示目的,这些函数更易于阅读)。注释掉的线是2d纹理坐标,我用投影坐标替换了它以获得正确的插值

glMatrixMode(GL_投影);
glLoadIdentity();
格洛托(0640,0480,11000);
glMatrixMode(GLU模型视图);
glLoadIdentity();
常量浮点数=600;
常数浮动陷阱_窄=300;
常数浮点mid=320;
glBegin(GLU三角带);
gl3f(1,1,1);
//glTexCoord4f(0,0,0,1);
glTexCoord4f(0,0,0,陷阱宽度);
glVertex3f(中圈闭宽度/2,10,-10);
//glTexCoord4f(1,0,0,1);
glTexCoord4f(陷阱窄,0,0,陷阱窄);
glVertex3f(中陷窄/2470,-10);
//glTexCoord4f(0,1,0,1);
glTexCoord4f(0,陷阱宽度,0,陷阱宽度);
glVertex3f(中+陷阱宽度/2,10,-10);
//glTexCoord4f(1,1,0,1);
glTexCoord4f(陷阱窄,陷阱窄,0,陷阱窄);
glVertex3f(中间+陷阱_窄/2470,-10);
格伦德();
第三个坐标在这里没有使用,因为我们只是使用2D纹理。第四个坐标将在插值后分割其他两个坐标,提供投影。显然,如果在顶点处将其分割,您将看到获得原始纹理坐标

以下是两个渲染的外观:


如果您的梯形实际上是变换四边形的结果,那么使用GL绘制该四边形可能更容易/更好,而不是在软件中进行变换并将2D形状馈送到GL…

这里尝试的是扭曲纹理。示例片段着色器如下所示:

precision mediump float;
varying vec4 vtexCoords;
uniform sampler2D sampler;

void main()
{
   gl_FragColor = texture2DProj(sampler,vtexCoords);
}
两件看起来应该不同的事情是:

1) 我们正在使用
不同的vec4 vtexCoords。纹理坐标是4维的。
2) 使用
texture2DProj()
代替
texture2D()

根据梯形的大小边的长度,您将指定纹理坐标。以下URL可能会有所帮助:

公认的答案给出了正确的解决方案和解释,但对于那些在OpenGL(ES)2.0管道上寻求更多帮助的人来说

const GLfloat L = 2.0;
const GLfloat Z = -2.0;
const GLfloat W0 = 0.01;
const GLfloat W1 = 0.10;

/** Trapezoid shape as two triangles. */
static const GLKVector3 VERTEX_DATA[] = {
    {{-W0,    0,  Z}},
    {{+W0,    0,  Z}},
    {{-W1,    L,  Z}},

    {{+W0,    0,  Z}},
    {{+W1,    L,  Z}},
    {{-W1,    L,  Z}},
};

/** Add a 3rd coord to your texture data.  This is the perspective divisor needed in frag shader */
static const GLKVector3 TEXTURE_DATA[] = {
    {{0, 0, 0}},
    {{W0, 0, W0}},
    {{0, W1, W1}},

    {{W0, 0, W0}},
    {{W1, W1, W1}},
    {{0, W1, W1}},
};

////////////////////////////////////////////////////////////////////////////////////

// frag.glsl

varying vec3 v_texPos;
uniform sampler2D u_texture;

void main(void) 
{
    // Divide the 2D texture coords by the third projection divisor
    gl_FragColor = texture2D(u_texture, v_texPos.st / v_texPos.p);
}
或者,在着色器中,根据@maverick9888的回答,您可以使用
texture2Dproj
,尽管对于iOS/OpenGLES2,它仍然只支持
vec3
输入

void main(void) 
{
    gl_FragColor = texture2DProj(u_texture, v_texPos);
}

我还没有正确地对其进行基准测试,但对于我非常简单的情况(1d纹理),分割版本似乎有点快。

形状是作为一个经过变换和投影的四边形生成的,还是一个任意的2D形状?最简单的解决方案是在3D中渲染一个倾斜的四边形…你应该检查第二个三角形的UV。看起来像纹理偏移显示你的代码。看起来有点后缩…你的投影矩阵可能有问题。这确实会影响插值。@StefanHanke我已经添加了顶点着色器、片段着色器、绘制和更新代码片段。请让我知道这是否仍然感觉到后缩。不幸的是,
GL\u QUAD
在OpenGL ES 2.0中不可用。这种方法能否适应于
GL\u TRIANGLE\u STRIP
和ES 2.0?具体来说,我只是尝试实现上述功能,但不确定如何在着色器中使用额外的两个纹理坐标。在另外两个纹理坐标中,一个是未使用的,另一个应该用来分割前两个,就像透视变换一样。此时,我发现我可以在片段着色器中使用
texture2DProj()
代替divid
const GLfloat L = 2.0;
const GLfloat Z = -2.0;
const GLfloat W0 = 0.01;
const GLfloat W1 = 0.10;

/** Trapezoid shape as two triangles. */
static const GLKVector3 VERTEX_DATA[] = {
    {{-W0,    0,  Z}},
    {{+W0,    0,  Z}},
    {{-W1,    L,  Z}},

    {{+W0,    0,  Z}},
    {{+W1,    L,  Z}},
    {{-W1,    L,  Z}},
};

/** Add a 3rd coord to your texture data.  This is the perspective divisor needed in frag shader */
static const GLKVector3 TEXTURE_DATA[] = {
    {{0, 0, 0}},
    {{W0, 0, W0}},
    {{0, W1, W1}},

    {{W0, 0, W0}},
    {{W1, W1, W1}},
    {{0, W1, W1}},
};

////////////////////////////////////////////////////////////////////////////////////

// frag.glsl

varying vec3 v_texPos;
uniform sampler2D u_texture;

void main(void) 
{
    // Divide the 2D texture coords by the third projection divisor
    gl_FragColor = texture2D(u_texture, v_texPos.st / v_texPos.p);
}
void main(void) 
{
    gl_FragColor = texture2DProj(u_texture, v_texPos);
}