找回密码
 立即注册
查看: 126|回复: 0

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

[复制链接]
发表于 2022-11-10 08:57 | 显示全部楼层 |阅读模式
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);

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-6-30 06:27 , Processed in 0.062643 second(s), 23 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表