数学基础

参考games101和unity shader 入门精要

一些重点的推导

透视变换矩阵

  1. 将锥体压缩成长方体

  2. 将长方体压缩成中心移到原点

  3. 将长方体压缩成\([-2 , 2]^3\)的正方体 , [-1 , 1]也行

先将这个锥体压缩成和Znear(近平面)同宽同高的长方体 ,远平面Zfar

方法:假设一个4x4的仿射变换矩阵,找一些特殊的点

比如:近平面的点\(\left(\begin{matrix} x \\ y \\ Znear \\ 1\end{matrix}\right)\tag{2}\) 经过变换之后还是\(\left(\begin{matrix} x \\ y \\ Znear \\ 1\end{matrix}\right)\tag{2}\),也可以写成\(\left(\begin{matrix} x*Znear \\ y * Znear \\ Znear*Znear \\ Znear\end{matrix}\right)\tag{2}\)

\[\left(\begin{matrix}x_{11} & x_{12} &x_{13} & x_{14} \\x_{21} & x_{22} &x_{23} & x_{24}\\x_{31} & x_{32} &x_{33} & x_{34}\\x_{41} & x_{42} &x_{43} & x_{44} \end{matrix}\right) * {\left(\begin{matrix} x \\ y \\ Znear \\ 1\end{matrix}\right)} = {\left(\begin{matrix} x*Znear \\ y * Znear \\ Znear*Znear \\ Znear\end{matrix}\right)\tag{2}} \]

\[这个仿射变换的矩阵就可以写成 \left(\begin{matrix} Znear & 0 & 0 & 0 \\ 0 & Znear & 0 & 0\\ 0 & 0 &x_{33} & x_{34}\\ 0 & 0 & 1 & 0 \end{matrix}\right) \]

再找一个远平面Zfar最中心的点\(\left(\begin{matrix} 0 \\ 0 \\ Zfar \\ 1\end{matrix}\right)\tag{2}\), 经过变换之后依旧是\(\left(\begin{matrix} 0 \\ 0 \\ Zfear \\ 1\end{matrix}\right)\tag{2}\) , 也可以写成\(\left(\begin{matrix} 0 \\ 0 \\ Zfar * Zfar\\ Zfar\end{matrix}\right)\tag{2}\)

\[这个仿射变换的矩阵就可以写成 \left(\begin{matrix} Znear & 0 & 0 & 0 \\ 0 & Znear & 0 & 0\\ 0 & 0 &x_{33} & x_{34}\\ 0 & 0 & 1 & 0 \end{matrix}\right) * \left(\begin{matrix} 0 \\ 0 \\ Zfar \\ 1\end{matrix}\right) = \left(\begin{matrix} 0 \\ 0 \\ Zfar * Zfar\\ Zfar\end{matrix}\right) \\解:perspective\_orth = \left(\begin{matrix} Znear & 0 & 0 & 0 \\ 0 & Znear & 0 & 0\\ 0 & 0 & Zfar * Znear & -Znear*Zfar\\ 0 & 0 & 1 & 0 \end{matrix}\right) \]

将长方体压缩成中心移到原点

此时定义一个摄像头的视角fov , 还有一个宽高比 那么长方体上下左右坐标分别为

    eye_fov = eye_fov * 0.5 * MY_PI / 180.0;
    float top = tan(eye_fov) * zNear, bottom = -top;
    float right = top * aspect_ratio, left = -right;

那么移动到原点的仿射变换方程为

\[orth\_to\_origin = \left(\begin{matrix} 1 & 0 & 0 & \frac{-(right+ left)}{2} \\ 0 & 1& 0 & \frac{-(top + bottom)}{2}\\ 0 & 0 & 1 & \frac{-(Znear + Zfar)}{2})\\ 0 & 0 & 0 & 1 \end{matrix}\right) \]

将长方体压缩成\([-2 , 2]^3\)的正方体 , [-1 , 1]也行

\[orth = \left(\begin{matrix} \frac{2}{(right - left)} & 0 & 0 & 0 \\ 0 & \frac{2}{top - bottom}& 0 & 0\\ 0 & 0 & \frac{2}{Znear - Zfar} & 0 \\ 0 & 0 & 0 & 1 \end{matrix}\right) \]

最后 \(projection = orth * orth\_to\_orgin * perspective\_orth;\)

空间变换

上面的透视变换矩阵只是一种,还有一种高级用法:法线变换

法线变换:由法线空间变换到观察空间内

  1. 首先看空间变换是怎么回事,是怎么变的

    父空间P以及子空间C , 一般有两种需求,1,从子空间变换到父空间;2,从父空间变换到子空间,只要把这个矩阵表示为正交矩阵,两者求一个就行,另一个转置即可

    我们求从子空间变换到父空间

    子坐标表示下的矢量或者坐标\(A_C\) 转换到父坐标空间\(A_p\)

    \(A_p = M_{c->p} * A_c \\ M_{c->p}即为子空间变换到父空间的变换坐标\)

    那么怎么求?

    使用一个很简单的例子:

    子空间的坐标轴在父空间的表示为\(X_C ,Y_C , Z_C , 以及O_C\)

    还有一点子坐标空间内的\(A_C = (a , b , c)\)

    那么从坐标原点\(O_c\) 走到\(A_c\) 即为 \(O_c + a * X_c + b * Y_c + c * Z_c\)

    在父空间下面同样的步骤也会走到\(A_c\) , 但是此时此刻实在父空间下,也可以写成\(A_p = O_c + a * X_c + b * Y_c + c * Z_c\)

    写成矩阵即为

    \[A_p = \left(\begin{matrix}| & | & | & x_{O_c} \\X_c &Y_c&Z_c&Y_{O_c}\\|&|&|&Z_{O_c}\\0&0&0&1\end{matrix}\right) *\left(\begin{matrix}a\\b\\c\\1\end{matrix}\right)\\ M_{c->p} = {\left(\begin{matrix}| & | & | & x_{O_c} \\X_c &Y_c&Z_c&Y_{O_c}\\|&|&|&Z_{O_c}\\0&0&0&1\end{matrix}\right) } \]

    1. 那么一个矢量从子空间变换到父空间的矩阵

      因为上面是点,需要位移,这个是矢量,不需要位移把最后一行,最后一列去掉

      \[M_{c->p} = {\left(\begin{matrix}| & | & | \\X_c &Y_c&Z_c\\|&|&|\end{matrix}\right) } \]

    2. 那么从父空间到子空间的矩阵为

\[M_{p->c} = {M_{c->p}} ^{-1} = {M_{c->p}} ^{T} = {\left(\begin{matrix}- & X_c & - \\ - &Y_c& - \\ - & Z_c &-\end{matrix}\right) } \]

前提,这个矩阵必须正交,三个向量相互垂直(三个坐标轴肯定垂直) , 然后将三个向量单位化,ok

法线变换

在法线进行非同一伸缩变换的时候,不能够直接使用上述公式

法线不能,但是切线可以。

假设如同上面,切线为\(父空间下 T_p , 子空间下T_c\)

法线为\(父空间下 N_P, 子空间下N_c\)

切线变换公式

\[T_p = {M_{c->p}} T_c \]

无论在父空间还是子空间下面法线始终和切线垂直

\[T_p * N_p = (M_{c->p}T_c) * (GN_c) = 0 \]

这个G为从子空间将法线变换到父空间的正交矩阵

上式等于

\[{T_c}^T{M^T_{c->p}}GN_c = 0\\{T_c}^TN_c = 0\\{M_{c->p}}^TG = I\\ G = {M^T_{c->p}}^{-1} = {M^{-1}_{c->p}}^{T} = {M^T_{p->c}}\\ 是不是突然第一步突然把上面中间的点乘去掉了,左边换成转置了 \\上面那个是 数学逻辑上面的点乘,这个是实际做法点乘\\当时我也困惑了好久,举个例子\\ \left(\begin{matrix} a\\b\\c \end{matrix}\right) *\left(\begin{matrix} x\\y\\z \end{matrix}\right) = \left(\begin{matrix} ax\\by\\cz \end{matrix}\right) \\但是我们实际上计算这两个点乘肯定是这样的\\ \left(\begin{matrix} a & b & c \end{matrix}\right) * \left(\begin{matrix} x\\y\\z \end{matrix}\right) = \left(\begin{matrix} ax & by & cz \end{matrix}\right) \]

​ 那么在unity中法线最后从子空间C变换到P空间是什么呢。

\[GN_C = {M^T_{p->c}}N_c \\ 注意这个此时 M_{3×3}N_c(_{3×1}) = N_p(_{3×1})\\ 在线性代数上面这个肯定不能相乘,上面这个只是逻辑上的 \\N_p(_{1×3}) = N_c(_{1×3})M_{p->c} \]

如有错误,敬请指正

每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。
原文地址:https://www.cnblogs.com/spnooyseed/p/15603973.html