坐标转换

一个向量可以被表示为\(v=xi+yj+zk\),其中\(i\)\(j\)\(k\)为坐标系的基向量:

\(i= \begin{bmatrix} 1\\ 0\\ 0 \end{bmatrix}\)\(j= \begin{bmatrix} 0\\ 1\\ 0 \end{bmatrix}\)\(k= \begin{bmatrix} 0\\ 0\\ 1 \end{bmatrix}\)

基向量可写成矩阵的方式:

\(\begin{bmatrix} i_x&i_y&i_z\\ j_x&j_y&j_z\\ k_x&k_y&k_z \end{bmatrix}\)

一个坐标系可以使用任意线性无关的基向量构成,如\(l\)\(m\)\(n\)

使用由\(l\)\(m\)\(n\)构成的矩阵乘以一个任意向量\(\begin{bmatrix}a&b&c\end{bmatrix}\)

\(\begin{bmatrix} a&b&c \end{bmatrix} \begin{bmatrix} l_x&l_y&l_z\\ m_x&m_y&m_z\\ n_x&n_y&n_z \end{bmatrix}= \begin{bmatrix} al_x+bm_x+cn_x&al_y+bm_y+cn_y&al_z+bm_z+cn_z \end{bmatrix}\)

\(\begin{bmatrix} al_x+bm_x+cn_x\\ al_y+bm_y+cn_y\\ al_z+bm_z+cn_z \end{bmatrix}=a \begin{bmatrix} l_x\\ l_y\\ l_z \end{bmatrix}+b \begin{bmatrix} m_x\\ m_y\\ m_z \end{bmatrix}+c \begin{bmatrix} n_x\\ n_y\\ n_z \end{bmatrix}= al+bm+cn\)

最终得到了由基向量表示的结果,由此可见

如果把矩阵的行解释为坐标系的基向量,那么乘以该矩阵就相当于执行了一次坐标转换,若有\(aM=b\),我们就可以说,\(M\)\(a\)转换到\(b\)

从另一个角度看,x,y,z分量分别代表了向量在每个基向量方向上分别“走了多少个单位”,变换的只是基向量的方向,而在每个方向上走多远却没有改变。

旋转

使用单位且正交的基向量\(x'\)\(y'\)\(z'\)构成新的坐标系,使用基向量构成的矩阵乘以向量\(v\)

\(\begin{bmatrix} v_x&v_y&v_z \end{bmatrix} \begin{bmatrix} x_x&x_y&x_z\\ y_x&y_y&y_z\\ z_x&z_y&z_z \end{bmatrix}= \begin{bmatrix} v'_x&v'_y&v'_z \end{bmatrix}\)

可以发现,在矩阵变换向量的过程中,也完成了旋转。

应用

首先确定一个\(forward\)正方向,利用世界空间的\(up\)方向\((0,1,0)\)通过叉积运算得到与\(forward\)正交的\(right\)方向,然后再利用计算得到的\(right\)方向通过叉积运算得到正确的\(up\)方向。

float3 forward = direction;
half isParallel = step(0.999, forward.y);
float3 up = isParallel * float3(0, 0, 1) + (1 - isParallel) * float3(0, 1, 0);
float3 right = normalize(cross(up, forward));
up = normalize(cross(forward, right));

\(up\)的计算中,为了防止\(forward\)方向与世界空间的\(up\)方向平行得到错误的计算,加入判断选择需要使用的向量。

例如可以使用计算得到的三个基向量变换模型空间的顶点位置,以此达到旋转模型的目的:

float3 newPos = positionOS.x * right + positionOS.y * up + positionOS.z * forward;

或者构成矩阵用以旋转向量:

float3x3 rotationMatrix = float3x3(right, up, forward);

在实际使用过程中注意左乘和右乘的区别,即行向量与列向量的使用区别:
向量以行表示,则矩阵以行构建,向量以列表示,则矩阵以列构建。
\(\begin{bmatrix} a&b&c \end{bmatrix} \begin{bmatrix} l_x&l_y&l_z\\ m_x&m_y&m_z\\ n_x&n_y&n_z \end{bmatrix}= \begin{bmatrix} al_x+bm_x+cn_x&al_y+bm_y+cn_y&al_z+bm_z+cn_z \end{bmatrix}\)

\(\begin{bmatrix} l_x&m_x&n_x\\ l_y&m_y&n_y\\ l_z&m_z&n_z \end{bmatrix} \begin{bmatrix} a\\ b\\ c \end{bmatrix}= \begin{bmatrix} al_x+bm_x+cn_x\\ al_y+bm_y+cn_y\\ al_z+bm_z+cn_z \end{bmatrix}\)

在Unity Shader中, float3x3(right, up, forward) 表示将向量以行向量的方式组成矩阵,故变换向量时使用 mul(vector, rotationMatrix) 方式计算,若 rotationMatrix 以列向量方式存储,故变换向量时使用 mul(rotationMatrix, vector) 方式计算。

参考

《3D数学基础:图形与游戏开发》

posted on 2024-09-05 19:58  WoBok  阅读(2)  评论(0编辑  收藏  举报