我使用的是没有弃用功能的OpenGL,我的光计算是在片段着色器上完成的。所以,我正在做平滑的阴影。
我的问题是,当我画一个立方体时,我需要平坦的法线。平面法线表示面部生成的每个碎片具有相同的法线。
到目前为止,我的解决方案是为每个面生成不同的顶点。所以,现在我有24个(6 * 4)顶点,而不是8个顶点。
但这对我来说似乎是错误的,复制了顶点。是否有更好的方法来平常?
更新:我使用的是OpenGL版本3.3.0,我还没有支持OpenGL 4.
答案 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旋转 - 矩阵。