什么是四元数:提到四元数代表旋转,旋转轴可以是任意一轴

unity 向量在XZ面上的投影_世界坐标

四元数设置物体旋转角度:四元数涉及到旋转轴:axis,旋转弧度:rad

unity 向量在XZ面上的投影_世界坐标_02

 与四元数相乘

 

unity 向量在XZ面上的投影_四元数_03

unity 向量在XZ面上的投影_世界坐标_04

与向量相乘

unity 向量在XZ面上的投影_四元数_05

计算物体右前方30度,10米远坐标?

第一种方法:

unity 向量在XZ面上的投影_世界坐标_06

TransformPoint :自身坐标转世界,本质就是对向量做旋转然后叠加到物体上

  第二种方法:

this.transform.position=this.transform.position+Quaternion.Euler(0,30,0)

*this.transform.rotation*new vector3(0,0,10)。

对上面的式子进行分解:

unity 向量在XZ面上的投影_unity 向量在XZ面上的投影_07

54行相乘是当前物体转的时候把向量Vector3(0,10,0) 也转了。

54 56行代码vect向量是相对于世界的,所以才有58行,

58行vect通过加物体的世界位置坐标得到相对于物体的向量。

 

四元数应用:

unity 向量在XZ面上的投影_unity 向量在XZ面上的投影_08

创建Capsule(玩家Player)假设把玩家先放在世界原点(0,0,0)位置,球Sphere(炸弹),求切点的脚本文件挂在炸弹上。

using UnityEngine;
using System.Collections;

/// <summary>
/// 切点探测器
/// </summary>
public class TangentDetector : MonoBehaviour
{
    private Vector3 leftTangent;
    private Vector3 rightTangent;

    private Transform playerTF;
    private float radius;
    private void Start()
    {
        GameObject playerGO  = GameObject.FindWithTag("Player");
        if (playerGO != null)
        {
            playerTF = playerGO.transform;
            radius = playerGO.GetComponent<CapsuleCollider>().radius;
        }
        else
        {
            this.enabled = false;
        }
    }
//计算切点
    public void CalaculateTangent()
    {
        Vector3 playerToExplosion = transform.position - playerTF.position;
        Vector3 playerToExplosionRadius = playerToExplosion.normalized * radius;
        float angle = Mathf.Acos(radius / playerToExplosion.magnitude) * Mathf.Rad2Deg;            
        rightTangent = Quaternion.Euler(0, angle, 0) * playerToExplosionRadius;
        leftTangent =  Quaternion.Euler(0, -angle, 0) * playerToExplosionRadius;


    }

    //**************测试**************
    private void Update()
    {
        CalaculateTangent();

        Debug.DrawLine(transform.position, leftTangent);
        Debug.DrawLine(transform.position, rightTangent);
    }
}

结果如下: 

unity 向量在XZ面上的投影_世界坐标_09

但是一旦移动玩家切点不随玩家移动:

 

 下面我们从代码引擎来分析,玩家移动之后

unity 向量在XZ面上的投影_世界坐标_10

7: 是世界坐标原点(0,0,0)

1:理解中的玩家到炸弹的向量:  playerToExplosion

     transform.position 炸弹的世界坐标位置  ; playerTF.position玩家的世界坐标位置

     Vector3 playerToExplosion = transform.position - playerTF.position;

2:实际引擎中的玩家到炸弹的向量:是从世界坐标原点发出的

3:截取实际的长度为半径radius的玩家到炸弹的向量  

 Vector3 playerToExplosionRadius = playerToExplosion.normalized * radius;

6:把3截取的向量旋转一定的角度到待求的切点位置即旋转到4的位置,根据三角函数反余弦求出旋转角度

 float angle = Mathf.Acos(radius / playerToExplosion.magnitude) * Mathf.Rad2Deg;

4:由6求的旋转角度得出playerToExplosionRadius被旋转之后的半径长向量 绿线4(相当于切点的位置)

   rightTangent =  Quaternion.Euler(0, angle, 0) * playerToExplosionRadius;

 然而这只是相对于世界原点的,移动玩家,切点(即绿线4)不会随之移动,于是需要把绿线4移动到绿线8的地方与玩家同步

绿线8处的切点如何求呢,即用绿线4+玩家坐标向量得到红色向量5.

5:玩家自身边界,两个切点

 rightTangent =playerTF .position + Quaternion.Euler(0, angle, 0) * playerToExplosionRadius;

 leftTangent = playerTF.position + Quaternion.Euler(0, -angle, 0) * playerToExplosionRadius;

   移动玩家,切点跟随

unity 向量在XZ面上的投影_旋转角度_11

四元数优点:避免万向节死锁

unity 向量在XZ面上的投影_旋转角度_12

缺点:

unity 向量在XZ面上的投影_unity 向量在XZ面上的投影_13