背面剔除线条

时间:2015-03-01 14:50:12

标签: opengl directx shader linear-algebra

我在3D空间中有圆圈(图像上的红色),带有法线(白色)

circle with normals

此圆圈被绘制为线条。

问题是:我需要使用片段着色器代码中的丢弃仅绘制其法线指向相机(法线和相机矢量之间的角度<90)的像素。像背面剔除但是线条。

red is visible part of circle

圆圈的红色部分是我需要绘制的,黑色是我需要在片段着色器中丢弃的内容。

好例子是3DS Max旋转小发明,隐藏了线条的背面:

3ds max rotation gizmo

片段着色器中的

所以,我有:

if(condition)
    discard;

帮我解决这个问题。考虑到正交和透视相机都会很好。

1 个答案:

答案 0 :(得分:4)

嗯,你已经描述过你的病情了:

  

(法线和相机矢量之间的角度<90)

您必须将法线转发到片段着色器(不要忘记在FS中重新标准化,插值将改变长度)。并且您需要查看向量(与法线相同的空间,因此您可以将法线转换为眼睛空间,或使用世界空间,甚至将视图方向/相机位置转换为对象空间)。由于条件angle(N,V) >= 90 (degrees)cos(angle(N,V)) <= 0相同(假设归一化向量),因此您只需使用点积:

if (dot(N,V) <= 0)
    discard;

<强>更新

正如你在评论中指出的那样,你有&#34; classic&#34; GL矩阵可用。因此,在眼睛空间中进行此转换是有意义的。在顶点着色器中,放置

in vec4 vertex;  // object space position
in vec3 normal;  // object space normal direction
out vec3 normal_eyespace;
out vec3 vertex_eyespace;

uniform mat3 normalMatrix;
uniform mat4 modelView;
uniform mat4 projection;

void main()
{
    normal_eyespace = normalize(normalMatrix * normal);
    vec4 v = modelViewMatrix * vertex;
    vertex_eyespace = v.xyz;
    gl_Position=projectionMatrix * v;
}

在片段着色器中,您只需执行

in vec3 normal_eyespace;
in vec3 vertex_eyespace;

void main()
{
    if (dot(normalize(normal_eyespace), normalize(-vertex_eyespace)) <= 0)
        discard;
    // ...
}

注意:此代码假定现代GLSL使用in / out而不是attribute / varying限定符。我也假设没有内置属性。但是该代码应该很容易适应旧的GL。