zifa2003293 发表于 2022-11-10 08:57

Unity面试题学习笔记(14)——U3D数学向量篇

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("前方");
      }
      else if(dotProduct == 0)
      {
            Debug.Log("右方");
      }
      else if(dotProduct < 0)
      {
            Debug.Log("后方");
      }
公式推导:




点乘公式推导出角度

角度 = 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("右侧");
      }
      else if(crossProduct.y < 0)
      {
            Debug.Log("左侧");
      }
总结:

向量叉乘对于我们的意义:

[*]得到一个平面的法向量。
[*]得到两个向量之间的左右位置关系。
当使用点乘或叉乘来判断两个物体的相对方向时:

[*]点乘用的两个向量分别是本物体的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);
页: [1]
查看完整版本: Unity面试题学习笔记(14)——U3D数学向量篇