如何计算法向量矩阵?

23

我遇到了一些关于我的标准矩阵的问题。

vs.glsl

#version 440

in vec3 vPosition;
in vec3 vNormal;

out vec4 eyeCordFs;
out vec4 eyeNormalFs;

uniform mat4 model;
uniform mat4 view;
uniform mat4 proj;

void main()
{   
    mat4 modelView = view * model;
    mat4 normalMatrix = view * transpose(inverse(model));
    vec4 eyeNorm = normalize(normalMatrix * vec4(vNormal, 0.0));
    vec4 eyeCord= modelView * vec4(vPosition, 1.0);

    eyeCordFs = eyeCord;
    eyeNormalFs = eyeNorm;

    gl_Position = proj * modelView * vec4( vPosition,1.0);
}

fs.glsl

#version 440

in vec4 eyeCordFs;
in vec4 eyeNormalFs;

out vec3 outputColor;

uniform vec4 lightPos;

void main()
{
    vec4 s = normalize(lightPos - eyeCordFs) ;
    vec4 r = reflect(-s,eyeNormalFs);
    vec4 v = normalize(-eyeCordFs);
    float spec = max( dot(v,r),0.0 );
    float diff = max(dot(eyeNormalFs,s),0.0);

    vec3 diffColor = diff * vec3(1,0,0);
    vec3 specColor = pow(spec,3) * vec3(1,1,1);
    vec3 ambientColor = vec3(0.1,0.1,0.1);

    outputColor =  diffColor + 0.5 * specColor + ambientColor; 
}

这个的输出结果看起来像这样: enter image description here 这对我来说有点奇怪。但是我知道我没有缩放任何东西,所以我想我可以使用modelView矩阵来转换我的法线。
于是我改变了这一行:
vec4 eyeNorm = normalize(normalMatrix * vec4(vNormal, 0.0));

为了

vec4 eyeNorm = normalize(modelView * vec4(vNormal, 0.0));

现在输出看起来像这样: enter image description here 看起来是正确的。我计算normalMatrix的方式有误吗?
2个回答

57

正常矩阵是模型视图矩阵的转置逆。因此,在GLSL中,它将是:

transpose(inverse(modelViewMatrix))

mat4 normalMatrix = transpose(inverse(modelView));

然而,你不应该在着色器中计算法线矩阵。在着色器中这样做会浪费大量宝贵的GPU周期。矩阵求逆本身就不是一项廉价的操作,在着色器中这样做还会强制GPU对每个顶点反复执行计算。在CPU上预先计算并将其作为一项统一变量传递。


可以通过模型矩阵的3x3部分进行转换。或者这只适用于世界空间光照吗? - Michael IV
3
只有在没有各向异性变换涉及的情况下(比如每个轴都有不同缩放因子的缩放),这种方法才有效。 - datenwolf
7
如果Golum成为了一名图形程序员,他可能会说:"我的宝贝!... GPU周期。" - code_dredd
因为我想要使用Vulkan,我听说它没有传统的Uniform。最后,我也听说发送大量Uniform不是一个好主意。 - Sébastien Bémelmans
1
@SébastienBémelmans:嗯,你在着色器中某个时刻必须进行一些矩阵·向量乘法。你应该避免在着色器中进行与顶点属性无关的计算,例如在着色器中计算矩阵的逆。最坏的情况是你要做64次乘法。查看数据从顶点属性流到顶点着色器输出的方式,确定哪些计算涉及外部数据,然后在CPU上合并该数据并将其提交到GPU。 - datenwolf
显示剩余9条评论

-3

这也是GLSL中的默认uniform。您可以将其声明为这样

uniform mat3 normalMatrix;

请点击这里。


7
如果你在使用 Three.js,那可能是对的,但这不是普遍情况。 - Tim Angus
这个预定义的uniform,以及所有其他固定功能矩阵,在GLSL 1.40中已不再可用。如果您想模拟固定功能照明,则需要计算法线矩阵。 - William

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