着色器中旋转法线

6

我有一个场景,其中包含多个模型,每个模型都有独立的位置和旋转。在给定法线的情况下,着色器会对每个像素应用简单的双向光照。

这是我的顶点着色器。

#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; 但这会将旋转和变换同时应用于法线。

那么,在将法线发送到片段着色器进行光照之前,我如何在顶点着色器中旋转法线?有什么常见的方法吗?

2个回答

6

你需要使用模型视图投影矩阵的前三行/列来转换法线。(如果你进行了任何缩放操作,你需要使用该矩阵的逆转置矩阵。请参考这篇文章。)

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);

我代码中肯定有优化的空间。

我推荐这本书《OpenGL 4.0 Shading Language Cookbook》


谢谢。您会建议我向着色器发送一个单独的普通矩阵(仅包括模型旋转但不包括缩放或变换)吗?我在某个地方看到过这种做法,想知道这是否比在着色器中重新提取模型矩阵中的旋转更好。 - danijar
抱歉,我的时间在编辑上一个评论时用完了...我认为缩放是必要的,因为它可以改变表面到光源的距离。而且由于你需要比例尺,所以需要使用上三角矩阵的逆转置来进行比例校正。不过我会将我的法线矩阵作为统一变量发送到着色器中,这样它只需要计算一次而不是每个顶点都计算一次。不过你可能需要一个数学库来完成这个操作,因为你的平台可能没有提供执行这些矩阵计算的函数。 - bwroga
很有道理。顺便说一下,我使用GLM。 - danijar
更重要的是,缩放是必要的,因为它可以改变表面对光线的角度。 - bwroga
编辑:关于我的第二条评论,缩放法线实际上与距离无关。距离仅适用于片段位置,而不适用于法线。法线仅因第三条评论中提到的原因而被缩放。 - bwroga

0

以下解决方案适用于我的模型,但我对其背后的数学并没有非常深入的理解。这是我的来源:添加深度和逼真度-表面法线

你需要应用到法向量的变换表示为: N' = N * (M-1)T

基本上,这意味着你将法向量(N)乘以模型视图矩阵(M)的逆转置。如果你的 M 矩阵是 4x4 的,你应该只使用 (M-1)T 的结果中左上角的 3x3 上三角矩阵进行法向量乘法。

再次强调,这对我有效,但我无法很好地解释其中的数学原理。


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