3D數學基礎
向量
向量可以看做具有方向和大小的一條線段。
比如:我們如果用點A減去點B,則可以得到一個向量,該向量的方向為點B面向點A的方向,而大小為兩點的距離。這個方法在遊戲開發中經常用到,比如我們要讓物體B面向物體A,一般都是使用物體B的位置減去物體A的位置,得到的向量取模。
點積
向量的點積表示一個向量在另一個向量上的投影,如下:
而相互垂直的兩個向量點積為0:
我們可以使用這個特性來判斷兩個向量是否垂直。
Unity提供的計算點積的方法如下:
public static float Dot(Vector3 lhs, Vector3 rhs);
叉積
向量的叉積可以得到垂直於兩個向量的第3個向量,如下:
而得到的向量的方向是根據我們使用的是左手座標系還是右手座標系來決定的。
Unity提供的計算叉積的方法如下:
public static Vector3 Cross(Vector3 lhs, Vector3 rhs);
3D數學在Unity3D中的應用
Vector3取模
- Vector.normalized:返回當前向量的模,向量本身的值不變;
- 靜態方法Vector.Normalize(Vector3):返回引數向量的模,引數本身的值不變;
- Vector.Normalize:沒有返回值,向量本身程式設計自己的模;
Demo06
下面我們的這個例子是製作一個指北針,我們需要先製作一個小星球和一個在這個小星球上走動的小人,然後在製作一個指北針,該指北針始終指向小星球的北極。
小星球製作
小星球的製作我使用了一款外掛:Maoots(點選這裡下載),下面我們一步一步來實現小星球和在這個星球上漫步的小人。
1.首先匯入Maoots外掛;
2.為場景新增一個線性光源;
3.新增一個空物體Man,然後找到MagicBoots\FBX\penelopeFBX預製件,將其作為該空物體的子項新增(注意一定要使用外掛提供的模型,因為外掛的程式碼中有模型動畫控制的程式碼,如果使用自己的模型執行時會因為動畫問題報錯導致無法正常執行);
4.為Man新增CapsuleCollider和Rigidbody並調整一個碰撞體的位置(引數請設定和截圖一致),如下:
5.為Main Camera新增MagicBoots\Scripts\MagicCamera並將Man下的penelopeFBX設定為Target Character,並設定引數如下:
6.新增一個名為“Level”的Layer;
7.新增一個球體,這個球體就是我們的小星球了,設定其圖層為“Level”,併為其新增一個碰撞體(自帶的就行),調整一下Man和小星球的位置,如下:
8.為Man新增MagicBoots\Scripts\MagicBoots指令碼,並進行如下的設定:
9.好了,現在可以執行一下看看了,不出意外的話我們的角色就可以在小星球上奔跑了;
10.在小星球的頂部新增一個小旗杆表示為北極,同時在人物頭頂新增一個小箭頭表示指北針,我們的指北針會始終指向小旗杆,再新增天空盒子和地面貼圖美化一下場景就可以了。
注意:由於我是使用的Unity5,在持續移動人物時會出現傾斜的問題,該問題在Unity4上是沒有的。
指北針製作
主要使用到叉積的運算,我們新增下面的程式碼到攝像機即可:
1 using UnityEngine; 2 using System.Collections; 3 4 public class Demo06Script : MonoBehaviour 5 { 6 /// <summary> 7 /// 小人. 8 /// </summary> 9 public Transform player; 10 11 /// <summary> 12 /// 星球. 13 /// </summary> 14 public Transform planet; 15 16 /// <summary> 17 /// 每秒旋轉速度. 18 /// </summary> 19 public float rotateSpeed = 45; 20 21 //對應的上方向 22 private Vector3 playerUp; 23 private Vector3 planetUp; 24 25 //指北針 26 private Transform compass; 27 28 void Awake() 29 { 30 playerUp = player.up; 31 planetUp = planet.up; 32 33 compass = GameObject.Find("Man/compass").transform; 34 } 35 36 void Update() 37 { 38 playerUp = player.up; 39 planetUp = planet.up; 40 41 //求星球和小人上方向向量的叉積, 得到了一個平面 42 Vector3 crossValue = Vector3.Cross(planetUp, playerUp).normalized; 43 44 //求小人和上方獲得的叉積的叉積, 這條線段指向北極 45 Vector3 northValue = Vector3.Cross(playerUp, crossValue).normalized; 46 47 //繪製線段 48 Debug.DrawLine(player.position, player.position + player.up * 100, Color.black); 49 Debug.DrawLine(player.position, player.position + planet.up * 100, Color.green); 50 Debug.DrawLine(player.position, player.position + crossValue * 100, Color.blue); 51 Debug.DrawLine(player.position, player.position + northValue * 100, Color.red); 52 53 //旋轉指北針 54 Quaternion target = Quaternion.LookRotation(northValue, playerUp); 55 //每幀旋轉一定角度 56 compass.transform.rotation = Quaternion.RotateTowards(compass.transform.rotation, target, rotateSpeed * Time.deltaTime); 57 } 58 }
執行即可檢視效果。