Unity Vector3.Slerp() 球形插值详解之二

来源:互联网 发布:java实现猜数字游戏 编辑:程序博客网 时间:2024/05/16 08:14
using UnityEngine;using System.Collections;/// <summary>/// 在日出和日落之间动画弧线/// 网上看到有人对Vector3.Slerp()的详解,但是经过962f之力将他的思路看明白。/// 受到启发,就有了自己对Vector3.Slerp()的理解。tt2()函数、tt3()函数是自己的写的,tt4()是别人的。/// tt2()函数球形插值/// tt3()函数利用球形插值绘制类似抛物线。/// </summary>public class Vector3_Slerp_2 : MonoBehaviour{    /// <summary>    /// 日出    /// </summary>    public Transform sunrise;    /// <summary>    /// 日落    /// </summary>    public Transform sunset;    /// <summary>    /// 计算中间点的一个因素    /// </summary>    public float m_centerFac = 0.5f;    /// <summary>    /// 插值中心点的影响因素    /// </summary>    public float m_moveTowardsValue = 1f;    /// <summary>    /// 插值的个数    /// </summary>    public int m_lineNum = 30;    private Vector3 mStart = Vector3.zero;    private Vector3 mEnd = Vector3.zero;    void Update()    {        //tt2();        tt3();        //tt4();    }    /// <summary>    /// 官方用例    /// </summary>    private void tt1()    {        //弧线的中心        Vector3 center = (sunrise.position + sunset.position) * 0.5f;        //向下移动中心,垂直于弧线        center -= new Vector3(0, 1, 0);        //相对于中心在弧线上插值        Vector3 riseRelCenter = sunrise.position - center;        Vector3 setRelCenter = sunset.position - center;        transform.position = Vector3.Slerp(riseRelCenter, setRelCenter, Time.time);        transform.position += center;    }    /// <summary>    ///  球面插值    ///  自己的理解    ///  只在垂直平面上做球面插值。    /// </summary>    private void tt2()    {        mStart = sunrise.position;        mEnd = sunset.position;        /// 绘制世界坐标系        Debug.DrawLine(new Vector3(-100, 0, 0), new Vector3(100, 0, 0), Color.green);        Debug.DrawLine(new Vector3(0, -100, 0), new Vector3(0, 100, 0), Color.green);        Debug.DrawLine(new Vector3(0, 0, -100), new Vector3(0, 0, 100), Color.green);                /// 求出起始点与终点的中心点        Vector3 center = (mStart + mEnd) * m_centerFac;        ////////////////////////////////////        /// 1. center、mStart、mEnd 构成一个平面A        ////////////////////////////////////        Debug.DrawLine(new Vector3(center.x, 0f, center.z), center, Color.white);        /// 绘制一个三角形        Debug.DrawLine(new Vector3(center.x, 0f, center.z), mStart, Color.white);        Debug.DrawLine(new Vector3(center.x, 0f, center.z), mEnd, Color.white);        Debug.DrawLine(mStart, mEnd, Color.white);        Vector3 normal = mEnd - mStart;        ///只在垂直平面上做球面插值。        Vector3 tangent = new Vector3(center.x, 0f, center.z) - center;               /// 两个坐标轴的正交化。        Vector3.OrthoNormalize(ref normal, ref tangent);        float moveTowardsValue = (mEnd - mStart).magnitude * m_moveTowardsValue;        Vector3 center2 = center + tangent * moveTowardsValue;        ////////////////////////////////////        /// 2. 两个坐标轴的正交化后 center2、mStart、mEnd 构成一个平面B,        /// 3. 平面B与平面A是同一平面。        ////////////////////////////////////        Debug.DrawLine(center2, mStart, Color.blue);        Debug.DrawLine(center2, mEnd, Color.blue);        Debug.Log(string.Format("{0} : {1}", Vector3.Distance(center2, mStart), Vector3.Distance(center2, mEnd)));        for (int i = 1; i < m_lineNum; ++i)        {            Vector3 drawVec = Vector3.Slerp(mEnd - center2, mStart - center2, 1f / m_lineNum * i);            drawVec += center2;            Debug.DrawLine(center2, drawVec, Color.yellow);        }        /// 绘制起始点与终点的中心点到计算出的插值的中心点        Debug.DrawLine(center, center2, Color.black);    }    /// <summary>    ///  利用球面插值模拟抛物线    ///  自己的理解    /// </summary>    private void tt3()    {        mStart = sunrise.position;        mEnd = sunset.position;        /// 绘制世界坐标系        Debug.DrawLine(new Vector3(-100, 0, 0), new Vector3(100, 0, 0), Color.green);        Debug.DrawLine(new Vector3(0, -100, 0), new Vector3(0, 100, 0), Color.green);        Debug.DrawLine(new Vector3(0, 0, -100), new Vector3(0, 0, 100), Color.green);        /// 求出起始点与终点的中心点        Vector3 center = mEnd + (mStart - mEnd) * m_centerFac;        ////////////////////////////////////        /// 1. center、mStart、mEnd 构成一个平面A        ////////////////////////////////////        Debug.DrawLine(new Vector3(center.x, mEnd.y, center.z), center, Color.white);        /// 绘制一个三角形        Debug.DrawLine(new Vector3(center.x, mEnd.y, center.z), mStart, Color.white);        Debug.DrawLine(new Vector3(center.x, mEnd.y, center.z), mEnd, Color.white);        Debug.DrawLine(mStart, mEnd, Color.white);        Vector3 normal = mStart - mEnd;        ///只在垂直平面上做球面插值。        Vector3 tangent = new Vector3(center.x, mEnd.y, center.z) - center;        /// 两个坐标轴的正交化。        Vector3.OrthoNormalize(ref normal, ref tangent);        float moveTowardsValue = (mEnd - mStart).magnitude * m_moveTowardsValue;        //Vector3 center2 = center + tangent * moveTowardsValue;        Vector3 center2 = center - Vector3.up * moveTowardsValue;        ////////////////////////////////////        /// 2. 两个坐标轴的正交化后 center2、mStart、mEnd 构成一个平面B,        /// 3. 平面B与平面A是同一平面。        ////////////////////////////////////        Debug.DrawLine(center2, mStart, Color.blue);        Debug.DrawLine(center2, mEnd, Color.blue);        Debug.Log(string.Format("{0}:{1} -- {2}:{3}", Vector3.Distance(center2, mStart), Vector3.Distance(center2, mEnd),             Vector3.Distance(mEnd, mStart), Vector3.Distance(center2, center)));        for (int i = 1; i < m_lineNum; ++i)        {            Vector3 drawVec = Vector3.Slerp(mEnd - center2, mStart - center2, 1f / m_lineNum * i);            drawVec += center2;            Debug.DrawLine(center2, drawVec, Color.yellow);        }        /// 绘制起始点与终点的中心点到计算出的插值的中心点        Debug.DrawLine(center, center2, Color.black);    }    /// <summary>    /// 球面插值    /// http://www.manew.com/thread-43314-1-1.html 文章用例    /// </summary>    private void tt4()    {        mStart = sunrise.position;        mEnd = sunset.position;        Debug.DrawLine(new Vector3(-100, 0, 0), new Vector3(100, 0, 0), Color.green);        Debug.DrawLine(new Vector3(0, -100, 0), new Vector3(0, 100, 0), Color.green);        Debug.DrawLine(new Vector3(0, 0, -100), new Vector3(0, 0, 100), Color.green);             Debug.DrawLine(Vector3.zero, mStart, Color.white);        Debug.DrawLine(Vector3.zero, mEnd, Color.white);        Debug.DrawLine(mStart, mEnd, Color.white);        /// 求出起始点与终点的中心点        Vector3 centor = (mStart + mEnd) * 0.5f;        Debug.DrawLine(Vector3.zero, centor, Color.blue);        Vector3 centorProject = Vector3.Project(centor, mStart - mEnd); // 中心点在两点之间的投影        centor = Vector3.MoveTowards(centor, centorProject, m_moveTowardsValue);        // 沿着投影方向移动移动距离(距离越大弧度越小)        Debug.DrawLine(centor, mStart, Color.blue);        Debug.DrawLine(centor, mEnd, Color.blue);        Debug.Log(string.Format("{0} : {1}", Vector3.Distance(centor, mStart), Vector3.Distance(centor, mEnd)));        for (int i = 1; i < m_lineNum; ++i)        {            Vector3 drawVec = Vector3.Slerp(mEnd - centor, mStart - centor, 1f / m_lineNum * i);            drawVec += centor;            Debug.DrawLine(centor, drawVec, Color.yellow);            //Debug.DrawLine(centor, drawVec, 5 == i ? Color.blue : Color.yellow);        }    }}

0 0