4

作为一个有点类似于我之前和之前发布的问题,我试图让法线在我的 GLSL 应用程序中正确显示。出于解释的目的,我使用 RenderMonkey 提供的 ninjaHead.obj 模型进行测试(您可以在此处获取)。现在在 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 渲染

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

编辑 响应 kvark 的评论,这里是渲染的模型,没有任何法线/光照计算来显示所有正在渲染的三角形。 渲染平面着色

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

解决方案 大家问题已经解决了!感谢 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 代码来节省周五下午的时间并且...当您确定您正在查看的代码部分是正确的时,问题可能出在其他地方!

4

2 回答 2

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

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

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

于 2011-04-20T19:25:27.643 回答
0

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


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

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

vNormal = normal4*modelRotationMatrix;

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

转换法线的标准方法是将 a 乘以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;

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

于 2011-04-23T12:57:40.887 回答