首页 文章

透视校正着色器渲染

提问于
浏览
0

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

我有一个非常复杂的实现基于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

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

    确实,“平滑”关键字不是问题,而是投影纹理映射 .

    为了解决这个问题,我直接从我的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;
    }
    

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

相关问题