我有一个场景,有几个模型,有个别位置和旋转。给定法线,着色器将简单的双向光照应用于每个像素。
这是我的顶点着色器。
#version 150
in vec3 position;
in vec3 normal;
in vec2 texcoord;
out vec3 f_normal;
out vec2 f_texcoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 proj;
void main()
{
mat4 mvp = proj * view * model;
f_normal = normal;
f_texcoord = texcoord;
gl_Position = mvp * vec4(position, 1.0);
}
这是片段着色器。
#version 150
in vec3 f_normal;
in vec2 f_texcoord;
uniform sampler2D tex;
vec3 sun = vec3(0.5, 1.0, 1.5);
void main()
{
vec3 light = max(0.0, dot(normalize(f_normal), normalize(sun)));
gl_FragColor = texture(tex, f_texcoord) * vec4(light, 1.0);
}
对于没有旋转的对象,这可以正常工作。但对于旋转模型,灯光也会旋转,当然,情况并非如此。
原因是法线不会旋转。我已经尝试了f_normal = model * normal;
,但这适用于法线的旋转和转换。
那么在将它们发送到片段着色器进行照明之前,如何在顶点着色器中旋转法线呢?什么是常用方法?
答案 0 :(得分:4)
您需要通过模型 - 视图 - 投影矩阵的上3行/列来变换法线。 (如果您正在执行任何缩放,则需要使用此矩阵的逆转置。See this article)。
mat3 normalMatrix = mat3(mvp);
normalMatrix = inverse(normalMatrix);
normalMatrix = transpose(normalMatrix);
f_normal = normalize(normal * normalMatrix);
// You should also send your tranformed position to the fragment shader
f_position = vec3(mvp * vec4(position, 1.0));
在片段着色器中,您需要计算光源到片段的距离并进行标准化。找到法线和光矢量的点积,并将其乘以浅色。
vec3 light = normalize(sun - f_position);
light = max(dot(f_normal, light), 0.0) * vec3(1.0, 1.0, 1.0);
gl_FragColor = texture(tex, f_texcoord) * vec4(light, 1.0);
我的代码肯定有优化空间。
答案 1 :(得分:0)
以下解决方案适用于我的模型,但我对其背后的数学没有非常深刻的理解。这是我的来源:Adding Depth and Realism - Surface Normals
您需要应用于法线向量的变换表示为: N'= N *(M -1 ) T
基本上,这意味着您将法线(N)乘以ModelView矩阵(M)的反转置。如果你的M矩阵是4x4,你应该使用得到的3x3左上象限(M -1 ) T 进行正常乘法。
同样,这对我有用,但我不能很好地解释数学。