以下代码中 using M = GameHelper.Math.Mathf; 为自定义类 可以替换为你们自己实现这些公式的类
1. Cubic Hermite interpolation remainder:
(Unity animation curve interpolation algorithm, d1, d2, respectively, the slope)
Document: https://blog.csdn.net/luolei188/article/details/86563231
achieved:
(Note to avoid t1 == t2, otherwise there will be problems infinity)
/// <summary>
/// 三次Hermite插值余项
/// </summary>
/// <param name="t">需求时间</param>
/// <param name="t1">时间1</param>
/// <param name="t2">时间2</param>
/// <param name="v1">时间1上的值</param>
/// <param name="v2">时间2上的值</param>
/// <param name="d1">倒数1</param>
/// <param name="d2">倒数2</param>
/// <returns></returns>
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的入斜率
Test code:
(final results)
//可以通过修改 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. Bezier:
(curve drawing method commonly used in the game, for example, (Handles.DrawBezier))
Document: https://blog.csdn.net/xiaozhangcsdn/article/details/98963937
a Bezier curve:
/// <summary>
/// 一次贝塞尔曲线
/// </summary>
/// <param name="t">时间(0,1)</param>
/// <param name="s">起点</param>
/// <param name="e">终点</param>
/// <returns></returns>
public static float MathfOneBezier(float t, float s, float e)
{
return (1 - t) * s + t * e;
}
/// <summary>
/// 一次贝塞尔曲线
/// </summary>
/// <param name="t">比例值(0,1)</param>
/// <param name="s">起点</param>
/// <param name="e">终点</param>
/// <returns></returns>
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;
}
Quadratic Bezier curve:
/// <summary>
/// 二次贝塞尔曲线
/// </summary>
/// <param name="t">时间(0,1)</param>
/// <param name="s">起点</param>
/// <param name="e">终点</param>
/// <param name="c">控制点</param>
/// <returns></returns>
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;
}
/// <summary>
/// 二次贝塞尔曲线
/// </summary>
/// <param name="t">时间(0,1)</param>
/// <param name="s">起点</param>
/// <param name="e">终点</param>
/// <param name="c">控制点</param>
/// <returns></returns>
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;
}
Cubic Bezier curves:
/// <summary>
/// 三次贝塞尔曲线
/// </summary>
/// <param name="t">时间(0,1)</param>
/// <param name="s">起点</param>
/// <param name="e">终点</param>
/// <param name="sc">起点控制点</param>
/// <param name="ec">终点控制点</param>
/// <returns></returns>
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;
}
/// <summary>
/// 三次贝塞尔曲线
/// </summary>
/// <param name="t">时间(0,1)</param>
/// <param name="s">起点</param>
/// <param name="e">终点</param>
/// <param name="sc">起点控制点</param>
/// <param name="ec">终点控制点</param>
/// <returns></returns>
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;
}
Bezier test code included:
(final results)
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;
}
}