Unity3D C#数学系列之变换矩阵推导

本文详细介绍了Unity中的矩阵基础,涵盖了仿射变换、齐次坐标、变换矩阵推导(包括平移、缩放、坐标系转换和旋转,涉及2D和3D空间)、以及关键矩阵的构建。通过实例演示了如何用4x4矩阵实现点和向量的平移、缩放和旋转,并探讨了齐次坐标的必要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


1 仿射变换与齐次坐标

《Unity3D C#数学系列之矩阵基础》中我们说到一个4×4的矩阵可以用来对三维空间中的点或向量进行各种变换,包括平移、旋转、缩放(当然还有错切、镜像等,由于我工作中这几种从来没用过,所以这里就不说这两种变换了)以及这几种变化的组合。这些变换有一个统一的名字,叫做仿射变换。三维空间中,只要是仿射变换,就可以用一个4×4的变换矩阵来表示。
但是为什么变换矩阵一定是4×4的呢,3×3行不行?答案是不行。如果不考虑点的平移,只考虑向量或点的旋转、缩放,3×3的矩阵就可以了。但如果考虑点的平移,3×3的矩阵就不满足要求了,必须扩充到4×4。至于为什么3×3无法表示平移,下面我们推导平移矩阵的时候就知道答案了。
我们知道三维空间中,一个点或者向量用3个变量x,y,z来表示就行了,但是在进行矩阵变换的时候,需要增加一维变量w。用(x, y, z, w)表示的向量或点,就叫齐次坐标。向量的w分量为0,点的w分量为1(为0时可以忽略掉平移的效果,如向量平移后还是它本身,为1时会保留平移的效果)。

2 变换矩阵的推导

2.1 变换矩阵推导一般过程

设4×4的变换矩阵为 M \textbf{M} M4×4
变换矩阵
设一个点A变换前的坐标为(x,y,z,w),变换后的点A’ 坐标为(x’,y’, z’,w’),则有
(还记得为什么点或向量的坐标要写成列矩阵的的形式吗,不记得了去看看上一篇文章)
变换矩阵推导的一般过程
矩阵乘法展开后就有方程组
矩阵乘法展开
我们上面说过,点的齐次坐标的w分量为1,所以又有
矩阵乘法展开
从上面方程组中的最后一个方程我们可以看出(无论x、y、z为何值都满足这个方程), m \textbf{m} m41 m \textbf{m} m42 m \textbf{m} m43全部等于0, m \textbf{m} m44等于1。
变换矩阵的一般推导过程
然后,我们令A(x,y,z,1)分别为(1, 0, 0, 1),(0,1,0, 1),(0,0,1, 1)同时我们需要分析出对应变换后的坐标A’(x’,y’, z’,1),然后代入上面的方程组的前3个,一般就能推导出平移、旋转、缩放的矩阵了。

2.2 平移矩阵

设点A(x,y,z,1)平移(a,b,c,0)(即在x轴方向平移a个单位,y方向平移b个单位,z方向平移c个单位),则A’点的坐标为(x + a,y + b,z + c,1),代入上面的方程组中有
平移矩阵的推导
无论x、y、z为何值都满足上面方程组中的各个方程,必然有
平移矩阵的推导
所以平移的变换矩阵为
平移矩阵
平移矩阵的逆矩阵如下:
平移矩阵的逆矩阵
如果我们用一个3×3的矩阵来进行平移变换,将方程组展开,会发现根本没有解。所以3×3的矩阵无法表示平移,但4×4的矩阵可以。其根本原因是因为平移不是线性变换,必须要扩展一维才可以
3×3矩阵无法表示平移变换

2.3 缩放矩阵

2.3.1 沿坐标轴的缩放

设向量(x,y,z,0)沿坐标轴缩放(kx,ky,kz,0),则缩放后的坐标为(kxx,kyb,kzz,0),代入2.1中的方程组中有
沿坐标轴的缩放矩阵
显然有
沿坐标轴的缩放矩阵
所以沿坐标轴缩放(kx,ky,kz)的缩放矩阵为
沿坐标轴的缩放矩阵
其逆矩阵为如下:
沿坐标轴的缩放矩阵的逆矩阵

2.3.2 沿任意轴的缩放

设向量 v ⃗ \vec{v} v (x,y,z,0)沿单位向量 n ⃗ \vec{n} n (nx,ny,nz,0)缩放k个单位,假设缩放后的坐标为 v ′ ⃗ \vec{v'} v (nx,ny,nz,0),现在我们要求缩放矩阵,必须先把 v ′ ⃗ \vec{v'} v 给求出来。
我们将 v ⃗ \vec{v} v 分为两个部分,一个是 v ⃗ \vec{v} v ,其垂直于 n ⃗ \vec{n} n ,沿着 n ⃗ \vec{n} n 缩放将对其不产生任何影响;另一个是 v ⃗ \vec{v} v //,其平行于 n ⃗ \vec{n} n ,沿着 n ⃗ \vec{n} n 缩放将对其产生影响。
沿任意轴的缩放
沿任意轴缩放的推导01
由于 v ⃗ \vec{v} v //平行于 n ⃗ \vec{n} n ,则有 v ⃗ \vec{v} v // = ( v ⃗ \vec{v} v · n ⃗ \vec{n} n ) n ⃗ \vec{n} n
所以 v ⃗ \vec{v} v //沿着 n ⃗ \vec{n} n 缩放k个单位后的值为k( v ⃗ \vec{v} v · n ⃗ \vec{n} n ) n ⃗ \vec{n} n
又由于 v ⃗ \vec{v} v ⃗垂直于 n ⃗ \vec{n} n ,所以 v ⃗ \vec{v} v ⃗沿着 n ⃗ \vec{n} n 缩放k个单位后的值仍为 v ⃗ \vec{v} v = v ⃗ \vec{v} v - v ⃗ \vec{v} v // = v ⃗ \vec{v} v -( v ⃗ \vec{v} v · n ⃗ \vec{n} n ) n ⃗ \vec{n} n
于是
沿任意轴缩放的推导02
v ⃗ \vec{v} v =(x,y,z), n ⃗ \vec{n} n =(nx,ny,nz )代入有,
沿任意轴缩放的推导03
代入2.1中的方程组中有
沿任意轴缩放的推导04
于是
沿任意轴缩放的推导05
所以沿单位向量 n ⃗ \vec{n} n (nx,ny,nz)缩放k个单位的缩放矩阵为
沿任意轴缩放k个单位的缩放矩阵

2.4 坐标系之间的变换

在推导旋转矩阵之前,我们先看看不同坐标系之间的变换矩阵是怎么推导的,这是推导旋转矩阵的基础。
我们在说一个点或者一个向量的坐标的时候,一定要知道这个坐标是在什么坐标系下的。
我们在说一个点或者一个向量的坐标的时候,一定要知道这个坐标是在什么坐标系下的。
我们在说一个点或者一个向量的坐标的时候,一定要知道这个坐标是在什么坐标系下的。
只要说到坐标,一定要立马想到这个坐标所在的坐标系
同一个点或者同一个向量,在不同坐标系下,它们的坐标值是不一样的。所以我们这里才会来求不同坐标系之间的变换矩阵。
这里先直接给出结论:
坐标系之间的变换
具体推导过程如下。
变换矩阵的推导
我们在上一篇文章《Unity3D C#数学系列之矩阵基础》中说过逆矩阵可以用来还原某种变换或者说反变换,且正交矩阵的逆矩阵就是其转置矩阵。并且,由标准正交基(长度为1的坐标系的x、y、z轴向量)构成的矩阵其实就是正交矩阵。
而对于向量,无论怎么平移,向量的值都是不变的,所以对于向量其变换矩阵使用3×3就足够了。那么对于向量,坐标系O’x’y’z’到Oxyz的变换矩阵也可求到了,如下。
坐标系变换矩阵的逆矩阵

2.5 旋转矩阵

2.5.1 二维平面中的旋转

我们先来看二维平面上的旋转。在二维平面上,我们说的旋转是指绕着某一个点旋转
说一条线绕着某一点(假设名字为旋转中心)旋转,是指该线上的所有点绕着旋转中心旋转。
说一个多边形绕着某一点(假设名字为旋转中心)旋转,是指这个多边形上的每一个点绕着旋转中心旋转。

2.5.1.1 绕原点的旋转

我们先来推导下二维平面Oxyz坐标系中,绕原点O旋转的旋转矩阵。
二维平面的旋转
设坐标系Oxyz是左手坐标系(因为Unity中世界坐标系和局部坐标系都是左手坐标系,所以我们这里举例子也按照Unity的来),A点绕着原点O旋转了θ度到达新点A‘,求旋转矩阵。
推导过程如下。
绕原点旋转的变换矩阵推导
绕原点的旋转矩阵推导
旋转矩阵是正交矩阵
(还记得正交矩阵满足什么条件吗?忘记了去复习一下《Unity3D C#数学系列之矩阵基础》第4.4节)
所以其逆矩阵就是其转置矩阵。
旋转矩阵的逆矩阵

2.5.1.2 绕任意点的旋转

如图,左手坐标系Oxyz中,B点在Oxyz坐标系的坐标为(a, b),求A点绕点B旋转θ角的旋转矩阵。
二维平面绕任意点的旋转
其推导过程如下:
二维平面绕任意点的旋转矩阵推导过程

2.5.2 三维空间中的旋转

三维空间说的旋转是指一个点或者一个向量绕着某一个方向或者说某一个轴旋转(二维是绕着某一个点)。

2.5.2.1 绕x轴的旋转

如图,A点绕X轴旋转θ度后到达A‘点(我们这里还是假设Oxyz坐标系是左手坐标系的)。
绕X轴的旋转
绕着X轴旋转其实可以理解在Oyz这个二维平面内绕着原点O进行旋转。然后将A’点和A点的x轴坐标设置为一样的。
上面这句话可能没表达清楚,看下面这张图应该就能理解了,其中灰色平面与Oyz平面平行。
三维空间绕X轴的旋转
根据上一节我们讲的二维平面中绕原点的旋转矩阵,咱们可以直接写出三维空间中绕x轴的旋转矩阵。
三维空间绕x轴旋转θ的旋转矩阵

2.5.2.2 绕y轴的旋转

同绕x轴的旋转,绕着y轴的旋转可以理解为在Oxz这个二维平面内绕着原点O进行旋转。然后将A’点和A点的y轴坐标设置为一样的。
绕y轴的旋转
绕y轴旋转θ角的旋转矩阵为
绕y轴旋转θ角的旋转矩阵

2.5.2.3 绕z轴的旋转

同绕x轴的旋转,绕着z轴的旋转可以理解为在Oxy这个二维平面内绕着原点O进行旋转。然后将A’点和A点的z轴坐标设置为一样的。
绕z轴旋转θ角的旋转矩阵
绕z轴旋转θ角的旋转矩阵为
绕z轴旋转θ角的旋转矩阵

2.5.2.4 绕任意轴的旋转

如图,Oxyz坐标系中,A点绕向量 r ⃗ {\vec{r}} r =(a,b,c)旋转θ度到达A’点,求旋转矩阵。
绕任意轴的旋转
绕任意轴的旋转与二维平面的旋转推导方法类似的,关键在建立一个辅助坐标系。
其推导过程如下:
绕任意轴的旋转矩阵推导
后面我实在是不想算了,要用的时候直接查资料吧。。。


博主本文博客链接。


### 投影矩阵的定义 投影矩阵(Projection Matrix)是一种在数学和计算机科学中广泛应用的矩阵形式,它能够将向量从一个空间映射到另一个空间。具体来说,投影矩阵可以将高维数据映射到一个低维子空间中,从而实现数据的降维处理。这种映射通常是线性变换,并且具有幂等性,即对一个向量进行两次投影变换的结果与一次投影变换相同[^1]。 ### 投影矩阵的作用 投影矩阵在多个领域有着重要的应用,尤其是在机器学习、数据分析以及信号处理等领域。通过精心选择投影的方向和方式,可以实现以下目标: - **数据压缩**:通过减少数据的维度来降低存储需求和传输成本。 - **噪声去除**:去除数据中的无关信息或噪声,提高数据质量。 - **特征提取**:从原始数据中提取出重要的特征,用于后续的分析或建模。 - **模式识别**:帮助发现数据中的潜在模式和结构,便于分类或聚类分析。 ### 投影矩阵的应用实例 在计算机图形学中,投影矩阵用于定义摄像机的视角,将三维场景转换为二维图像。例如,在Unity 3D中,可以通过修改摄像机的投影矩阵来实现特殊的视觉效果,如模拟摄像机的晃动效果。这通常涉及到对标准投影矩阵的调整,以适应特定的视觉需求[^2]。 ### 投影矩阵的数学推导 投影矩阵可以分为正交投影矩阵和透视投影矩阵两种类型。正交投影矩阵适用于平行投影,而透视投影矩阵则用于模拟人眼或相机的透视效果。透视投影矩阵可以通过正交投影矩阵与透视变换矩阵的乘积来获得,这一过程包括了从透视投影到正交投影的转换[^3]。 例如,透视投影矩阵 $ \mathbf{M}_{persp} $ 可以通过以下公式计算得到: $$ \mathbf{M}_{persp} = \mathbf{M}_{ortho} \cdot \mathbf{M}_{persp->ortho} $$ 其中,$ \mathbf{M}_{ortho} $ 是正交投影矩阵,而 $ \mathbf{M}_{persp->ortho} $ 是将透视投影转换为正交投影的变换矩阵。具体的矩阵形式如下所示: $$ \mathbf{M}_{ortho} = \begin{bmatrix} 2/(r-l) & 0 & 0 & 0 \\ 0 & 2/(t-b) & 0 & 0 \\ 0 & 0 & 2/(n-f) & 0 \\ 0 & 0 & 0 & 0 \end{bmatrix} $$ $$ \mathbf{M}_{persp->ortho} = \begin{bmatrix} 1 & 0 & 0 & -(l+r)/2 \\ 0 & 1 & 0 & -(b+t)/2 \\ 0 & 0 & 1 & -(f+n)/2 \\ 0 & 0 & 0 & 1 \end{bmatrix} \cdot \begin{bmatrix} n & 0 & 0 & 0\\ 0 & n & 0 & 0\\ 0 & 0 & n+f & -nf\\ 0 & 0 & 1 & 0 \end{bmatrix} $$ 通过这些矩阵的乘积,可以获得最终的透视投影矩阵,用于将三维坐标转换为二维屏幕坐标。 ### 示例代码 下面是一个简单的C#代码示例,展示了如何在Unity 3D中修改摄像机的投影矩阵以实现动态效果: ```csharp using UnityEngine; public class CameraProjectionExample : MonoBehaviour { public Matrix4x4 originalProjection; void Start() { originalProjection = Camera.main.projectionMatrix; } void Update() { Matrix4x4 p = originalProjection; p.m01 += Mathf.Sin(Time.time * 1.2F) * 0.1F; p.m10 += Mathf.Sin(Time.time * 1.5F) * 0.1F; Camera.main.projectionMatrix = p; } } ``` 这段代码首先保存了摄像机的原始投影矩阵,然后在每一帧更新时对矩阵的某些元素进行了动态调整,从而实现了摄像机视角的晃动效果。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值