本文介绍了在着色器中旋转法线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个场景,其中包含多个具有各自位置和旋转角度的模型.在给定法线的情况下,着色器将简单的双向照明应用于每个像素.

I have a scene with several models with individual positions and rotations. Given normals, the shaders apply simple bidirectional lighting to each pixel.

那是我的顶点着色器.

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

对于不旋转的对象,此方法工作正常.但是对于旋转模型,照明也会同时旋转,当然不应该这样.

For objects without rotation this works fine. But for rotated models the lighting is rotated as well which, of course, shouldn't be the case.

其原因是法线不旋转.我已经尝试过f_normal = model * normal;,但这将旋转和变换都应用于法线.

The reason for that is that the normals are not rotated. I already tried f_normal = model * normal; but this applies both rotation and transformation to the normals.

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

So how can I rotate the normals in the vertex shader before I send them to the fragment shader for lighting? What is a common approach?

推荐答案

您确实需要按照模型视图投影矩阵的前3行/列对法线进行变换. (但是,如果要执行任何缩放,则需要使用此矩阵的逆转置.请参阅本文).

You do need to transform the normals, by the upper 3 rows/cols of the model-view-projection matrix. (If you are performing any scaling though, you need to use the inverse transpose of this matrix. 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));

在片段着色器中,您需要计算从光源到片段的距离并进行归一化.找到法线和光矢量的点积,然后将其乘以光的颜色.

In your fragment shader, you need to calculate the distance from your light source to your fragment and normalize. Find the dot product of the normal and the light vector and multiply this by the light color.

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

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

There is definitely room for optimization in my code.

我推荐这本书 OpenGL 4.0 Shading Language Cookbook .

这篇关于在着色器中旋转法线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 16:48