2

在让我的 GLSL 顶点着色器正确显示顶点几天后,我现在开始使用光照!无论如何,我对openGL光照/法线的理解都不是很好,所以请耐心等待。我不确定我需要对我的法线应用哪些翻译才能让它们正确显示。这是设置我的灯的应用程序代码:

    final float diffuseIntensity = 0.9f;
    final float ambientIntensity = 0.5f;

    final float position[] = { 0f, 0f, 25000f, 0f};
    gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, position, 0);
    final float diffuse[] = { 0, diffuseIntensity, 0, 1f};
    gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, diffuse, 0);
    final float ambient[] = { ambientIntensity, ambientIntensity, ambientIntensity, 1f};
    gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, ambient, 0);

到目前为止相当标准的东西。现在由于应用程序的要求,这里是(有点奇怪的)顶点着色器:

void main()
{   
// P is the camera matrix, model_X_matrices are the relative translation/rotation etc of the model currently being rendered.
vec4 pos = gl_ProjectionMatrix * P * modelTranslationMatrix * modelRotationMatrix * modelScaleMatrix * gl_Vertex;

gl_Position = pos;

gl_TexCoord[0] = gl_MultiTexCoord0;

gl_FrontColor = gl_Color;           
}

我的理解是我需要将其转换gl_Normal为世界坐标。对于我的着色器,我相信这将是:

vec4 normal = modelTranslationMatrix * modelRotationMatrix * modelScaleMatrix * vec4(gl_Normal);

然后我需要获取灯光的位置(已在世界空间的应用程序代码中声明)。我想我会这样做:

vec3 light_position = gl_LightSource[0].position.xyz;

然后通过求法线与光照位置的点积求出光照的漫反射值。

此外,我认为在片段着色器中,我只需要将颜色乘以这个漫反射值,它就可以工作了。我只是真的不确定如何正确转换法线坐标。我的假设是正确的还是我完全没有把握?

编辑: 在读到法线矩阵 ( gl_NormalMatrix) 只是矩阵的 3x3 逆gl_ModelView矩阵后,我猜想在世界空间中计算法线的正确方法是gl_Normal乘以modelTranslationMatrix * modelRotationMatrix * modelScaleMatrix? 我还需要将它乘以P矩阵还是与正常计算无关?

4

2 回答 2

2

您应该进行预乘modelTranslationMatrix * modelRotationMatrix * modelScaleMatrix并且仅将其作为单个制服传递。

法线乘以模型视图矩阵的逆转置,详细信息在此处找到的优秀文章中进行了解释http://www.lighthouse3d.com/tutorials/glsl-tutorial/the-normal-matrix/

在 GLSL 中,执行此操作的代码是

mat4 modelView = view * model;
mat4 mvp = projection * modelView;
mat4 normalMvp = projection * transpose(inverse(modelView));

但是不要通过 GLSL 来实现它! 相反,您应该在主机代码中进行计算并通过统一传递矩阵。矩阵-矩阵乘法是 O(n³),因此相当昂贵。在 GPU 端进行这种计算会在每个 GPU 线程上并行创建大量计算负载。我们不希望这种情况发生。取而代之的是使用 linmath.h 或 GLM 或 Eigen 或等效的东西在 CPU 上进行一次计算。

于 2011-04-19T15:02:31.843 回答
0

尽管我意识到这是一个有年头的问题,但由于我自己只是在努力解决这个问题,所以我想我会分享我的答案。

opengl 中的向量表示为一个点的同义词(即每个轴一个坐标)。这意味着它的方向是由从原点到这些坐标的平移定义的。当你翻译一个概念数学向量时,你不会改变它的方向。当您翻译 opengl 向量而不翻译它的 origin时,您可以这样做。

这就是通过模型视图矩阵(或您的自定义矩阵堆栈是什么)转换法线向量的问题 - 一般来说,这将包含旋转和平移(以及问题中的缩放,但这既不是这里也不是那里)。通过应用平移,您可以更改法线的方向。长话短说:离顶点越远,法线越接近平行于相机顶点向量。

因此,而不是

vec4 normal = modelTransformMatrix * vec4(gl_Normal);

你真的想要

vec3 normal = mat3(modelTransformMatrix) * gl_Normal;

因此不包括平移项,但保留任何旋转、比例和剪切。

至于使用相机矩阵,这取决于你想做什么。重要的是方程中的所有值都在同一个坐标空间中。话虽如此,乘以相机投影可能会导致问题,因为它(可能)设置为从相对于相机的 3d 世界坐标投影到屏幕坐标 + 深度。通常你会计算世界空间中的光照——乘以模型平移而不是相机投影。

于 2012-04-11T23:22:43.023 回答