GLSL法线产生奇怪效果

4
作为一个与我之前遇到的问题有些相似并且之前已经发布过的问题,我正在尝试在我的GLSL应用程序中正确显示法线。 为了说明,我正在使用RenderMonkey提供的ninjaHead.obj模型进行测试(您可以在此处获取)。现在,在RenderMonkey的预览窗口中,一切看起来都很好: 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;
}

然而,我的渲染产生了这个... openGL render 有人知道可能是什么原因导致这样,或者如何使其工作吗?
编辑: 针对kvark的评论,下面的模型呈现出没有任何法线/光照计算的平坦阴影。 Render flat shading 这里是模型使用用于颜色的法线进行着色。我认为问题已经被找到了!现在问题是为什么它会被呈现成这样以及如何解决它?欢迎提出建议!
解决方案: 大家好,问题已经解决!感谢kvark提供的所有有益见解,这些见解肯定有助于我的编程实践,但恐怕答案来自于我这个巨大的笨蛋... 我的代码中display()函数设置了一个随机值的glNormalPointer偏移量的错误。以前是这样的:
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指令是一个好习惯。 - Kos
1
你应该从问题中删除解决方案,并将其作为答案添加(如果它确实解决了你的问题,则接受它)。 - murgatroid99
2个回答

1
  1. 你的P矩阵是什么?(我想这应该是世界->相机视图变换)。

  2. vNormal = normal4*modelRotationMatrix; 为什么要改变参数的顺序?这样做会将法线乘以倒转的旋转矩阵,这不是你真正想要的。请使用标准顺序(modelRotationMatrix * normal4)。

  3. vViewVec = tempCameraPos - pos。这是完全错误的。 pos 是您在齐次剪裁空间中的顶点,而tempCameraPos 在世界空间中(我想)。您需要得到与法线相同空间的结果(世界空间),因此对于这个方程,请使用世界空间顶点位置 (modelTranslationMatrix * modelRotationMatrix * modelScaleMatrix * gl_Vertex)。


感谢您的回复。是的,P确实是世界相机矩阵。我已经按照您在(2)和(3)中建议的进行了更改,但没有看到任何可见的变化。我无法弄清楚发生了什么! - Sonoman
@Chris Robinson。您的截图显示有些三角形根本没有被绘制出来。您能否使用常量颜色填充模型以检查此问题? - kvark
@kvark 当我不使用法线渲染(即平面着色),模型确实被填充并且所有三角形都被渲染。 - Sonoman
@Chris Robinson。好的,现在我建议将中间函数结果放入颜色中,以查看工作代码和非工作代码之间的不同参数。尝试:gl_FragColor = normalize(vViewVec); 然后 =vNormal - kvark
@kvark 感谢迄今为止的所有帮助。我使用法线来渲染模型并在编辑中得到了奇怪的结果。现在很明显,这是错误的,我认为在这种情况下法线应该逐渐变化,以便相邻三角形之间的差异不会过大。即使有一些三角形被反向绘制,我也不会期望看到我正在看到的颜色变化。你对可能的原因有什么线索吗? - Sonoman
@Chris Robinson。对我来说,很明显OpenGL从你那里得到了垃圾法线。请检查并发布您创建/加载法线的代码,上传它们并将其与着色器链接。 - kvark

0

你好像有点混淆了GL版本?你正在通过uniform手动传递矩阵,但是使用固定函数来传递顶点属性。嗯,无论如何...


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

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;

这肯定是你代码需要修复的一个问题 - 我希望它能解决你的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接