5

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

我的问题是,当我绘制立方体时,我需要平面法线。所谓平面法线,我的意思是面部生成的每个片段都具有相同的法线。

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

但这对我来说似乎是错误的,复制顶点。有没有更好的方法来获得平坦的法线?

更新:我使用的是 OpenGL 版本 3.3.0,我还不支持 OpenGL 4。

4

3 回答 3

10

如果您在相机空间中进行照明,则可以使用 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 
      ...
      ...
    }
于 2013-02-20T13:48:05.743 回答
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();
}
于 2013-02-20T13:44:08.083 回答
3

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

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

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

于 2013-02-20T14:00:56.047 回答