游戏中的数学公式(增录中...)

以下代码中 using M = GameHelper.Math.Mathf; 为自定义类 可以替换为你们自己实现这些公式的类
1.三次Hermite插值余项:
(Unity中 动画曲线插值算法,d1 ,d2 分别为斜率)
文献:https://blog.csdn.net/luolei188/article/details/86563231
实现:
(注意避免出现 t1 == t2 ,否则会出现无穷大的问题)

/// 
/// 三次Hermite插值余项 
/// 
/// 需求时间
/// 时间1
/// 时间2
/// 时间1上的值
/// 时间2上的值
/// 倒数1
/// 倒数2
/// 
public static float MathfHermite(float t, float t1, float t2, float v1, float v2, float d1, float d2)
{
    float value1 = (t - t1) / (t2 - t1), value2 = (t - t2) / (t1 - t2);
    float value3 = (t - t2) / (t1 - t2), value4 = (t - t1) / (t2 - t1);
    float value5 = (t - t2) / (t1 - t2), value6 = (t - t1) / (t2 - t1);
    float value = v1 * (1 + 2 * value1) * (value2 * value2)
        + v2 * (1 + 2 * value3) * (value4 * value4)
        + d1 * (t - t1) * (value5 * value5)
        + d2 * (t - t2) * (value6 * value6);
    return value;
}
//如果是Unity动画插值计算,t:想要获取的时间,t1 关键帧1的时间,t2 关键帧2的时间, v1 关键帧1的值,v2关键帧2的值,d1关键帧1的出斜率,d2 关键帧2的入斜率

测试代码:
(最终效果)
游戏中的数学公式(增录中...)_第1张图片

//可以通过修改 key1Out 和key2In 来控制控制柄角度 实现不同的曲线
//以下代码是在x ,z 平面内工作的,请忽略y轴
using UnityEngine;
using System.Collections;
using M = GameHelper.Math.Mathf;

public class Hermite : MonoBehaviour {

    [Range(-180,180)]
    public float key1Out = 0;
    [Range(-180, 180)]
    public float key2In = 0;

    public Transform key1, key2, time,tValue;
    private float t1, t2, v1, v2, t;

    [Range(30,100)]
    public int Step = 30;

    void OnDrawGizmos()
    {
        Gizmos.DrawLine(Vector3.zero,Vector3.zero + new Vector3(1000,0,0));
        Gizmos.DrawLine(Vector3.zero, Vector3.zero + new Vector3(0, 0, 1000));
        if (key1 == null || key2 == null || time == null || tValue == null) return;
        if (key1 != null) t1 = key1.position.x;
        if (key1 != null) v1 = key1.position.z;
        if (key2 != null) t2 = key2.position.x;
        if (key2 != null) v2 = key2.position.z;
        t = time.position.x;
        
        //避免t1 == t2 ,否则可能会出现被除数为0的情况
		if(t1==t2) t2+=0.00001f;
        float value = M.MathfHermite(t,t1,t2,v1,v2, key1Out, key2In);
        tValue.position = new Vector3(t,0,value);

        float f1 = (t2 - t1) / Step;
        Vector3 pre = new Vector3(t1,0,v1);
        for (int i = 1; i <= Step; i++)
        {
            float x = t1 + i* f1;
            float y = M.MathfHermite(x, t1, t2, v1, v2, key1Out, key2In);
            Vector3 current = new Vector3(x,0,y);
            Gizmos.DrawLine(pre,current);
            pre = current;
        }
    }
}

2.贝塞尔曲线:
(游戏中常用的曲线绘制方法,例如(Handles.DrawBezier))
文献:https://blog.csdn.net/xiaozhangcsdn/article/details/98963937
一次贝塞尔曲线:

/// 
/// 一次贝塞尔曲线
/// 
/// 时间(0,1)
/// 起点
/// 终点
/// 
public static float MathfOneBezier(float t, float s, float e)
{
    	return (1 - t) * s + t * e;
}

/// 
/// 一次贝塞尔曲线
/// 
/// 比例值(0,1)
/// 起点
/// 终点
/// 
public static Vector3 MathfOneBezier(float t, Vector3 s, Vector3 e)
{
	    Vector3 tv = Vector3.zero;
	    tv.x = MathfOneBezier(t, s.x, e.x);
	    tv.y = MathfOneBezier(t, s.y, e.y);
	    tv.z = MathfOneBezier(t, s.z, e.z);
	    return tv;
}

二次贝塞尔曲线:

/// 
/// 二次贝塞尔曲线
/// 
/// 时间(0,1)
/// 起点
/// 终点
/// 控制点
/// 
public static float MathfTwoBezier(float t, float s, float e, float c)
{
    float value1 = (1 - t);
    return value1 * value1 * s + 2 * t * value1 * c + t * t * e;
}
/// 
/// 二次贝塞尔曲线
/// 
/// 时间(0,1)
/// 起点
/// 终点
/// 控制点
/// 
public static Vector3 MathfTwoBezier(float t, Vector3 s, Vector3 e, Vector3 c)
{
    Vector3 tv = Vector3.zero;
    tv.x = MathfTwoBezier(t, s.x, e.x, c.x);
    tv.y = MathfTwoBezier(t, s.y, e.y, c.y);
    tv.z = MathfTwoBezier(t, s.z, e.z, c.z);
    return tv;
}

三次贝塞尔曲线:

/// 
/// 三次贝塞尔曲线
/// 
/// 时间(0,1)
/// 起点
/// 终点
/// 起点控制点
/// 终点控制点
/// 
public static float MathfThreeBezier(float t, float s, float e, float sc, float ec)
{
    float value1 = 1 - t;
    return s * value1 * value1 * value1 + 3 * sc * t * value1 * value1 + 3 * ec * t * t * value1 + e * t * t * t;
}

/// 
/// 三次贝塞尔曲线
/// 
/// 时间(0,1)
/// 起点
/// 终点
/// 起点控制点
/// 终点控制点
/// 
public static Vector3 MathfThreeBezier(float t, Vector3 s, Vector3 e, Vector3 sc, Vector3 ec)
{
    Vector3 tv = Vector3.zero;
    tv.x = MathfThreeBezier(t, s.x, e.x, sc.x, ec.x);
    tv.y = MathfThreeBezier(t, s.y, e.y, sc.y, ec.y);
    tv.z = MathfThreeBezier(t, s.z, e.z, sc.z, ec.z);
    return tv;
}

附带 贝塞尔曲线测试代码:
(最终效果)

using UnityEngine;
using System.Collections;
using M = GameHelper.Math.Mathf;

public class Test : MonoBehaviour {

    public enum BezierType
    {
        One,
        Two,
        Three
    }
    [Range(0,1)]
    public float Range = 0;
    public Transform S, E, SC, EC, Target;
    public BezierType bt = BezierType.One;

    private Vector3 SP, EP, SCP, ECP;
    [Range(10,100)]
    public float Step = 30;

    void OnDrawGizmos()
    {
        if (S != null) SP = S.transform.position;
        if (E != null) EP = E.transform.position;
        if (SC != null) SCP = SC.transform.position;
        if (EC != null) ECP = EC.transform.position;
        if (bt == BezierType.One)
        {
            SetTargetPos(M.MathfOneBezier(Range, SP, EP));
            Gizmos.DrawLine(SP, EP);
        }
        else if (bt == BezierType.Two)
        {
            SetTargetPos(M.MathfTwoBezier(Range, SP, EP, SCP));
            DrawBizer( BezierType.Two);
        }
        else if (bt == BezierType.Three)
        {
            SetTargetPos(M.MathfThreeBezier(Range, SP, EP, SCP, ECP));
            DrawBizer( BezierType.Three);
        }
    }
    void DrawBizer(BezierType type)
    {
        Vector3 prePos = SP;
        for (int i = 1; i <= Step; i++)
        {
            Vector3 current = type== BezierType.Two? M.MathfTwoBezier(i / Step, SP, EP, SCP):M.MathfThreeBezier(i/Step,SP,EP,SCP,ECP);
            Gizmos.DrawLine(prePos, current);
            prePos = current;
        }
    }
    void SetTargetPos(Vector3 pos)
    {
        if (Target != null)
            Target.position = pos;
    }
}

你可能感兴趣的:(游戏中的数学公式)