天天看點

遊戲程式設計精粹學習 - 路徑/線段平滑

來自《遊戲程式設計精粹1》尋路部分文章,使用CatmullRom插值來達到平滑,算是對書中内容的練習。

在尋路上經常會用到此功能。

遊戲程式設計精粹學習 - 路徑/線段平滑

using UnityEngine;
using System.Collections;

public class Practice : MonoBehaviour
{
    public Transform[] points;


    void OnDrawGizmos()
    {
        //DrawSegmentPath();
        DrawSmoothPath();
    }

    void DrawSegmentPath()
    {
        for (int i = 1, j = 0; i < points.Length; i++, j++)
        {
            var a = points[i];
            var b = points[j];

            Gizmos.DrawLine(a.position, b.position);
        }
    }

    void DrawSmoothPath()
    {
        for (int i = 3; i < points.Length; i++)
        {
            var a = points[i - 3];
            var b = points[i - 2];
            var c = points[i - 1];
            var d = points[i];

            DrawCurve(a.position, b.position, c.position, d.position);
        }

        var fixA = points[0];
        var fixB = points[1];
        var fixC = points[2];
        var diff = fixB.position - fixA.position;
        var fill = fixA.position + diff.normalized * diff.magnitude;
        DrawCurve(fill, fixA.position, fixB.position, fixC.position);

        fixA = points[points.Length - 3];
        fixB = points[points.Length - 2];
        fixC = points[points.Length - 1];
        diff = fixC.position - fixB.position;
        fill = fixC.position + diff.normalized * diff.magnitude;
        DrawCurve(fixA.position, fixB.position, fixC.position, fill);
    }

    void DrawCurve(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3)
    {
        for (float i = 1, j = 0, iMax = 20f; i <= iMax; i++, j++)
        {
            var t1 = i / iMax;
            var t2 = j / iMax;

            var tempP0 = CatmullRom(p0, p1, p2, p3, t1);
            var tempP1 = CatmullRom(p0, p1, p2, p3, t2);

            Gizmos.DrawLine(tempP0, tempP1);
        }
    }

    Vector3 CatmullRom(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float u)
    {
        var r = p0 * (-0.5f * u * u * u + u * u - 0.5f * u) +
                p1 * (1.5f * u * u * u + -2.5f * u * u + 1f) +
                p2 * (-1.5f * u * u * u + 2f * u * u + 0.5f * u) +
                p3 * (0.5f * u * u * u - 0.5f * u * u);

        return r;
    }
}