为什么这个glsl着色器不尊重深度指数?

时间:2013-11-28 11:21:24

标签: glsl shader

这是我正在使用的顶点着色器:

attribute vec3 v_pos;
attribute vec4 v_color;
attribute vec2 v_uv;
attribute vec3 v_rotation; // [angle, x, y]

uniform mat4 modelview_mat;
uniform mat4 projection_mat;

varying vec4 frag_color;
varying vec2 uv_vec;
varying mat4 v_rotationMatrix;

void main (void) {

    float cos = cos(v_rotation[0]);
    float sin = sin(v_rotation[0]);

    mat2 trans_rotate = mat2(
      cos, -sin,
      sin, cos
    );

    vec2 rotated = trans_rotate * vec2(v_pos[0] - v_rotation[1], v_pos[1] - v_rotation[2]);
    gl_Position = projection_mat * modelview_mat * vec4(rotated[0] + v_rotation[1], rotated[1] + v_rotation[2], 1.0, 1.0);
    gl_Position[2] = 1.0 - v_pos[2] / 100.0; // Arbitrary maximum depth for this shader.
    frag_color = vec4(gl_Position[2], 0.0, 1.0, 1.0);  // <----------- !!
    uv_vec = v_uv;
}

和片段:

varying vec4 frag_color;
varying vec2 uv_vec;

uniform sampler2D tex;

void main (void){
    vec4 color = texture2D(tex, uv_vec) * frag_color;
    gl_FragColor = color;
}

注意我是如何手动将gl_Position变量的Z索引设置为0.0 - &gt;范围内的绑定值。 1.0(上限在代码中完成;可以说,不是顶点具有z值&lt; 0或&gt; 100)。

它主要起作用。问题在于,当我渲染它时,我得到了这个:

enter image description here

这些元素的深度排序不正确,这些元素的z值分别为15,50和80,正如您可以从每个精灵的红色值中看到的那样。

呈现的正确顺序是蓝色 - &gt;顶部,紫色中间,粉红色底部;但是这些精灵正在以渲染顺序呈现。

即。它们是通过以下方式绘制的:

glDrawArrays() <--- Pink, first geometry batch
glDrawArrays() <--- Blue, second geometry batch
glDrawArrays() <--- Purple, thirds geometry batch

发生了什么事?

在冲洗之前我多少次调用gl绘制函数无关紧要;深度测试应该排除这一切吗?

您是否必须以某种方式在片段着色器内手动调用深度测试?

1 个答案:

答案 0 :(得分:1)

您说您正在将输出Z值标准化为以下范围: 0.0 - 1.0

它应该是范围: -W - + W 。给定正交投影,这意味着剪辑空间Z的范围应为: -1.0 - +1.0 。您只使用了深度范围的一半,这显着降低了深度缓冲区的分辨能力。

更糟糕的是(而且我很确定这是你实际问题的来源)看起来你通过给最远的点提供 0.0 的值来反转你的深度缓冲区,并且最接近分 1.0 。实际上, -1.0 对应于近平面, 1.0 对应于OpenGL中的远平面。

gl_Position[2] = 1.0 - v_pos[2] / 100.0;
~~~~~~~~~~~~~~
// This needs to be changed, your depth is completely backwards.


gl_Position.z = 2.0 * (v_pos.z / 100.0) - 1.0;
~~~~~~~~~~~~~
// This should fix both the direction, and use the full depth range.

但是,值得一提的是,现在gl_Position[2]gl_Position.z的值范围从 -1.0 1.0 ,这意味着它不能是用作可见颜色而没有一些缩放和偏差:

frag_color = vec4 (gl_Position.z * 0.5 + 0.5, 0.0, 1.0, 1.0);  // <----------- !!

最后,我一直在讨论规范化设备坐标,而不是窗口坐标。在窗口坐标系中,默认深度范围为0.0 =近,1.0 =远;这可能是一些混乱的根源。了解窗口坐标(gl_FragCoord)与顶点着色器中的计算无关。

您可以在片段着色器中使用它来测试您的深度范围是否设置正确:

vec4 color = texture2D(tex, uv_vec) * vec4 (gl_FragCoord.z, frag_color.yzw);

它应该产生与以下相同的结果:

vec4 color = texture2D(tex, uv_vec) * frag_color;