|
1.向量:
概念:
- 标量:有数值大小,没有方向。
- 向量:有数值大小,有方向的矢量(一维,二维,三维....)。
几何意义:
//Vector3有两种几何意义
//1.位置 —— 代表一个点
Debug.Log(transform.position);
//2.方向 —— 代表一个方向
Debug.Log(transform.forward);
Debug.Log(transform.up);
Debug.Log(transform.right);
两点决定一向量:
//从A指向B的向量为AB向量
//B - A = Vector3(AB)
//从B指向A的向量为BA向量
//A - B = Vector3(BA)
//终点减起点
//A和B此时几何意义是两个点
Vector3 A = new Vector3(1, 2, 3);
Vector3 B = new Vector3(5, 1, 5);
//求向量,此时AB和BA的几何意义是两个向量
Vector3 AB = B - A;
Vector3 BA = A - B;
//求另一个物体到本物体的向量
//transform.position - target.transform.position
零向量和负向量:
零向量:(0,0,0),唯一一个大小为0的向量。
负向量:
- (x,y,z)的负向量为(-x,-y,-z)。
- 负向量和原向量大小相等。
- 负向量和原向量方向相反。
//零向量
Debug.Log(Vector3.zero);
//负向量
Debug.Log(-Vector3.forward);
向量的模长:
- 向量的模长就是向量的长度。
- 向量是由两个点算出,所以向量的模长就是两个点的距离。
- 模长公式(求Vector3 A(x,y,z)的模长):
模长=\sqrt{x^{2}+y^{2}+z^{2}}
//Vector3中提供了获取向量模长的成员属性
//magnitude
Debug.Log(AB.magnitude);
//和Vector3.Distance(A, B);的结果一样
Vector3 C = new Vector3(1, 5, 7);
Debug.Log(C.magnitude);
单位向量:
- 模长为1的向量为单位向量。
- 任意一个向量经过归一化就是单位向量。
- 只需要方向,不想让模长影响计算结果时使用单位向量。
- 归一化公式(求Vector3 A(x,y,z)的单位向量):
单位向量=(x/模长,y/模长,z/模长)
//返回一个单位向量
Debug.Log(C.normalized);
//将原向量变为单位向量
Debug.Log(C);
C.Normalize();
Debug.Log(C);
2.向量的运算:
向量加法:
公式:向量A(Xa,Ya,Za),向量B(Xb,Yb,Zb),则A + B = (Xa + Xb,Ya + Yb,Za + Zb)。
几何意义:
- 位置+位置:没有任何几何意义。
- 向量+向量:两个向量相加得到一个新向量(向量相加,首尾相连)。
- 位置+向量:位置加向量得到一个新的位置(位置和向量相加=平移位置,沿着向量的方向移动向量模长的距离)。
向量减法:
公式:向量A(Xa,Ya,Za),向量B(Xb,Yb,Zb),则A - B = (Xa - Xb,Ya - Yb,Za - Zb)。
几何意义:
- 位置-位置:两个位置相减得到一个新向量(两点决定一向量,详情看上一节)。
- 向量-向量:两个向量相减得到一个新向量(向量相减,头连头,尾指尾,A - B = B头指A头)。
- 位置-向量:位置减向量相当于加负向量(实际意义和位置+向量相同,只不过方向相反)。
- 向量-位置:没有任何意义。
向量乘除法:
向量只会和标量进行乘除法运算。
几何意义:
- 向量 */ 标量 = 向量
- 向量 */ 正数 = 方向不变,放大缩小模长
- 向量 */ 负数 = 方向相反,放大缩小模长
- 向量 * 0 = 得到零向量
3.点乘:
公式:
向量A(Xa,Ya,Za),向量B(Xb,Yb,Zb)
A · B = Xa * Xb + Ya * Yb + Za * Zb
向量 · 向量 = 标量
几何意义:
点乘可以得到一个向量在自己向量上投影的长度。(B · A是向量A在向量B上投影的长度再乘上B向量的模长)
点乘的几何意义
- 点乘结果 > 0,两个向量夹角为锐角
- 点乘结果 = 0,两个向量夹角为直角
- 点乘结果 < 0,两个向量夹角为钝角
测试画线:
//画线段(起点,终点)
Debug.DrawLine(transform.position, transform.position + transform.forward, Color.green);
//画射线(起点,方向)
Debug.DrawRay(transform.position, transform.up, Color.red);
通过点乘判断对象方位:
Debug.DrawRay(this.transform.position, this.transform.forward, Color.red);
Debug.DrawRay(this.transform.position,
(enemy.transform.position - this.transform.position).normalized,
Color.blue);
//得到两个向量的点乘结果
//向量a 点乘 向量AB的结果
float dotProduct = Vector3.Dot(transform.forward,
(enemy.transform.position - this.transform.position).normalized);
if(dotProduct > 0)
{
Debug.Log(&#34;前方&#34;);
}
else if(dotProduct == 0)
{
Debug.Log(&#34;右方&#34;);
}
else if(dotProduct < 0)
{
Debug.Log(&#34;后方&#34;);
}
公式推导:
点乘公式推导出角度
角度 = Acos(单位向量A · 单位向量B)
//求玩家到目标的向量
Vector3 dis = (enemy.transform.position - this.transform.position).normalized;
//第一步,用单位向量算出点乘结果
Mathf.Acos(Vector3.Dot(dis, transform.forward));
//第二步,用反三角函数得出角度
float angle = Mathf.Acos(Vector3.Dot(dis, transform.forward)) * Mathf.Rad2Deg;
Debug.Log(angle);
//直接使用API
Debug.Log(Vector3.Angle(dis, transform.forward));
总结:
向量点乘对于游戏开发的意义:
4.叉乘:
公式:
向量A(Xa,Ya,Za),向量B(Xb,Yb,Zb)
A × B = (YaZb - ZaYb,ZaXb-XaZb,XaYb-YaXb)
向量 × 向量 = 向量
叉乘计算:
//crossProduct是一个Vector3类型的变量
crossProduct = Vector3.Cross(A.position, B.position);
几何意义:
- A × B 得到的向量同时垂直A和B。
- A × B 向量垂直于A和B组成的平面(法向量)。
- 法向量的方向在Unity中遵循左手定理(用左手的四指先表示向量a的方向,然后手指朝着手心的方向摆动到向量b的方向,大拇指所指的方向就是向量c的方向,注意旋转角度不得超过180°,或者说应该选择旋转量较小的一方)。
- A × B = -(B × A)
叉乘向量的方向:
正右负左
//假如向量A和B都在 XZ平面上
//向量A 叉乘 向量B
//y大于0 证明 B在A的右侧
//y小于0 证明 B在A的左侧
crossProduct = Vector3.Cross(A.position, B.position);
if(crossProduct.y > 0)
{
Debug.Log(&#34;右侧&#34;);
}
else if(crossProduct.y < 0)
{
Debug.Log(&#34;左侧&#34;);
}
总结:
向量叉乘对于我们的意义:
- 得到一个平面的法向量。
- 得到两个向量之间的左右位置关系。
当使用点乘或叉乘来判断两个物体的相对方向时:
- 点乘用的两个向量分别是本物体的forward(transform.forward)和参照物体与本物体之间的向量(target.position - this.transform.position),且点乘的结果与向量顺序无关。
- 叉乘用的两个向量分别是本物体的position和参照物体的position,叉乘结果和向量顺序有关(Vector3.Cross(本物体位置,参照物体位置)),保持顺序才能获得参照物体对于本物体的位置。
5.向量插值:
线性插值:
概念:
Vector3.Lerp(start,end,t);
对两点进行插值计算,t的取值范围为0 - 1。
应用:
- 1.每帧改变start的值(先快后慢)
- 2.每帧改变t的值(匀速)
//result = start + (end - start) * t
//1.先快后慢
A.position = Vector3.Lerp(A.position, target.position, Time.deltaTime);
//2.匀速
if(targetPos != target.position)
{
targetPos = target.position;
starPos = B.position;
//为什么不用Time.time?
//因为Time.time会不断增加,且无法置零。所以用可以置零的自定义float变量。
m_time = 0;
}
m_time += Time.deltaTime;
B.position = Vector3.Lerp(starPos, targetPos, m_time);
球形插值:
概念:
Vector3.Slerp(start,end,t)
- 对两个向量进行插值计算,t的取值范围为0-1。
- 线性插值是平移,直线运动;球形插值是旋转,弧形运动。
应用:
和Lerp相同,只是API和运动轨迹不同。
//1.先快后慢
A.position = Vector3.Slerp(A.position, target.position, Time.deltaTime);
//2.匀速
if (targetPos != target.position)
{
targetPos = target.position;
starPos = B.position;
m_time = 0;
}
m_time += Time.deltaTime;
B.position = Vector3.Slerp(starPos, targetPos, m_time); |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|