验证顶点着色器中变换矩阵的使用。正确性或法线变换
Posted
技术标签:
【中文标题】验证顶点着色器中变换矩阵的使用。正确性或法线变换【英文标题】:Verification of transformation matrix usage in vertex shader. Correctness or normals transformation 【发布时间】:2018-02-09 22:48:24 【问题描述】:我需要能够根据变换矩阵修改顶点坐标,但我有逐顶点光照,所以我不确定我的方法是否适用于法线:
#version 120
uniform mat4 transformationMatrix;
void main()
vec3 normal, lightDir;
vec4 diffuse, ambient, globalAmbient;
float NdotL;
// Transformation part
normal = gl_NormalMatrix * gl_Normal * transpose(mat3(transformationMatrix));
gl_Position = gl_ModelViewProjectionMatrix * transformationMatrix * gl_Vertex;
// Calculate color
lightDir = normalize(vec3(gl_LightSource[0].position));
NdotL = max(abs(dot(normal, lightDir)), 0.0);
diffuse = gl_Color * gl_LightSource[0].diffuse;
ambient = gl_Color * gl_LightSource[0].ambient;
globalAmbient = gl_LightModel.ambient * gl_Color;
gl_FrontColor = NdotL * diffuse + globalAmbient + ambient;
我在第 8-9 行执行所有转换。 您能评论一下这是否正确吗?
【问题讨论】:
【参考方案1】:如果你想创建一个普通矩阵,那么你必须使用左上角3*3的inverse
transpose
,这个4*4的矩阵。
见Why transforming normals with the transpose of the inverse of the modelview matrix? 和Why is the transposed inverse of the model view matrix used to transform the normal vectors?
这意味着您必须像这样编写代码:
normal = gl_NormalMatrix * transpose(inverse(mat3(transformationMatrix))) * gl_Normal;
但是,如果一个向量从左边乘以一个矩阵,结果相当于从右边乘一个列向量到转置矩阵。
见GLSL Programming/Vector and Matrix Operations
这意味着你可以这样写代码,避免transpose
操作:
normal = gl_NormalMatrix * (gl_Normal * inverse(mat3(transformationMatrix)));
如果4*4矩阵transformationMatrix
是Orthogonal matrix,这意味着X、Y、Z轴是Orthonormal(单位向量,相互垂直),那么使用上面的就足够了左 3*3。在这种情况下,逆矩阵等于转置矩阵。
见In which cases is the inverse matrix equal to the transpose?
这将简化您的代码:
normal = gl_NormalMatrix * mat3(transformationMatrix) * gl_Normal;
当然也可以这样表达:
normal = gl_NormalMatrix * (gl_Normal * transpose(mat3(transformationMatrix)));
请注意,这与您在代码中所做的不同,因为*
操作是从左到右处理的(请参阅GLSL - The OpenGL Shading Language 4.6, 5.1 Operators, page 97),结果是
vec3 v;
mat3 m1, m2;
(m1 * v) * m2
不等于
m1 * (v * m2);
【讨论】:
谢谢。我的变换矩阵不应该是正交的,所以我应该使用你的第二个解决方案。我阅读了提供的链接,我有最后一个问题:如果我的法线被规范化,似乎一些转换可能会破坏这种规范化,所以我需要 normal = normalize ( gl_NormalMatrix * gl_Normal * inverse(mat3(transformationMatrix))); ? @zlon 如果矩阵不是正交矩阵,则矩阵变换会丢失法线向量的归一化,您必须在变换后对其进行归一化。【参考方案2】:正常的变换看起来不正确。
由于 v * transpose(M) 与 M * v 完全相同,因此您根本没有对非均匀缩放进行任何特殊情况处理。
您正在寻找的很可能是使用反转置矩阵:
normal = gl_NormalMatrix * transpose(inverse(mat3(transformationMatrix))) * gl_Normal;
有关这背后的数学的更多详细信息,请查看this。
【讨论】:
以上是关于验证顶点着色器中变换矩阵的使用。正确性或法线变换的主要内容,如果未能解决你的问题,请参考以下文章