在着色器中旋转法线

dan*_*jar 5 shader lighting glsl normals vertex-shader

我有一个场景,有几个模型,有个别位置和旋转.给定法线,着色器将简单的双向照明应用于每个像素.

那是我的顶点着色器.

#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);
}
Run Code Online (Sandbox Code Playgroud)

这是片段着色器.

#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);
}
Run Code Online (Sandbox Code Playgroud)

对于没有旋转的对象,这很好.但是对于旋转模型,照明也是旋转的,当然不应该是这种情况.

原因是法线不旋转.我已经尝试了,f_normal = model * normal;但这适用于法线的旋转和变换.

那么在将它们发送到片段着色器进行照明之前,如何在顶点着色器中旋转法线呢?什么是常用方法?

bwr*_*oga 5

您确实需要通过模型-视图-投影矩阵的上 3 行/列来转换法线。(如果您正在执行任何缩放,则需要使用此矩阵的逆转置。请参阅此文章)。

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));
Run Code Online (Sandbox Code Playgroud)

在片段着色器中,您需要计算从光源到片段的距离并进行标准化。找到法线和光向量的点积,然后乘以光的颜色。

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);
Run Code Online (Sandbox Code Playgroud)

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

我推荐这本书OpenGL 4.0 Shading Language Cookbook