【问题标题】:Odd effect with GLSL normals带有 GLSL 法线的奇怪效果
【发布时间】:2026-01-04 01:20:03
【问题描述】:

由于与我之前遇到并发布过的问题有点相似,我试图让法线在我的 GLSL 应用程序中正确显示。 出于解释的目的,我使用 RenderMonkey 提供的 ninjaHead.obj 模型进行测试 (you can grab it here)。现在在 RenderMonkey 的预览窗口中,一切看起来都很棒: 分别生成的顶点和片段代码为:

顶点:

uniform vec4 view_position;

varying vec3 vNormal;
varying vec3 vViewVec;

void main(void)
{
  gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

  // World-space lighting
  vNormal = gl_Normal;
  vViewVec = view_position.xyz - gl_Vertex.xyz;
}

片段:

uniform vec4 color;

varying vec3 vNormal;
varying vec3 vViewVec;

void main(void)
{
   float v = 0.5 * (1.0 + dot(normalize(vViewVec), vNormal));
   gl_FragColor =  v* color;
}

我的 GLSL 代码以此为基础,但我并没有完全得到预期的结果...

我的顶点着色器代码:

uniform mat4 P;
uniform mat4 modelRotationMatrix;
uniform mat4 modelScaleMatrix;
uniform mat4 modelTranslationMatrix;
uniform vec3 cameraPosition;

varying vec4 vNormal;
varying vec4 vViewVec;

void main()
{
vec4 pos = gl_ProjectionMatrix * P * modelTranslationMatrix * modelRotationMatrix * modelScaleMatrix * gl_Vertex;

gl_Position = pos;

gl_TexCoord[0] = gl_MultiTexCoord0;

gl_FrontColor = gl_Color;   

vec4 normal4 = vec4(gl_Normal.x,gl_Normal.y,gl_Normal.z,0);     

// World-space lighting
   vNormal = normal4*modelRotationMatrix;
   vec4 tempCameraPos = vec4(cameraPosition.x,cameraPosition.y,cameraPosition.z,0);     
   //vViewVec = cameraPosition.xyz - pos.xyz;
   vViewVec = tempCameraPos - pos;
}

我的片段着色器代码:

varying vec4 vNormal;
varying vec4 vViewVec;

void main()
{
  //gl_FragColor = gl_Color;
  float v = 0.5 * (1.0 + dot(normalize(vViewVec), vNormal));
gl_FragColor =  v * gl_Color;
}

但是我的渲染产生了这个......

有谁知道这可能是什么原因和/或如何使它起作用?

编辑 为了响应 kvark 的 cmets,这里是渲染的模型,没有任何法线/光照计算来显示所有正在渲染的三角形。

这里是带有用于颜色的法线的模型着色。相信问题已经找到了!现在的原因是为什么它被渲染成这样以及如何解决它?欢迎提出建议!

解决方案 好了大家问题都解决了!感谢 kvark 提供的所有有用的见解,这肯定有助于我的编程实践,但我担心答案来自我是一个巨大的山雀......我在设置 glNormalPointer 偏移量的代码的 display() 函数中有一个错误为随机值。以前是这样的:

gl.glEnableClientState(GL.GL_NORMAL_ARRAY);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, getNormalsBufferObject());
gl.glNormalPointer(GL.GL_FLOAT, 0, getNormalsBufferObject());

但应该是这样的:

gl.glEnableClientState(GL.GL_NORMAL_ARRAY);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, getNormalsBufferObject());
gl.glNormalPointer(GL.GL_FLOAT, 0, 0);

所以我想这是一个教训。永远不要在周五下午盲目地使用 Ctrl+C 和 Ctrl+V 代码来节省时间并且...当您确定您正在查看的代码部分是正确的时,问题可能出在其他地方!

【问题讨论】:

  • 请务必指定您的 OpenGL 版本。在您的 GLSL 中使用 #version 指令也是一个好习惯。
  • 您应该从您的问题中删除解决方案并将其添加为答案(如果它确实解决了您的问题,请接受它)。

标签: opengl glsl normals


【解决方案1】:
  1. 你的P 矩阵是什么? (我想这是一个世界->相机视图变换)。

  2. vNormal = normal4*modelRotationMatrix; 为什么要更改参数的顺序?这样做是通过反向旋转将法线相乘,这是您真正不想要的。改用标准顺序(modelRotationMatrix * normal4)

  3. vViewVec = tempCameraPos - pos。这是完全不正确的。 pos 是同质剪辑空间中的顶点,而 tempCameraPos 是世界空间中的顶点(我想)。您需要将结果放在与法线相同的空间中(世界空间),因此请使用世界空间顶点位置 (modelTranslationMatrix * modelRotationMatrix * modelScaleMatrix * gl_Vertex) 进行此等式。

【讨论】:

  • 感谢您的回复。是的 P 确实是世界相机矩阵。我已经做出了您在 (2) 和 (3) 中建议的更改,但没有明显的更改。我不知道发生了什么!
  • @克里斯·罗宾逊。您的屏幕截图显示根本没有绘制一些三角形。你能用恒定颜色填充模型来检查吗?
  • @kvark 当我在没有法线的情况下渲染时(即平面着色),模型确实被填充并且所有的三角形都被渲染了。
  • @克里斯·罗宾逊。好的,很好。现在我建议将中间函数结果放入颜色中,以查看工作代码和非工作代码之间的哪些参数不同。试试:gl_FragColor = normalize(vViewVec); 然后=vNormal
  • @kvark 感谢您迄今为止的所有帮助。我已经使用颜色的法线渲染了模型,并在我的编辑中得到了奇怪的结果。现在显然这是错误的,我认为在这种情况下相邻三角形之间的法线应该缓慢变化。即使有些三角形是向后绘制的,我也不希望看到我看到的颜色变化。关于它可能是什么的任何线索?
【解决方案2】:

您似乎在混合 GL 版本?您通过制服手动传递矩阵,但使用固定函数传递顶点属性。嗯。总之……


我真的不喜欢你对你的法线做的事情。看看:

vec4 normal4 = vec4(gl_Normal.x,gl_Normal.y,gl_Normal.z,0);     

vNormal = normal4*modelRotationMatrix;

普通只存储方向数据,为什么要使用vec4呢?我相信只使用vec3 会更优雅。此外,看看接下来会发生什么 - 将法线乘以 4x4 模型旋转矩阵......另外,法线的第四个坐标等于 0,因此它不是齐次坐标中的正确向量。我不确定这是这里的主要问题,但如果这种乘法会给你带来垃圾,我不会感到惊讶。

转换法线的标准方法是将vec3 乘以模型视图矩阵的 3x3 子矩阵(因为您只对方向感兴趣,而不是平移)。好吧,确切地说,“最正确”的方法是使用该 3x3 子矩阵的逆转置(这在您进行缩放时很重要)。在旧的 OpenGL 版本中,您将其预先计算为 gl_NormalMatrix

因此,您应该使用类似

的东西,而不是上面的
// (...)
varying vec3 vNormal;
// (...)

mat3 normalMatrix = transpose(inverse(mat3(modelRotationMatrix)));
// or if you don't need scaling, this one should work too-
mat3 normalMatrix = mat3(modelRotationMatrix);

vNormal = gl_Normal*normalMatrix;

这当然是需要在您的代码中修复的一件事 - 我希望它能解决您的问题。

【讨论】: