非均匀缩放的法线矩阵
normal matrix for non uniform scaling
我正在尝试为 OpenGL 2.0 上的 GLSL 着色器计算法线矩阵。
理论是:普通矩阵是 ModelView 的左上角 3x3 矩阵,经过转置和反转。
这似乎是正确的,因为我一直在正确渲染我的场景,直到我从 Maya 导入模型并发现比例不均匀。加载的模型有奇怪的光照,而我的程序模型是正确的,所以我把钱花在了正常的矩阵计算上。
非均匀比例如何计算?
您已经知道需要转置倒矩阵来变换法线。对于缩放矩阵,这很容易计算。
一个非均匀的 3x3 缩放矩阵如下所示:
[ sx 0 0 ]
[ 0 sy 0 ]
[ 0 0 sz ]
其中sx
、sy
和sz
是3个坐标方向的比例因子。
这个的倒数是:
[ 1 / sx 0 0 ]
[ 0 1 / sy 0 ]
[ 0 0 1 / sz ]
转置它不会改变任何东西,所以这已经是你的正常变换矩阵了。
请注意,与旋转等不同,此变换矩阵在应用于归一化向量时不会保持向量归一化。所以在你的着色器中应用这个矩阵之后,你必须在使用它进行光照计算之前重新归一化结果。
我只想在 Reto Koradi 的回答中添加一个实际示例。
假设您已经有一个 4x4 模型矩阵并且还想用它来变换法线。您可以通过获取该矩阵前 3 列的长度来推导每个轴的比例。如果现在将每一列除以其相应的比例因子,矩阵将不再影响模型的比例,因为基向量将具有单位长度。
正如您所指出的,法线必须按每个轴中比例的倒数进行缩放。好在第一步我们已经推导出了刻度,所以我们可以再分列。
所有这一切实际上意味着如果你想从你的模型矩阵中推导出法线的变换矩阵,你需要做的就是将它的前三列中的每一列除以它们的长度平方(可以重写为点积).在 GLSL 中你会写:
mat3 mat_n = mat3(mat_model);
mat_n[0] /= dot(mat_n[0], mat_n[0]);
mat_n[1] /= dot(mat_n[1], mat_n[1]);
mat_n[2] /= dot(mat_n[2], mat_n[2]);
vec3 new_normal = normalize(mat_n * normal);
我正在尝试为 OpenGL 2.0 上的 GLSL 着色器计算法线矩阵。
理论是:普通矩阵是 ModelView 的左上角 3x3 矩阵,经过转置和反转。
这似乎是正确的,因为我一直在正确渲染我的场景,直到我从 Maya 导入模型并发现比例不均匀。加载的模型有奇怪的光照,而我的程序模型是正确的,所以我把钱花在了正常的矩阵计算上。
非均匀比例如何计算?
您已经知道需要转置倒矩阵来变换法线。对于缩放矩阵,这很容易计算。
一个非均匀的 3x3 缩放矩阵如下所示:
[ sx 0 0 ]
[ 0 sy 0 ]
[ 0 0 sz ]
其中sx
、sy
和sz
是3个坐标方向的比例因子。
这个的倒数是:
[ 1 / sx 0 0 ]
[ 0 1 / sy 0 ]
[ 0 0 1 / sz ]
转置它不会改变任何东西,所以这已经是你的正常变换矩阵了。
请注意,与旋转等不同,此变换矩阵在应用于归一化向量时不会保持向量归一化。所以在你的着色器中应用这个矩阵之后,你必须在使用它进行光照计算之前重新归一化结果。
我只想在 Reto Koradi 的回答中添加一个实际示例。
假设您已经有一个 4x4 模型矩阵并且还想用它来变换法线。您可以通过获取该矩阵前 3 列的长度来推导每个轴的比例。如果现在将每一列除以其相应的比例因子,矩阵将不再影响模型的比例,因为基向量将具有单位长度。
正如您所指出的,法线必须按每个轴中比例的倒数进行缩放。好在第一步我们已经推导出了刻度,所以我们可以再分列。
所有这一切实际上意味着如果你想从你的模型矩阵中推导出法线的变换矩阵,你需要做的就是将它的前三列中的每一列除以它们的长度平方(可以重写为点积).在 GLSL 中你会写:
mat3 mat_n = mat3(mat_model);
mat_n[0] /= dot(mat_n[0], mat_n[0]);
mat_n[1] /= dot(mat_n[1], mat_n[1]);
mat_n[2] /= dot(mat_n[2], mat_n[2]);
vec3 new_normal = normalize(mat_n * normal);