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 }
运行即可查看效果。