Unity中的数学基础知识---向量的基础应用

一、向量的减法

①获取两个物体之间的距离(使用向量的模判断)

注意:Unity3D中的模可以直接使用向量的magnitude属性直接获得,如果不需要开平方根,可以使用向量的sqrMagnitude获得,这样,在一些不需要直接获取向量的模的时候可以减少运算量,因为平方根比较消耗计算时间。

/***
 *
 *  Title: 第16章 3D数学
 *  Description:
 *        功能:向量的减法           
 *  Date: 2019
 *  Version: 1.0
 *  Modify Recorder:
 *     
 */
using UnityEngine;
using System.Collections;

public class Demo1 : MonoBehaviour {
    public Transform traOther;                    //其他物体    
    private float _FloCloseDistance=5.0F;         //设定限制接近的最小距离


	void Update () 
    {
	    if (traOther) 
        {
	        //使用向量减法( other.position - transform.position)获得两个对象之间的向量
            var sqrLen = (traOther.position - transform.position).sqrMagnitude;
	        // 使用sqrMagnitude取代Magnitude来计算距离,提高运算效率
            if (sqrLen < _FloCloseDistance * _FloCloseDistance)
            {
                print("其他物体太接近我了!");
            }
            else {
                print("其他物体距离很远,目前很安全!");
            }
	    }	
	}
}

②获取两个物体之间的距离(可以使用Unity向量类中的Distance(Vector3 a,Vector3 b)函数 )

/// <summary>
        /// 获取到两个物体之间的距离
        /// </summary>
        /// <param name="targetObj">目标对象</param>
        /// <param name="needMoveObj">需要移动的对象</param>
        /// <returns></returns>
        public float GetDistance(Transform targetObj,Transform needMoveObj,int Method=1)
        {
            float distance=0;
            if (targetObj!=null && needMoveObj!=null)
            {
                switch (Method)
                {
                    case 1:
                        distance = Vector3.Distance(targetObj.position, needMoveObj.position);
                        break;
                    case 2:
                        ////获取到模的平方
                        //distance = (targetObj.position - needMoveObj.position).sqrMagnitude;
                        //获取到模的长度(消耗资源)
                        distance = (targetObj.position - needMoveObj.position).magnitude;
                        break;
                    default:
                        break;
                }

            }
            return distance;
        }

二、向量的加法

两个向量的维数必须相同,才能够相加减。

意义:向量a加向量b解释为:平移向量,使向量a的头连接向量b的尾,接着从a的尾向b的头画出一个向量(也叫三角形法则)

三、对向量进行单位化 (获取方向)

意义:只关心向量方向而不关心大小,比如飞机的朝向,某个面的法线朝向等。

单位向量就是大小为1的向量,它经常也被称为标准化向量、法线(Normal)或者归一化

单位化向量=向量/向量的模(且向量的模不等于0),可以使用Unity中的normalized属性或者Normalize()函数将向量单位化

 Vector3 goNormalVec1 = Vector3.Normalize(gameObject.transform.position);
 Vector3 goNormalVec2 = gameObject.transform.position.normalized;

 Debug.Log("Vector3.Normalize方法物体的单位向量=" + goNormalVec1);
 Debug.Log("normalized属性物体的单位向量=" + goNormalVec2);

、向量与标量相乘(实现移动)

向量乘以标量K的效果是以因子|K|缩放向量的长度;如若果K<0,则向量除了做缩放操作外还使得向量方向倒转。

/***
 *
 *  Title: 第16章 3D数学
 *
 *  Description:
 *        功能:向量与标量的乘法
 *            
 *  Date: 2019 
 *  Version: 1.0
 *  Modify Recorder:
 *     
 */
using UnityEngine;
using System.Collections;

public class Demo2 : MonoBehaviour 
{
    public Vector3  speedDirection;                      //速度
    public float speedScale=1F;                          //加速比率

    void Update () 
    {
        gameObject.transform.position += speedDirection * speedScale*Time.deltaTime;
	
    }
}
         /// <summary>
        /// 移动到目标点(跟随目标)
        /// </summary>
        /// <param name="targetObj">目标对象</param>
        /// <param name="needMoveObj">需要移动的对象</param>
        public void MoveToTargetPostion(Transform targetObj,Transform needMoveObj,float moveSpeed=0.5F)
        {
            if (targetObj!=null && needMoveObj != null && moveSpeed>=0)
            {
                //先计算二者方向 
                Vector3 dir = (targetObj.position - needMoveObj.position).normalized;
                //物体从当前位置移动到目标位置
                needMoveObj.position +=  dir * Time.deltaTime * speed;
            }
        }

 五、向量的乘法

①向量的点乘

意义:点乘的计算结果给出了两个向量的相似程度,该相似度反映在两个向量之间的夹角上;

点乘结果越大,两个向量越接近;

点乘公式:a.b=||a|||b||cosθ==> θ = arccos(a·b)

如果只需知道a和b的夹角类型而不用知道该夹角的确切值,可以只根据所求出点乘结果的符号来判断

即a.b>0方向基本相同   a.b=0 a和b正交,相互垂直

        //测试点积
        private void TestDot(Vector3 a,Vector3 b)
        {
            //计算a,b点积结果
            float result = Vector3.Dot(a,b);
            Debug.Log("计算a,b点积结果="+result);

            //通过向量直接获取两个向量的夹角(默认是角度)该方法范围是[0-180]
            float angle = Vector3.Angle(a,b);
            Debug.Log("通过向量计算a,b向量夹角=" + angle);

            //计算a、b单位向量的点积,得到夹角余弦值|a.normalized|*|b.normalized|=1
            result = Vector3.Dot(a.normalized,b.normalized);
            Debug.Log("计算a,b单位向量的点积得到的余弦值=" + result);

            //通过反余弦函数获取向量a、b夹角(默认是弧度)
            float radians = Mathf.Acos(result);
            Debug.Log("反余弦计算a,b夹角=" + radians);
            //将弧度转换为角度
            angle = radians * Mathf.Rad2Deg;
            Debug.Log("计算反余弦计算a,b角度=" + angle);

        }
/***
 *
 *  Title: 
 *         第16章 3D数学
 *
 *  Description:
 *        功能:
 *            学习向量的“点乘”
 *            估算两个游戏对象的夹角角度。
 *
 *  Date: 2017
 * 
 *  Version: 1.0
 *
 *  Modify Recorder:
 *     
 */
using UnityEngine;
using System.Collections;

public class Demo3: MonoBehaviour {
    public Transform TraOther;                   //其他物体的方位
    private Vector3 _VecForward;                 //前方
    private Vector3 _VecToOther;                 //其他方向


    void Update () {
        if (TraOther){
            //使用TransformDirection把当前对象的正面朝向从局部坐标系转换到世界坐标系下,使得该向
            //量与其他对象的位置向量在世界坐标系下统一
            //Vector3.forward表示该对象当前的正方向向量
            _VecForward = transform.TransformDirection(Vector3.forward);
            //使用向量减法获得其他对象到当前对象之间的向量
            _VecToOther = TraOther.position - transform.position;
            //使用点乘计算结果的符号来判断其他对象是否在当前对象的后方
            if (Vector3.Dot(_VecForward, _VecToOther) > 0)
            {
                print("其他对象在我前方!");
            }
            else
            {
                print("其他对象在我后方。");
            }

           
        }
	}
}

/***
 *
 *  Title: 
 *         第16章 3D数学
 *
 *  Description:
 *        功能:
 *            学习向量的“点乘”
 *            计算两个游戏对象的确切夹角角度。
 *
 *  Date: 2017
 * 
 *  Version: 1.0
 *
 *  Modify Recorder:
 *     
 */
using UnityEngine;
using System.Collections;

public class Demo4: MonoBehaviour {
    public Transform TraTarget;                  //目标
    private Vector3 _VecTargetDir;
    private Vector3 _VecForward;
    private float _FloAngle;

    /*  当对象的朝向与目标对象夹角小于5时,打印“视线靠近了”信息 */
	void Update () {
	    //使用向量减法获得当前对象与目标对象之间的向量
        _VecTargetDir = TraTarget.position - transform.position;
	    //当前对象的正方向向量
        _VecForward = transform.forward;
	    //求出targetDir和forward向量之间的夹角值
        _FloAngle = Vector3.Angle(_VecTargetDir, _VecForward);
	    //判断该夹角是否小于5
        if (_FloAngle < 5.0)
        {
            print("视线靠近了!");	
        }
        else {
            print("视线没有靠近。");	
        }
	}
}

 ②向量的叉乘

意义:叉乘计算的结果是向量,该向量垂直于原来的两个向量

Vector3 normal = Vector3.Cross (fromVector,toVector);//叉乘求出法线向量 

angle *= Mathf.Sign (Vector3.Dot(normal,upVector));  //求法线向量与物体上方向向量点乘,结果为1或-1,修正旋转方向 

计算出平面的法向量

Vector3 side1=b-a;
Vector3 side2=c-a;
Vector3 Normal=Vector3.Cross(side1,side2);
Normal.Normalize();
        //叉乘
        private void TestCross(Vector3 a, Vector3 b)
        {

            //计算向量 a、b 的叉积,结果为 向量 
            Vector3 c = Vector3.Cross(a, b);

            // 通过反正弦函数获取向量 a、b 夹角(默认为弧度)
            float radians = Mathf.Asin(Vector3.Distance(Vector3.zero, Vector3.Cross(a.normalized, b.normalized)));
            float angle = radians * Mathf.Rad2Deg;

            // 判断顺时针、逆时针方向,是在 2D 平面内的,所以需指定一个平面,
            //下面以X、Z轴组成的平面为例 , (Y 轴为纵轴),
            // 在 X、Z 轴平面上,判断 b 在 a 的顺时针或者逆时针方向,
            if (c.y > 0)
            {
                Debug.Log(" b 在 a 的顺时针方向");
            }

            else if (c.y == 0)
            {
                Debug.Log(" b 和 a 方向相同(平行)");
               
            }       
            else
            {
                Debug.Log("  b 在 a 的逆时针方向");
  
            }

        }



        // 获取两个向量的夹角  Vector3.Angle 只能返回 [0, 180] 的值
        // 如真实情况下向量 a 到 b 的夹角(80 度)则 b 到 a 的夹角是(-80)
        // 通过 Dot、Cross 结合获取到 a 到 b, b 到 a 的不同夹角
        private void GetAngle(Vector3 a, Vector3 b)
        {
            Vector3 c = Vector3.Cross(a, b);
            float angle = Vector3.Angle(a, b);

            // b 到 a 的夹角
            float sign = Mathf.Sign(Vector3.Dot(c.normalized, Vector3.Cross(a.normalized, b.normalized)));
            float signed_angle = angle * sign;

            Debug.Log("b -> a :" + signed_angle);

            // a 到 b 的夹角
            sign = Mathf.Sign(Vector3.Dot(c.normalized, Vector3.Cross(b.normalized, a.normalized)));
            signed_angle = angle * sign;

            Debug.Log("a -> b :" + signed_angle);

        }

 注意:本内容参考:《Unity3D/2D游戏开发从0到1》第16章

                                    http://www.manew.com/youxizz/2982.html

                                    https://blog.csdn.net/yupu56/article/details/53609028

                                    https://blog.csdn.net/Game_jqd/article/details/78908152

猜你喜欢

转载自blog.csdn.net/xiaochenXIHUA/article/details/89553118
今日推荐