LearnGL - 11.5 - 矩阵04 - 法线从对象空间变换到世界空间

49 篇文章 0 订阅
47 篇文章 0 订阅


LearnGL - 学习笔记目录

前些篇:

了解了 Gouraud-Phong、Phong、Blinn-Phong、Flat Blinn-Phong 光照模型的基本认识。

这篇:我们重点讲解一下 法线从对象空间变换到世界空间 的变换矩阵的推导过程,因为之前四篇光照处理有用到,但没有细节的去讲解到。

本人才疏学浅,如有什么错误,望不吝指出。


Unity 中的处理

在 Unity ShaderLab 中,你可能会看到内置的函数:

// Transforms normal from object to world space
inline float3 UnityObjectToWorldNormal( in float3 norm )
{
#ifdef UNITY_ASSUME_UNIFORM_SCALING
    return UnityObjectToWorldDir(norm);
#else
    // mul(IT_M, norm) => mul(norm, I_M) => {dot(norm, I_M.col0), dot(norm, I_M.col1), dot(norm, I_M.col2)}
    return normalize(mul(norm, (float3x3)unity_WorldToObject));
#endif
}

这函数中:

#ifdef UNITY_ASSUME_UNIFORM_SCALING
    return UnityObjectToWorldDir(norm);
#else

是处理统一缩放的法线变换,所以我们聚焦在后面那块:

    // mul(IT_M, norm) => mul(norm, I_M) => {dot(norm, I_M.col0), dot(norm, I_M.col1), dot(norm, I_M.col2)}
    return normalize(mul(norm, (float3x3)unity_WorldToObject));

unity_WorldToObject model matrix 的逆矩阵,然后我们用 float3 * float3x3 来免去了处理 transpose(unity_WorldToObject) 的转置处理,像上面那句也可以这么写,但没必要:

    return normalize(mul(transpose((float3x3)unity_WorldToObject), norm));

即: float3x3 * float3 的意思


OpenGL 处理

在我之前的一些 LearnGL 系列笔记中,如:LearnGL - 11.1 - 实现简单的Gouraud-Phong光照模型,写了一个 GLSL 函数 vec3 ObjectToWorldNormal(vec3 n)

// 将对象空间的法线转换到世界空间下的法线
vec3 ObjectToWorldNormal(vec3 n) {
	return normalize(mat3(IT_mMat) * n);	// 等价于:transpose(I_mMat) * vec4(n, 0)
}

(这里顺便吐槽一下,GLSL 中竟然不支持 inline 内联开展?因为我编译 GLSL shader 是会提示:“inline” not supported 之类的,不会又需要什么 GL 的 Extensions 吧?)

这代码中的 IT_mMat 是我在 C++ 层计算好的 mMat逆矩阵转置矩阵,再传入到 shader 的 uniform,对应上面 Unity 中的 unity_WorldToObject,只不过 unity_WorldToObject 没有转置而已,只是 巧妙的利用了 CG/HLSL 中 mul 函数的特性来避免 transpose 函数的转置处理。


为何要使用 IT_mMat

那么为何我们要用 Model Matrix 的 逆矩阵的转置矩阵 来变换法线呢?

先来看看,我们变换顶点都是使用 mMat对象空间 变换到 世界空间,那么如果我们使用这个 mMat 矩阵来变换法线可以吗?

那么我用 GGB 来测试
在这里插入图片描述

上图,左边 原始图形 中的 T T T 是切线, N N N 是法线,右边 缩放后的图形 T 1 T_1 T1 是切线, N 1 N_1 N1 是法线

在统一缩放(缩放分量相同)看起来没有问题

如果在非统一缩放呢?看看:

在这里插入图片描述

在这里插入图片描述

看起来 T 1 T_1 T1 还是 保持着 平面上的 切线,但是 N 1 N_1 N1没有保持 与平面 垂直 了。

所以,在非统一缩放时,用 mMat 矩阵来变换法线是不行的。

那么我们利用一些已知的数学公式来推导:

已知:

  • Model Matrix(对象到世界空间变换矩阵) mMat ,我们定义符号为: M m M_m Mm
  • T T T 是原始切线
  • N N N 是原始法线
  • T 1 T_1 T1 M m M_m Mm 变换后的切线
  • N 1 N_1 N1 M n \red{M_n} Mn 变换后仍然垂直于平面的法线

M n \red{M_n} Mn 是目前不知道的,正式是我们要求的 法线变换矩阵,即:IT_mMat

由于法线是垂直于切线的,所以我们可以将一些公理式子列出来:

{ N T ⋅ T = 0 ( 1 ) 法线与切线的点积为0,因为相互垂直 N 1 T ⋅ T 1 = 0 ( 2 ) 变换后的法线与切线仍然是垂直的 T 1 = M m ⋅ T ( 3 ) T 1 是通过 M m 矩阵变换后得到的 N 1 = M n ⋅ N ( 4 ) N 1 是通过 M n 矩 阵 变 换 后 得 到 的 \begin{cases} N^T \cdot T=0 & (1) \text{法线与切线的点积为0,因为相互垂直}\\ N_1^T \cdot T_1=0 & (2) \text{变换后的法线与切线仍然是垂直的}\\ T_1=M_m \cdot T & (3)T_1\text{是通过}M_m\text{矩阵变换后得到的}\\ N_1=\red{M_n} \cdot N &(4)N_1\text{是通过}M_n矩阵变换后得到的 \end{cases} NTT=0N1TT1=0T1=MmTN1=MnN(1)法线与切线的点积为0,因为相互垂直(2)变换后的法线与切线仍然是垂直的(3)T1是通过Mm矩阵变换后得到的(4)N1是通过Mn

注 意 : {\red{注意:}} :上面为何第(1), (2) 的 N T , N 1 T N^T, N^T_1 NT,N1T 要用转置的,因为我们将 T , T 1 T, T_1 T,T1 视为 Nx1 的矩阵
所以我们将同样的 N , N 1 N, N_1 N,N1 的 Nx1 矩阵转置为 1xN 来与后续的 Nx1 矩阵相乘

(上面关于点积 dot 可以参考我之前写的:LearnGL - 11.1 - 实现简单的Gouraud-Phong光照模型 - dot - 点积的作用


我们将 ( 1 ) (1) (1)号等式左边部分在中间添加一个 I I I,那么结果为: N T ⋅ T = N T ⋅ I ⋅ T = 0 N^T \cdot T=N^T \cdot \red{I} \cdot T=0 NTT=NTIT=0,其中 I \red{I} I 是单位矩阵

I = M m − 1 ⋅ M m I=M_m^{-1} \cdot M_m I=Mm1Mm 就是一个矩阵与它的逆矩阵变换后就抵消了矩阵的所有变换,没有变换的特性就是 单位矩阵 的特性,所以这个是没有问题的

所以: N T ⋅ T = N T ⋅ I ⋅ T → N T ⋅ T = N T ⋅ M m − 1 ⋅ M m ⋅ T = 0 N^T \cdot T=N^T \cdot \red{I} \cdot T \to N^T \cdot T=N^T \cdot \red{M_m^{-1}\cdot M_m} \cdot T=0 NTT=NTITNTT=NTMm1MmT=0


仔细观察公式中红色部分, N T ⋅ T = N T ⋅ M m − 1 ⋅ M m ⋅ T = 0 N^T \cdot T=N^T \cdot M_m^{-1}\cdot \red{M_m \cdot T}=0 NTT=NTMm1MmT=0 中 的 M m ⋅ T \red{M_m \cdot T} MmT ,其实这部分就是 ( 3 ) (3) (3)等式右边的内容: T 1 = M m ⋅ T T_1=\red{M_m \cdot T} T1=MmT

所以我们的式子再次可以调整为: N T ⋅ T = N T ⋅ M m − 1 ⋅ T 1 = 0 N^T \cdot T=N^T \cdot M_m^{-1}\cdot \red{T_1}=0 NTT=NTMm1T1=0


再次仔细观察一下 ( 2 ) : N 1 T ⋅ T 1 = 0 (2):N_1^T \cdot T_1=0 (2)N1TT1=0 N T ⋅ T = N T ⋅ M m − 1 ⋅ T 1 N^T \cdot T=N^T \cdot M_m^{-1}\cdot \red{T_1} NTT=NTMm1T1 有什么共同之处?

{ N 1 T ⋅ T 1 = 0 ( 2 ) N T ⋅ T = N T ⋅ M m − 1 ⋅ T 1 = 0 ( 5 ) \begin{cases} N_1^T \cdot \red{T_1}=0 & (2)\\ \blue{N^T \cdot T}=N^T \cdot M_m^{-1}\cdot \red{T_1}=0 & (5) \end{cases} {N1TT1=0NTT=NTMm1T1=0(2)(5)

( 5 ) (5) (5)等式左边(也就 蓝色 部分)的 N T ⋅ T \blue{N^T \cdot T} NTT 去掉,变成下面的等式

{ N 1 T ⋅ T 1 = 0 ( 2 ) N T ⋅ M m − 1 ⋅ T 1 = 0 ( 5 ) \begin{cases} N_1^T \cdot &\red{T_1}=0 & (2)\\ N^T \cdot M_m^{-1}\cdot &\red{T_1}=0 & (5) \end{cases} {N1TNTMm1T1=0T1=0(2)(5)

现在可以清晰看到 ( 2 ) (2) (2) ( 5 ) (5) (5)的红色部分的 T 1 \red{T_1} T1是相同的,那么剩下的部分我们标记上绿色:
{ N 1 T ⋅ T 1 = 0 ( 2 ) N T ⋅ M m − 1 ⋅ T 1 = 0 ( 5 ) \begin{cases} \green{N_1^T} \cdot &\red{T_1}=0 & (2)\\ \green{N^T \cdot M_m^{-1}}\cdot &\red{T_1}=0 & (5) \end{cases} {N1TNTMm1T1=0T1=0(2)(5)

这绿色的部分,我们也可以认为他们是相等的

即: { N 1 T = N T ⋅ M m − 1 ( 6 ) \begin{cases}\green{N_1^T}=\green{N^T \cdot M_m^{-1}} & (6)\end{cases} {N1T=NTMm1(6)


为了便于观察,将等式 左右 两个的内容 分别标记红色绿色

N 1 T = N T ⋅ M m − 1 \red{N_1^T}=\green{N^T \cdot M_m^{-1}} N1T=NTMm1

再将等式两边同时转置一下:

( N 1 T ) T = ( N T ⋅ M m − 1 ) T (\red{N_1^T})^T=(\green{N^T \cdot M_m^{-1}})^T (N1T)T=(NTMm1)T

左边 ( N 1 T ) T (\red{N_1^T})^T (N1T)T 本身有转置的,再次转置就抵消了,所以: ( N 1 T ) T = N 1 (\red{N_1^T})^T=\red{N_1} (N1T)T=N1


右边 ( N T ⋅ M m − 1 ) T (\green{N^T \cdot M_m^{-1}})^T (NTMm1)T,由于 矩阵转置 的性质: ( A ⋅ B ) T = B T ⋅ A T (A\cdot B)^T=B^T\cdot A^T (AB)T=BTAT

所以后变成了: ( N T ⋅ M m − 1 ) T = ( M m − 1 ) T ⋅ ( N T ) T (\green{N^T \cdot M_m^{-1}})^T=\green{(M_m^{-1})}^T \cdot \green{(N^T)}^T (NTMm1)T=(Mm1)T(NT)T

最后边的 ( N T ) T \green{(N^T)}^T (NT)T 转置的转置,所以抵消转置 ( N T ) T = N \green{(N^T)}^T=\green{N} (NT)T=N

所以 右边 ( N T ⋅ M m − 1 ) T = ( M m − 1 ) T ⋅ N (\green{N^T \cdot M_m^{-1}})^T=\green{(M_m^{-1})^T \cdot N} (NTMm1)T=(Mm1)TN


最终 ( 6 ) (6) (6)号等式 左右两边,变成了: N 1 = ( M m − 1 ) T ⋅ N \red{N_1}=\green{(M_m^{-1})^T \cdot N} N1=(Mm1)TN


那么结果已经出来了, ( M m − 1 ) T \green{(M_m^{-1})^T} (Mm1)T 就是我们的 M n M_n Mn 法线矩阵,就是 M m M_m Mm逆矩阵的转置矩阵

(关于逆矩阵怎么求,你也可以查看我之前的一篇学习笔记:LearnGL - 06.2 - Matrix - 矩阵03 - 逆矩阵、行列式、伴随矩阵、余子式、代数余子式、练习


总结

这些图形学基础中矩阵变换,建议去吭一下,因为后续会有很多各种各样的变换需求,如果这些基础的变换你能学习、理解这些意义,后续就会越学越顺。

虽然这个 法线矩阵 IT_mMat 本质上暂时没找到很好的理解方式,但是知道他是通过这些数学公式,可重新推导出来的就够了。(当然,如果大神的您,对法线矩阵 有很好的、了解本质的教程,希望您能分享一下,感激不尽!

而且,后面还有一些 世界空间切线空间 的变换,或是 切线空间世界空间 的变换矩阵(这个知识点,我之前学习过,但是这次为了完善 LearnGL 系列的内容,我会重复再详细的讲解一次,当做温习),这些是为了后续的 法线贴图 需要准备的知识点。


References

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值