如何在立方体上获得平坦法线

时间:2013-02-20 13:12:18

标签: opengl glsl opengl-3

我使用的是没有弃用功能的OpenGL,我的光计算是在片段着色器上完成的。所以,我正在做平滑的阴影。

我的问题是,当我画一个立方体时,我需要平坦的法线。平面法线表示面部生成的每个碎片具有相同的法线。

到目前为止,我的解决方案是为每个面生成不同的顶点。所以,现在我有24个(6 * 4)顶点,而不是8个顶点。

但这对我来说似乎是错误的,复制了顶点。是否有更好的方法来平常?

更新:我使用的是OpenGL版本3.3.0,我还没有支持OpenGL 4.

3 个答案:

答案 0 :(得分:9)

如果在相机空间中进行照明,则可以使用dFdx / dFdy从顶点的相机空间位置计算面的法线。

因此片段着色器看起来有点像这样。

varying vec3 v_PositionCS; // Position of the vertex in camera/eye-space (passed in from the vertex shader)

    void main()
    { 
      // Calculate the face normal in camera space
      vec3 normalCs = normalize(cross(dFdx(v_PositionCS), dFdy(v_PositionCS)));

      // Perform lighting 
      ...
      ...
    }

答案 1 :(得分:6)

因为几何着色器可以"看"一次三角形的所有三个顶点,您可以使用几何着色器计算法线并将它们发送到片段着色器。这样,您就不必复制顶点。

// Geometry Shader

#version 330 

layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;

out vec3 gNormal;

// You will need to pass your untransformed positions in from the vertex shader
in vec3 vPosition[];

uniform mat3 normalMatrix;

void main()
{
    vec3 side2 = vPosition[2] - vPosition[0];
    vec3 side0 = vPosition[1] - vPosition[0];
    vec3 facetNormal = normalize(normalMatrix * cross(side0, side2));

    gNormal = facetNormal;
    gl_Position = gl_in[0].gl_Position;
    EmitVertex();

    gNormal = facetNormal;
    gl_Position = gl_in[1].gl_Position;
    EmitVertex();

    gNormal = facetNormal;
    gl_Position = gl_in[2].gl_Position;
    EmitVertex();

    EndPrimitive();
}

答案 2 :(得分:3)

另一种选择是将MV矩阵和未旋转的AxisAligned坐标传递给片段着色器:

 attribute aCoord;
 varying vCoord;
 void main() {
    vCoord = aCoord;
    glPosition = aCoord * MVP;
 }

在片段着色器中,可以通过计算vCoord的主轴来识别法线,将其设置为1.0(或-1.0),将其他坐标设置为零 - 这是法线,必须由MV旋转 - 矩阵。