【发布时间】:2014-04-17 17:27:43
【问题描述】:
在片段着色器中采样全屏纹理的最佳方法是什么,例如延迟渲染器中的 g 缓冲区或后处理着色器中的场景纹理?
目前我使用以下两种方式:
-
将屏幕尺寸作为统一传递给着色器,并从
gl_FragCoord计算 (u,v):vec2 texCoord = gl_FragCoord.xy / vScreenSize; vec3 c = texture( tex, texCoord ).rgb;似乎并不理想,因为需要进行除法并且为着色器提供屏幕尺寸很麻烦。
-
将
gl_FragCoord.xy转换为ivec并使用texelFetch:vec3 c = texelFetch( tex, ivec2(gl_FragCoord.xy), 0 ).rgb;也不理想,因为需要从
float转换为int。
那么有没有更好的方法呢?我真的只想在我的像素着色器正在绘制的确切点对缓冲区进行采样。
// 编辑:
好的,根据来自顶点着色器的插值纹理坐标的建议,我设法找出了以下代码:
顶点着色器:
#version 150
uniform mat4 im_ModelViewProjectionMatrix;
in vec3 iv_Vertex;
noperspective out vec2 vVertCoord;
void main( void )
{
gl_Position = im_ModelViewProjectionMatrix * vec4(iv_Vertex, 1.0);
vVertCoord = (gl_Position.xy / gl_Position.w) * (0.5) + vec2(0.5);
}
我基本上用透视分割从剪辑空间位置计算归一化设备坐标 (NDC),然后将 NDC(范围从 [-1,1])映射到区间 [0,1]。这对于全屏四边形非常有用(即使没有透视分割,因为坐标非常简单)。我需要在我的延迟渲染器中绘制为光几何的任意几何虽然有一些问题。在顶点着色器中,我将vVertCoord 输出为红色=x 和绿色=y 的颜色:
#version 150
noperspective in vec2 vVertCoord;
out vec4 colorOut;
void main( void )
{
colorOut = vec4(vVertCoord.x, vVertCoord.y, 0, 1);
}
这是当我在点光球内时的结果,一切看起来都很好(黑线是故意渲染的):
但是,如果我靠近光几何,结果如下:
左上角的那个红色补丁在那里做什么?您不希望在禁用调试颜色的情况下以真实颜色查看结果,因为它看起来像 lsd-trip,当您移动相机时,一切都会扭曲。这与精度有关吗?请注意,当我在像素着色器中使用 gl_FragCoord 时,一切都很好。
【问题讨论】:
-
纹理坐标基于 gl_FragCoord 而不是普通的插值属性有什么特别的原因吗?在第一个示例中,这已经消除了除法的需要。 p.s.而不是 vScreenSize 你可以有屏幕尺寸的倒数(把除法变成乘法)
-
您可能不想要后者,这将消除进行任何纹理过滤的可能性。虽然您可能认为您并不真正关心这一点,但在延迟着色引擎中,以不同的分辨率进行 G-Buffer 生成和着色可能很有用(特别是在通常填充率非常有限的低端硬件上)。