Siki_Unity_3-16_3D数学基础
Unity 3-16 3D數學基礎
任務0-1:課程介紹
課程大綱:
1. 3D數學介紹
2. Unity中的幾種坐標系:
全局坐標系、屏幕坐標系等
坐標系間的坐標轉換:比如屏幕坐標轉換到世界坐標
3. 向量的基本概念:
4. 向量運算:
計算長度
向量與向量之間的加減乘,向量與標量之間的乘法,點乘和叉乘
5. 矩陣
6. 變換
任務1-1&1-2&1-3&1-4:3D數學介紹 -- 坐標系基礎知識
內容:
1D -- 數軸
2D -- 笛卡爾坐標系
3D -- 空間直角坐標系
左手坐標系和右手坐標系
1D:關于計數和度量的數學
數學上,數軸是一維的圖,數軸是一條規定了原點、方向和單位長度的直線
2D:笛卡爾坐標系 Cartesian coordinates
兩條直線可以確定一個唯一的平面(異面直線通過平移)
相交于原點的兩條數軸,構成了平面放射坐標系
若兩條數軸的單位長度相同,則為笛卡爾坐標系
是的,笛卡爾坐標系是笛卡爾直角坐標系和笛卡爾斜角坐標系的統稱
3D:空間直角坐標系
三個軸互相垂直
空間直角坐標系和Unity中的直角坐標系z軸方向是相反的
Unity為左手坐標系;
坐標(x, y, z)表示分別到三個平面的有符號距離
左手坐標系和右手坐標系:
空間直角坐標系:右手坐標系
OpenGL:右手坐標系
Direct3D:左手坐標系
Unity3D:左手坐標系
任務1-5:習題
1.3D笛卡爾坐標系中有一個點(2,3,3),如果不改變它的位置,將坐標系更改為OpenGL中使用的坐標系和Unity3D中使用的坐標系,則它的坐標值將分別變為多少?
2.在3DMAX中,使用的坐標系的方向為:+x向右,+y向前 (屏幕向內),+z向上。這個坐標系是左手坐標系還是右手坐標系?
解答:
1. 3D笛卡爾坐標系為右手坐標系,OpenGL也是使用右手坐標系,Unity3D使用的是左手坐標系
因此OpenGL的坐標和3D笛卡爾坐標系相同,為 (2, 3, 3)
Unity3D坐標的z值取負,為 (2, 3, -3)
2. 分別將拇指向右,食指向前,中指向上 -- 右手可以做到:右手坐標系
任務2-1&2-2&2-3&2-4:四種坐標系
(全局坐標系、局部坐標系、屏幕坐標系、視口坐標系)
內容:
1. 全局坐標系 World Coordinate System
2. 局部坐標系 Local Coordinate System
3. 屏幕坐標系 Screen Space
4. 視口坐標系 ViewPort Space
5. 坐標系之間的關聯和相互轉換
全局坐標系(世界坐標系)
Unity中,如果一個游戲物體沒有父物體,則Inspector中transform顯示的為全局坐標
Unity中,可以用transform.position取得一個物體的世界坐標
局部坐標系(物體坐標系、模型坐標系)
每個物體都有自身獨立的物體坐標系
當物體移動或改變方向時,和該物體相關聯的局部坐標系本身將隨之移動或改變方向
Unity中模型Mesh保存的頂點坐標均為局部坐標系下的坐標,因此物體的改變并不會影響頂點的坐標
Unity中,如果一個游戲物體沒有父物體,則它的本地坐標?
如果一個游戲物體是另一個的子物體,則Inspector中transform顯示的為局部坐標
可以通過transform.localPosition取得一個物體在其父物體的局部坐標系中的坐標
屏幕坐標系
建立在屏幕上的二維坐標系
以像素為單位,屏幕的左下角為(0, 0),右上角為 (Screen.width, Screen.height)
z軸坐標為相機的世界坐標中z軸的負值
鼠標位置坐標屬于屏幕坐標 -- Input.mousePosition
超出屏幕邊緣也是有返回值的(負值)
手指觸摸屏幕的坐標屬于屏幕坐標 -- Input.GetTouch(0).position
視口坐標系
將Game視圖的屏幕坐標系單位化,即左下角為(0, 0),右上角為(1, 1)
z軸坐標是相機的世界坐標中z軸坐標的負值
好處:得到的是比例,無需知道屏幕的大小
壞處:不能直接得到,需要通過其他坐標系進行轉換
任務2-5:世界坐標系與局部坐標系之間的關聯和相互轉換
&2-6:transform.forward和Vector3.forward
關聯:
移動一個游戲物體時:
transform.Translate(translation: Vector3, relativeTo: Space = Space.Self)
如果relativeTo=Space.Self (默認),則移動是按照局部坐標系來的
如果relativeTo=Space.World,則移動是按照世界坐標系來的
例:
transform.Translate(new Vector3(1, 0, 0) * Time.deltaTime); -- 局部坐標系的x軸方向
transform.Translate(new Vector3(1, 0, 0)*Time.deltaTime, Space.World); --世界坐標系
相互轉換:
坐標的轉換:
局部坐標系 -> 全局坐標系:Transform.TransformPoint(Vector3 position);
全局坐標系 -> 局部坐標系:Transform.InverseTransformPoint(Vector3 position);
方向的轉換:
局部坐標系 -> 全局坐標系:Transform.TransfromDirection(Vector3 direction);
全局坐標系 -> 局部坐標系:Transform.InverseTransformDirection(Vector3 direction);
向量的轉換:
局部坐標系 -> 全局坐標系:Transform.TransfromVector(Vector3 vector);
全局坐標系 -> 局部坐標系:Transform.InverseTransformVector(Vector3 vector);
transform.forward和Vector3.forward:
transform.forward, transform.right, transform.up:
當前物體的物體坐標系的三個坐標軸(z軸, x軸, y軸)在世界坐標系上的指向
注意:不是簡單的在物體坐標系中的指向
比如:
transform.Translate(transform.forward * Time...., Space.World);
先求出物體坐標系中的z軸正方向在世界坐標系中的坐標表示
然后將該坐標的值放在物體坐標系中,進行移動
例子:
物體順時針旋轉90°,因此物體坐標系為世界坐標系順時針旋轉90°
transform.Translate(transform.forward * Time.deltaTime, Space.Self);
transform.forward為物體的z軸方向,在世界坐標系中為x軸方向(1, 0, 0)
因為relativeTo=Space.Self,將(1,0,0)放入物體坐標系中,即物體坐標系x軸方向
故物體朝該方向移動 -- (一共進行了兩次轉換)
transform.Translate(transform.forward * Time.deltaTime, Space.World);
transform.forward為物體的z軸方向,在世界坐標系中為x軸方向(1, 0, 0)
因為relativeTo=Space.World, 方向在世界坐標系中為(1, 0, 0)
故物體朝該方向移動 -- (一共進行了一次轉換)
再舉個栗子,如果物體是順時針旋轉30°,那么
如果relativeTo=Space.World,那么就是朝著物體的z軸方向移動(30°方向)
如果relativeTo=Space.Self,則要在World情況下再旋轉30°,即為60°
因為物體坐標系相對于世界坐標系是順時針旋轉了30°的
再舉個栗子,如果物體是順時針旋轉45°的,那么
Space.World情況為朝著(45°)方向
Space.Self情況為朝著(90°)方向
Vector3.forward, Vector3.right, Vector3.up:
分別為(0,0,1) (1,0,0) (0,1,0)的縮寫
在transform.Translate()中使用時:
若不標明坐標系,則為物體的局部坐標,即物體自身的前右上方向
若relativeTo=Space.World,則為世界坐標系,即世界坐標的前右上方向
任務2-7:屏幕坐標系與全局坐標系之間的關聯和相互轉換
camera.WorldToScreenPoint(Vector3 position) -- 將世界坐標轉換為屏幕坐標camera.ScreenToWorldPoint(Vector3 position) -- 將屏幕坐標轉換為世界坐標
例子:
世界坐標轉換為屏幕坐標:
Camera.main.WorldToScreenPoint(transform.position);
若該物體位于屏幕中心顯示,且MainCamera的z軸坐標為-5
則Debug.Log的結果為(Screen.Width/2, Screen.Height/2, 5) -- z軸值正負相反
屏幕坐標轉換為世界坐標:
Vector3 mousePos = Input.mousePosition;
Vector3 sToW = Camera.main.ScreenToWorldPoint(mousePos);
此時Debug.Log的結果為 (0, 0, -5) -- 并不是我們想要的
因為ScreenToWorldPoint()是將mousePos投影在一個平面上
因此mousePos的坐標為(x, y, 0),與相機是重合的,因此不能視為平面,而是一個點
所以返回結果就是相機的坐標(0, 0, -5)
如果設置為離相機1000的平面,且鼠標是在屏幕中點位置,則為(0, 0, -5+1000)
使用例子:
Camera.main.ScreenToWorldPoint(new Vector3(mousePos.x, mousePos.y, 500);
即為鼠標所在屏幕坐標的位置在距離mainCamera 500的平面的投影
返回結果為(..., ..., 495); // 需要加上camera的z軸坐標為-5,
// 正中間為 (0, 0, 495),往左下為負,往右上為正
任務2-8:屏幕坐標、世界坐標與視口坐標之間的關聯和相互轉換
屏幕坐標轉換為視口坐標:camera.ScreenToViewportPoint(Vector3 position);
視口坐標轉換為屏幕坐標:camera.ViewportToScreenPoint(Vector3 position);
世界坐標轉換為視口坐標:camera.WorldToViewportPoint(Vector3 position);
視口坐標轉換為世界坐標:camera.ViewportToWorldPoint(Vector3 position);?
-- 與屏幕坐標和世界坐標之間的轉換相似,只不過多了一步屏幕坐標與視口坐標之間的轉換?
任務2-9:習題
1. 一個Cube的Transform信息如下:Position(0,2,5), Rotation(0,0,0), Scale(1,1,1)。它的父物體的Transform信息如下:Position(3,0,0), Rotation(0,90,0), Scale(1,1,1)。請問這個Cube的世界坐標為多少?
2. 實現功能:讓游戲物體在世界坐標系中按每秒移動(2,0,0)個單位的速度向右移動,在到達屏幕邊界時停止。
答案:
1.? ? 父物體的Transform為(3, 0, 0), 圍繞y軸旋轉90°,即x軸為世界坐標系z軸負方向
故父物體的局部坐標系的z軸為世界坐標系的x軸正方向
子物體相對于父物體的局部坐標系的坐標為(0, 2, 5)
子物體的世界坐標為(3, 0, 0) + (5 ,2 ,-0) = (8, 2, 0)
對于旋轉而言,父物體的Rotation為(0, 90, 0)
子物體相對于父物體沒有旋轉,因此子物體的相對于世界坐標的旋轉也為(0, 90, 0)
2.? ?// 按世界坐標系移動 -- transform.Translate(Vector3.right, Space.World);
// 每秒移動(2, 0, 0) -- * Time.deltaTime * 2;
// 到達屏幕邊界時停止 -- 判斷camera.main.WorldToViewportPoint(transform.position)
任務3-1&3-2:向量的定義 && 點和向量的關系
向量的基本概念
內容:
向量的定義
點和向量的關系
Unity中的點和向量
向量的定義:
向量,也成為矢量,具有大小和方向
向量的大小就是向量的長度,也成為模
向量的方向描述了空間中向量的指向
向量的書寫:
行向量:水平書寫的向量,如 [1,2,3]
列向量:豎直書寫的向量,如 (寫不出來)
通常用x, y來代表2D向量的分量,用x, y, z來代表3D向量的分量
分別表示向量在對應維度上的有向位移
(點的分量表示到對應軸的距離)
點和向量的關系:
點表示一個位置,沒有大小、方向的概念
向量表示一個有向位移,有大小和方向,可以形象化地表示為有向線段
求向量的值:終點坐標 - 起點坐標
任務3-3:Unity中的點和向量
在Unity中,只有Vector2, Vector3類,統一表示點和向量
比如:
transform.Translate(Vector3),此處為向量
transform.forward,此處為向量
camera.WorldToScreenPoint(Vector3),此處為點
transform.position,此處為點
計算兩點之間的距離時,即為計算以兩點為起點終點的向量的大小
任務3-4:習題
1. 一個向量的長度為4,它的起點A的坐標為(1,0),終點B的坐標(x,0),求x的值,并寫出這個向量。
2. 實現功能:讓一個游戲物體勻速移動到另一個游戲物體所在的位置。
答案:
1.? ? 向量可以表示為終點減起點,即(x,0) - (1,0) = (x-1, 0)
(x-1, 0)的長度為4,x-1=4,即x=5,向量為(4, 0)
注意,(x-1, 0)的長度為4的另一種情況是 x-1=-4,此時x=-3,向量為(-4, 0)
2.? ?// 移動功能
transform.Translate((other.position - transform.position) *?Time.deltaTime * speed, Space.World);
我向你移動,向量方向為我指向你,終點減起點,故為other.position - transform.position
// 到位置后的判斷
if(Vector3.Distance(other.position, transform.position) > 0.01f;
任務4:向量的運算
4-1&4-2&4-3&4-4:零向量、負向量、向量長度、向量與標量的乘法/除法、單位向量
&4-5:向量的加減法
零向量:唯一一個大小為零的向量,唯一一個沒有方向的向量
(0, 0) 或 (0, 0, 0)
在Unity中用Vector3.zero表示3D零向量
負向量:每個向量都有一個負向量
定義:一個向量和它的負向量相加等于零向量
與原向量大小相等,方向相反 (即原向量乘以標量-1)
將向量的每個分量都變負即可
向量的長度:
即向量的大小/ 向量的模?|AB|
如何求長度:向量各分量平方和的平方根?
在Unity中,vector3.magnitude即為向量的長度
vector3.sqrMagnitude為向量長度的平方
Vector3.Distance(A, B)可以計算兩點之間的長度,即向量(A-B)或(B-A).magnitude
向量與標量的乘法/除法:
把向量的每個分量分別與標量相乘/相除即可
注意除法的前提是非零標量
幾何含義:重復進行相同的有向位移
Unity中使用*來計算向量與標量的乘法,用/來計算向量與標量的除法
單位向量/ 標準化向量:
大小為1的向量
用處:在只關心向量方向,無所謂大小時,可以使用單位向量
歸一化 Normalization:對于任意非零向量,求其單位向量的過程
求得長度length后,用向量除以標量length即可求得它的單位向量
在Unity中可以使用vector3.Normalize()來歸一化向量 -- 原向量變成歸一化后的單位向量
使用vector3.normalized 來獲得該向量對應的單位向量 -- 原向量不變
例子:
vector.Normalize();
Vector3 new = vector.normalized;
向量的加法和減法:
兩個向量的加減法前提:兩個向量的維度相同
如何加減:將向量的各個對應分量進行相加/相減
與標量相同
加法滿足交換律:a + b = b + a
減法不滿足交換律:a - b = -(b - a)
幾何角度看:
向量加法是向量的拼接
向量減法是向量與另一個向量的負向量相加
在Unity中,向量的加法用+表示,減法用-表示
任務4-6&4-7:向量的點積
向量的點積/ 內積
向量與向量的乘法有兩種方式
一種是點積,也成為內積,表示為 a·b
點積計算公式:對應分量乘積的和,結果為標量
a·b=(ax,ay)·(bx,by)=axbx+ayby
比如:(0,2)·(3,3) = 0×3+2×3 = 0+6 = 6
點積滿足交換律:
a·b = b·a
點積計算公式2:通過兩個向量之間夾角的cos值
a·b = |a| |b| cosθ?
點積的幾何含義以及應用:
1. 點積的結果越大,表示兩個向量越相近 -- 從cos的函數可知
2. 常被用來計算兩個向量的夾角大小
3. 通過向量的點積的符號來判斷兩個向量的位置 (方向)關系
cos函數正負 --?
>0 : 夾角 0~90,方向基本相同
=0 : 夾角 =90,方向垂直
<0 : 夾角 90~180,方向基本相反
4. 通過點積求得一個向量在另一個向量上的投影
向量b在向量a上的投影的長度可以表示為:
(解釋: a·b = |a| |b| cosθ)
向量b在向量a上的投影可以表示為:
(解釋: p的方向與a的單位向量 a/|a|相同,因此 p=a/|a| * |p|
|p| = a·b/ |a| --> p = (a / |a|) * (a·b / |a| ))
a·a = |a| * |a|, 因為同方向,cos = 1
注意向量和標量)
在Unity中,用Vector3.Dot(v1, v2)來計算兩個向量的點積(返回值是float標量)
用Vector3.Angle()來計算兩個向量之間夾角的大小(結果在0~180之間)
任務4-8:向量的叉積
向量的叉積/ 外積
表示為?a×b
叉積的結果是一個向量
叉積僅可應用于3D向量
a×b=(ax,ay,az)×(bx,by,bz)=(aybz-azby,azbx-axbz,axby-aybx)
記憶:(除去x,除去y,除去z);(+,-,+);
例:(1,2,3)×(-2,-2,3)=(6-(-6),(-6)-3,(-2)+4)=(12,-9,2)
叉積的大小 (長度):向量的大小與向量夾角sin值的積
即 |a x b| = |a| |b| sinθ,也等于以a和b為兩邊的平行四邊形的面積大小
幾何含義:
1. 叉積得到的向量 垂直于 原來的兩個向量
可以通過向量的叉積得到兩個向量所在平面的法向量
2. 叉積的方向可以用來判斷b是在a的順時針方向或逆時針方向
Unity為左手坐標系,若求得叉積的方向向上,則為順時針旋轉
在Unity中,通過Vector3.Cross(v1, v2)?來計算向量的叉積
任務4-9:習題
1.向量(1,1)是單位向量嗎?如果不是的話,將它歸一化。
2.計算點(-1,3,2)與點(-2,3,-1)之間的距離。
3.已知向量a的長度為2,向量b的長度為3,夾角為60度。求a和b的點積和叉積的長度。
4.已知Unity中有2個向量a=(1,2,3),b=(-2,-2,3),請問b在a的順時針方向還是逆時針方向?
答案:
1. |(1, 1)| = sqr(12 + 12) = sqr(2) != 1,不是單位向量
(1, 1).normalized = (1/sqr(2), 1/sqr(2))
2. v = (-2,3,-1) - (-1,3,2) = (-1,0,-3)
v.magnitude = sqr(12+32) = sqr(10)
或Vector3.Distance((-1,3,2), (-2,3,-1))
3. |a| = 2, |b| = 3
cos = 1/2 -->?a·b = |a| |b| cos = 3
sin = sqr(3)/2 --> axb = |a| |b| sin = 3*sqr(3)
4. 通過叉積的方向判斷
a x b = (+(2*3-3*-2), -(1*3-3*-2), +(1*-2-2*-2)) = (12, -9, 2)
向下,Unity為左手坐標系,故a到b為逆時針方向旋轉,b在a的逆時針方向
任務5:矩陣
任務5-1&5-2:定義、矩陣和矩陣的加減法、矩陣和標量的乘法
矩陣內容:
矩陣的定義
矩陣和矩陣的加減法
矩陣和標量的乘法
矩陣和向量的乘法
矩陣和矩陣的乘法
特殊矩陣
矩陣的定義:
矩陣是一個按照長方陣排列的復數或實數的集合
矩陣的維度:矩陣有幾行幾列
比如 r x c矩陣:有r行、c列
(向量的維度是看該向量有幾個分量)
在一個m x n的矩陣中,有m*n個數,這些數為矩陣的元素
aij位于矩陣的第i行第j列,成為矩陣的(i, j)元
注:下標 ij 從1開始
Unity中,
通過Matrix4x4.SetRow()和Matrix4x4.SetColumn()來設置4x4矩陣的某行或某列
通過Matrix4x4.GetRow()和Matrix4x4.GetColumn()來獲取4x4矩陣的某行或某列
注意:這里的index從0開始
-- 具體見任務6
矩陣和矩陣的加減法:
加減法的前提:矩陣的維度相同
兩個矩陣的相加/相減即:矩陣各相同位置的元素的相加/相減
在Unity中,沒有矩陣之間加減的運算符,一般不會做矩陣和矩陣的加減法
矩陣和標量的乘法:
矩陣和標量相乘,得到的是一個相同維度的矩陣
規則:矩陣的每個元素和該標量的乘積
任務5-3:矩陣和向量的乘法
向量可以被當做是一行或一列的矩陣(行向量/列向量)
因此矩陣和向量的乘法可以看成是矩陣和矩陣的乘法
矩陣和矩陣相乘的前提:第一個矩陣的列數 = 第二個矩陣的行數
r x n矩陣 * n x c矩陣 = r x c矩陣
--> 一般情況下:行向量 * 矩陣,得到的還是行向量 1 x n
矩陣 * 列向量,得到的還是列向量,n x 1
乘法規則:
矩陣和向量相乘的結果向量中,每個元素都是原向量和矩陣中單獨行或者列的點積
在Unity中,一般會將向量轉換為矩陣后,再與矩陣相乘
任務5-4:矩陣和矩陣的乘法
矩陣A和矩陣B相乘,得到的矩陣C中的任意元素Cij等于A的第i行向量與B的第j行向量的點積
例:
任務5-5:單位矩陣
特殊矩陣:
方塊矩陣
對角矩陣
單位矩陣
轉置矩陣
逆矩陣
方塊矩陣:行數 = 列數,即 n x n矩陣
在方塊矩陣中,行號=列號的元素成為對角元素
對角矩陣:前提是方塊矩陣
除了對角元素之外的所有元素都為0
單位矩陣:前提是對角矩陣
當對角矩陣的對角元素全為1
單位矩陣的性質:
任意矩陣乘以單位矩陣,都將得到原矩陣
A I = A;? I A = A;
在Unity中
通過 Matrix4x4.zero得到一個4x4的所有元素都為0的矩陣
通過 Matrix4x4.identity得到一個4x4的單位矩陣
通過 matrix4x4.isIdentity來判斷一個矩陣是否為單位矩陣
任務5-6:轉置矩陣
轉置矩陣是對原矩陣進行轉置運算后得到的矩陣
r x c的矩陣進行轉置后,得到一個 c x r的矩陣。
轉置運算即將原矩陣的第i行變為第i列,第j列變為第j行 -- 沿對角線翻折
在Unity中,通過Matrix4x4.Transpose(matrix) 得到矩陣matrix的轉置矩陣
任務5-7&5-8:逆矩陣
逆矩陣:一個矩陣A和它的逆矩陣B滿足 AB = I
即 AA-1 = I 或 A-1A = I 或 AA-1?= A-1A = I
逆矩陣的前提:只有方塊矩陣才可能有逆矩陣
可逆/ 非奇異:一個矩陣有相應的逆矩陣,則這個矩陣是可逆的/ 非奇異的
不可逆/ 奇異:一個矩陣沒有相應的逆矩陣,則這個矩陣是不可逆的/ 奇異的
如何判斷可逆:
如果一個矩陣的行列式不為0,則是可逆的
行列式的計算方法:
二階行列式的計算方法:對角線的乘積相減
三階行列式的計算方法:代數余子法
行列式可以按某一行或某一列展開成元素與其對應的代數余子式的乘積之和
行列式某元素的余子式:
行列式刪去該元素所在的行和列的各元素,由剩下的元素組成的新的行列式
行列式某元素的代數余子式:
行列式某元素的余子式與該元素對應的正負號的乘積
正負號:
例子:
這里選擇的是第一行元素的代數余子式之和
下面通過第一列元素求行列式
因為行列式為0,該矩陣不可逆,是奇異的
逆矩陣的求解:
4x4的逆矩陣求解:?
|A| 表示A的行列式
a11c表示a11的代數余子式
注意:是轉置矩陣
例子:
行列式的計算 |A| :
逆矩陣的求解:
四階矩陣的逆矩陣更加復雜,就不說明了
在Unity中,通過Matrix4x4.Inverse(matrix)得到一個矩陣的逆矩陣
如:Matrix4x4 matrix1 = Matrix4x4.Inverse(matrix);? // 得到逆矩陣A-1
Matrix4x4 matrix2 = matrix * matrix1;? // AA-1
Debug.Log(matrix2.isIdentity); // AA-1 = I;輸出true
任務5-9:習題
1.判斷下列運算是否合理,合理的話計算結果。
(1)?
(2)
2.已知矩陣A,(1)求矩陣A的轉置矩陣,(2)如果A有逆矩陣的話,求A的逆矩陣。
A=
答案:
1. (1) 合理,2x2 2x2
[ 2*1+1*2 2*4+1*6] ? ?[4? 14]
[ 3*1+2*2 3*4+2*6] = [7? 24]
? ?(2) 不合理,3x3 2x1
2. AT=? ?[4? -1? 0]
[1? ?2? ?1]
[0? ?3? -1]
|A|,以第一行元素為標準
= 4 * | 2? 3 | - 1 * | -1? 3 | + 0
??| 1? -1 | ? | 0? -1 |
= 4*(-5) - 1*(1)
= -21
!= 0 --> 可逆
? ?求逆矩陣A-1:
任務6:變換
任務6-1:齊次變換
變換內容:
齊次變換
2D變換
3D變換
Unity中的變換
齊次變換:
將一個原本是n維的向量用一個n+1維的向量來表示
(x,y,z) -> (x,y,z,1)
優點:在投影幾何中,笛卡爾坐標對變換來說不方便
而笛卡爾坐標是適用于歐式幾何中的
齊次坐標系是計算機圖形學的重要手段之一
既能用來明確區分向量和點,同時也易于進行仿射幾何變換
詳解:
對于標準的空間直角坐標系:基向量是a=(1,0,0) b=(0,1,0) c=(0,0,1),原點為O
坐標系中任意一個向量v(vx,vy,vz)的坐標都可以用基向量來表示v=vxa+vyb+vzc
坐標系中任意點的位置(px,py,pz),可以視為原點的平移,需要考慮原點位置O,
表示為P=pxa+pyb+pzc+O
而上面的表示可以用矩陣的形式寫出:
?
任意3D坐標系可以表示為:
基向量a=(ax,ay,az), b=(bx,by,bz), c=(cx,cy,cz), 原點坐標(Ox,Oy,Oz)
因為是點,所以右下方為1
點的齊次坐標表示為 (x, y, z, 1)
向量的齊次坐標表示為 (x, y, z, 0)
用齊次坐標進行運算:
點與點之間的減法,得到一個向量 -- 起點指向終點的向量
向量與向量之間的加減法,得到一個向量 -- 向量的疊加
點和向量之間的加法,得到一個點 -- 點的平移
任務6-2:仿射變換
仿射變換:包括了線性變換和平移
代數上:線性變換指可以保留矢量加和標量乘的變換
需要滿足這兩個條件:
?-- v和u是矢量,s是標量
幾何上理解,線性變換需要滿足的條件:
1. 變換前是直線的,變換后依然是直線
2. 線段長度的比例保持不變
3. 變換前是原點的,變換后依然是原點
旋轉、縮放都滿足線性變換的這三個要求
但是,平移滿足了1、2,不滿足要求3
而因為仿射變換包括了線性變換和平移
因此可得:平移、旋轉、縮放都屬于仿射變換
仿射變換的幾何角度的要求是:
1. 變換前是直線的,變換后依然是直線
2. 線段長度的比例保持不變
仿射變換可以用矩陣和向量相乘的方式來表示
計算一個點或者一個向量,經過平移、旋轉、縮放等仿射變換后的值
一個三維的變換可以表示為:
?-- 前面的矩陣成為變換矩陣,c為點或向量的值
變換矩陣的前三列用來表示旋轉和縮放,又因平移不是線性變換,因此最后一列表示平移
任務6-3&6-4&6-5:2D變換(平移變換、縮放變換、旋轉變換)
2D平移矩陣:
最后結果為[px,py,1] + [tx,ty,0] -- 即為點加向量的形式
2D縮放矩陣:
--> 可以求得最后的形式為 s * [px, py, 1],即縮放比例乘以點坐標
2D旋轉矩陣:
例子:把點(3,2)圍繞O點逆時針旋轉90°
注意,這里面x->y角度為正
推導:
任務6-6:2D變換的逆矩陣
平移矩陣的逆矩陣:
?-- 平移 (-tx, -ty)的距離
解釋:
縮放矩陣的逆矩陣:
?-- 縮放 (1/sx, 1/sy) 倍數即可
旋轉矩陣的逆矩陣:
?-- 往反方向旋轉相同度數即可
解釋:
任務6-7:物體變換和坐標系變換
有些時候的變換是物體在變換,有些時候的變換是變換了一個坐標系
F為坐標系,M為變換矩陣,c為點坐標或向量
如果是物體變換,則可寫為 F(Mc) -- 得到在F中c'的值
如果是坐標系變換,則可寫為 (FM)c -- 得到F'的值
物體變換:
--[b1, b2, b3, O] 表示坐標系,bn分別表示基向量,O表示原點
例子:
?
坐標系變換:
-- 將變換應用到坐標系,得到新坐標系[b1', b2', b3', O']
例子:?
將坐標系i變換M --> 得到坐標系i'
P點坐標不變,仍為[2,2],但因為所在坐標系變了,因此P點位置變了
但是不管是什么變換,不管是物體變換還是坐標系變換:(FM)c = F(Mc)
任務6-8:復合變換
復合變換:將平移、旋轉、縮放結合起來的復雜的變換過程
因為矩陣乘法不滿足交換律,因此變換矩陣的先后順序很重要
(畫外音:結合律是滿足的,比如上一節所說的FMc的例子)
比如先旋轉再移動,和先移動再旋轉,結果是不一樣的
例子:
c: (2,2) 在標準笛卡爾坐標系中,先平移 (-2,1), 再旋轉90°
?
法1 -- 物體變換:
法2 -- 坐標系變換:
藍色為F,黑色為F',紫色為F''
任務6-9:3D變換
3D平移矩陣:
3D縮放矩陣:
3D旋轉矩陣:
?
繞著a軸旋轉,則a軸的值不會發生變化,比如繞著x軸旋轉,則第一行第一列不變
2D旋轉可以視為在3D中繞著z軸旋轉 -- 右手坐標系
繞x軸旋轉--y到z正方向; 繞z軸旋轉--x到y正方向; 繞y軸旋轉--x到z負方向 --> 正負號
任務6-10:Unity中的變換
Matrix4x4.Translate(Vector3 translation) -- 返回一個平移矩陣
Matrix4x4.Rotate(Quaternion rotation) -- 返回一個旋轉矩陣
Matrix4x4.Scale(Vector3 scaler) -- 返回一個縮放矩陣
Matrix4x4.TRS(Vector3 t, Quaternion r, Vector3 s)--返回一個移動+旋轉+縮放的復合矩陣
matrix4x4.MultiplyPoint(vector3) -- Transforms a position by this matrix (Generic)
matrix4x4.MultiplyPoint3x4(vector3) -- (Fast)
Returns a position?v?transformed by the current fully arbitrary matrix.
If the matrix is a regular 3D transformation matrix, it is much faster to
use?MultiplyPoint3x4?instead.?
MultiplyPoint?is slower, but can handle projective transformations as well.
遍歷Mesh上的所有點,分別進行TRS變換 -- 物體位置沒有變化,但Mesh的顯示變化了
matrix4x4.MultiplyVector(Vector vector) -- 將一個向量按照matrix4x4進行變換
任務6-11:習題
1. 將一個游戲物體先進行大小為(2,3,3)的縮放,再繞y軸旋轉60度,最后再移動(-1,2,5)個單位,寫出這個復合變換的變換矩陣(不用計算)。
答案:
Ts = [ 2? 0? 0? 0 ]
[ 0? 3? 0? 0 ]
[ 0? 0? 3? 0 ]
[ 0? 0? 0? 1 ]
Tr?= [cos60? ?0? sin60? 0 ]
[? ?0? ? ? ?1? ? ?0? ? 0 ]
[-sin60? 0? cos60 0 ]
[? ?0? ? ? ?0? ? ?0? ? ?1 ]
Tt?= [ 1? 0? 0? -1 ]
[ 0? 1? 0? 2? ]
[ 0? 0? 1? 5? ]
[ 0? 0? 0? 1? ]
TRS = Tt Tr Ts pos
?
?
轉載于:https://www.cnblogs.com/FudgeBear/p/8869241.html
總結
以上是生活随笔為你收集整理的Siki_Unity_3-16_3D数学基础的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ubuntu18.04下的mysql创建
- 下一篇: 【c++】——通过cmake定义宏add