问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

是坐标转换,也是旋转——矩阵变换

创作时间:
作者:
@小白创作中心

是坐标转换,也是旋转——矩阵变换

引用
1
来源
1.
https://www.cnblogs.com/WoBok/p/18399163

矩阵变换是3D图形学和游戏开发中的核心概念之一,它不仅能够实现坐标系之间的转换,还能够完成向量的旋转。本文将从基向量的表示开始,逐步解释矩阵变换的基本原理,并通过具体的代码示例展示其在实际应用中的实现方式。

坐标转换

一个向量可以被表示为(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数学基础:图形与游戏开发》

本文原文来自cnblogs

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号