我正在使用没有弃用功能的 OpenGL,并且我的光照计算是在片段着色器上完成的。所以,我正在做平滑的阴影。
我的问题是,当我绘制立方体时,我需要平面法线。所谓平面法线,我的意思是面部生成的每个片段都具有相同的法线。
到目前为止,我对此的解决方案是为每个面生成不同的顶点。所以,现在我有 24(6*4) 个顶点,而不是 8 个顶点。
但这对我来说似乎是错误的,复制顶点。有没有更好的方法来获得平坦的法线?
更新:我使用的是 OpenGL 版本 3.3.0,我还不支持 OpenGL 4。
如果您在相机空间中进行照明,则可以使用 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
...
...
}
由于几何着色器可以一次“看到”三角形的所有三个顶点,因此您可以使用几何着色器计算法线并将它们发送到片段着色器。这样,您不必复制顶点。
// 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();
}
另一种选择是将 MV-matrix 和未旋转的 AxisAligned 坐标传递给片段着色器:
attribute aCoord;
varying vCoord;
void main() {
vCoord = aCoord;
glPosition = aCoord * MVP;
}
在片段着色器中,可以通过计算 vCoord 的主导轴来识别法线,将其设置为 1.0(或 -1.0),将其他坐标设置为零——即法线,它必须由 MV 矩阵旋转。