透视校正着色器渲染

时间:2014-10-13 17:01:49

标签: opengl glsl compatibility

我想在一个通过非仿射变换(更具体地说是透视变换)变换的矩形上放置一个纹理。

我有一个非常复杂的实现,基于openscenegraph并加载我自己的顶点和片段着色器。 问题始于着色器很久以前写的并使用GLSL 120。

OpenGL方面是用C ++编写的,它以最简单的形式加载纹理并将其应用于四边形。直到最近,一切都运行正常,因为四边形最多是仿射变换(旋转+平移),因此纹理的渲染是正确的。

现在我们想要支持任何形状的四边形,包括这样的东西: http://ibin.co/1dbsGPpzbkOX

如上图所示,中间的纹理不正确(箭头所示) 经过数小时的研究,我发现这是由于OpenGL将四边形分成三角形并独立渲染每个三角形。如果我的四边形如图所示,这当然是不正确的,因为第四点会影响纹理拉伸。 然后我甚至发现这个问题有一个名称:它是“透视不正确的纹理坐标插值”,如下所述: [1]

寻找解决方案,我遇到了这篇文章,其中提到了在以后的GLSL版本中使用“smooth”属性:[2] 但这意味着将我的着色器更新为更新的版本。

我发现的替代方法是使用GL_Hints,如下所述:[3] 但这里的缺点是它只是一个提示,并且没有办法确保它被使用。

现在我已经展示了我的研究,这是我的问题:

更新我的(复杂)着色器和所有与其一起使用的OpenGL以遵守新的OpenGL管道范例将非常耗时,因此我尝试使用GLSL“版本330兼容性”并将“变化”更改为“平滑“和”平滑“,以及在C ++方面添加GL_NICE提示,但这些更改并没有解决我的问题。这是正常的,因为兼容模式不知何故不支持这种正确的透视变换?或者还有什么我需要做的事情? 或者,有没有更好的方法来获得此功能而无需重构所有内容?

这是我的顶点着色器:

#version 330 compatibility
smooth out vec4 texel;

void main(void) {
    gl_Position = ftransform();
    texel = gl_TextureMatrix[0] * gl_MultiTexCoord0;
}

并且片段着色器太复杂了,但它以

开头
#version 330 compatibility
smooth in vec4 texel;

1 个答案:

答案 0 :(得分:0)

使用derhass的提示我以一种截然不同的方式解决了这个问题。

"顺畅&#34>确实如此。关键字不是问题,而是投影纹理映射。

为了解决这个问题,我直接从我的C ++代码传递给了frag着色器透视变换矩阵,并计算了"正确的"我自己的纹理坐标,不使用GLSL的重心插值。

为了帮助任何有同样问题的人,以下是我的着色器的简化版本:

.vert

#version 330 compatibility

smooth out vec4 inQuadPos;      // Used for the frag shader to know where each pixel is to be drawn

void main(void) {
    gl_Position = ftransform();
    inQuadPos = gl_Vertex;
}

.frag

uniform mat3 transformMat;      // the transformation between texture coordinates and final quad coordinates (passed in from c++)
uniform sampler2DRect source;

smooth in vec4 inQuadPos;
void main(void)
{
    // Calculate correct texel coordinate using the transformation matrix
    vec3 real_texel = transformMat * vec3(inQuadPos.x/inQuadPos.w, inQuadPos.y/inQuadPos.w, 1);
    vec2 tex = vec2(real_texel.x/real_texel.z, real_texel.y/real_texel.z);
    gl_FragColor = texture2DRect(source, tex).rgba;
}

请注意,上面的片段着色器代码没有经过完全相同的测试,所以我不能保证它可以开箱即用,但它应该主要用于那里。