3

私が解決しようとしている問題は、一定の速度で 3 次ベジエ曲線に沿って 2D ポイントを移動できないように見えることです。

私はこのチュートリアルに従いました: http://catlikecoding.com/unity/tutorials/curves-and-splines/最初に曲線を実装すると、素晴らしく機能しました。しかし、一定の速度でポイントを近似しようとすると、かなり外れます。

私がこれまでに読んだことから、各ステップ時間で弧の長さと間隔の距離を計算して、曲線を反復処理することになっています。次に、これらの距離を目標距離 (弧の長さ * 時間) と比較して、最も近い距離を見つけます。解像度が十分に高い場合、これはエラーがほとんどなく、私のニーズに対して十分に正確であるはずです。

これが私がこれまでに持っているコードです:

ポイント計算:

public static Vector3 GetPoint (Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) 
{
    t = Mathf.Clamp01(t);
    float oneMinusT = 1f - t;
    return
        oneMinusT * oneMinusT * oneMinusT * p0 +
            3f * oneMinusT * oneMinusT * t * p1 +
            3f * oneMinusT * t * t * p2 +
            t * t * t * p3;
}

一定時間でポイントを計算するという悲しい試み:

private float GetApproximatedTime(float u)
{
    int resolution = 100;
    float ratio = 1.0f / resolution;
    float arcLength = 0.0f;
    Vector3 p0 = SelectedSpline.Evaluate(0.0f);
    List<MultiCurveUtility.ArcTimeLength> arcTimeLengthMap = new List<MultiCurveUtility.ArcTimeLength>();
    arcTimeLengthMap.Add(new MultiCurveUtility.ArcTimeLength(0.0f, 0.0f));

    for (int i = 1; i <= resolution; i++)
    {
        float t = ((float)i) * ratio;
        Vector3 p1 = SelectedSpline.Evaluate(t);
        arcLength += Vector3.Distance(p0, p1);
        arcTimeLengthMap.Add(new MultiCurveUtility.ArcTimeLength(t, arcLength));
        p0 = p1;
    }

    float target = u * arcLength;
    int low = 0;
    int high = 1;
    float min = 0.0f;
    float max = 0.0f;

    for (int i = 1; i < arcTimeLengthMap.Count; i++)
    {
        max = arcTimeLengthMap[i].ArcLength;
        if (target > min && target < max) 
        {
            high = i;
            low = i - 1;
            break; 
        }

        min = max;
    }

    float p = (target - min) / (max - min);
    float lowTime = arcTimeLengthMap[low].ArcTime;
    float highTime = arcTimeLengthMap[high].ArcTime;
    float lowHighDelta = highTime - lowTime;
    return arcTimeLengthMap[low].ArcTime + (lowHighDelta * p);
}

上記のコードでは、x 軸の一定速度での移動を表す 3 次ベジエ曲線上のポイントを評価するために使用できる時間を返すために、0 と 1 の間の time(u) を渡しています。

結果は次のとおりです 。Cubic Bezier Image

赤い点は、ベジェ式で元の時間を評価するだけで返される通常のポイントを表します。黄色の点は、近似された時間が経過した後の「一定の」速度位置を表します。接線をかなり誇張するように変更し始めるまでは、かなり正確に見えます。間隔を広げてみましたが、何の役にも立ちません。

とにかく、どんな助けも素晴らしいでしょう。私はまだ数式を読むのが得意ではありません (問題の原因は確かです)。そのため、コード例を使用してヘルプを得ることができれば幸いです。:>

ありがとう!

4

2 に答える 2

-4

わかりました、私は自分で答えを見つけたようです。

TLDR; 2D 曲線の場合、弧の長さを使用してターゲット距離を計算しないでください。水平 (x 軸) の長さのみを使用します。

簡単なメモ: 曲線が x 軸に沿って逆方向に進む可能性がある場合、この解決策はおそらくうまくいきません。私はしません。

詳しく説明すると、目標距離 (曲線上のどこを見ているべきかを概算するために使用される値) は、時間と弧の長さの積でした。円弧の長さは、y 軸の距離を考慮しているため、不正確でした。水平方向の動きしか気にしないので、y 距離は不要でした。

これが私の更新されたコードです:

private float GetApproximatedTime(float u)
{
int resolution = 25 * SelectedSpline.CurveCount; // Factor in additional curves.
float ratio = 1.0f / resolution;
float arcLength = 0.0f;
Vector3 p0 = SelectedSpline.Evaluate(0.0f);
List<MultiCurveUtility.ArcTimeLength> arcTimeLengthMap = new List<MultiCurveUtility.ArcTimeLength>();
arcTimeLengthMap.Add(new MultiCurveUtility.ArcTimeLength(0.0f, 0.0f));

for (int i = 1; i <= resolution; i++)
{
    float t = ((float)i) * ratio;
    Vector3 p1 = SelectedSpline.Evaluate(t);
    arcLength += Mathf.Abs(p1.x - p0.x); // Only use the x-axis delta.
    arcTimeLengthMap.Add(new MultiCurveUtility.ArcTimeLength(t, arcLength));
    p0 = p1;
}

float target = u * arcLength;
int low = 0;
int high = 1;
float min = 0.0f;
float max = 0.0f;

for (int i = 1; i < arcTimeLengthMap.Count; i++)
{
    max = arcTimeLengthMap[i].ArcLength;
    if (target > min && target < max) 
    {
        high = i;
        low = i - 1;
        break; 
    }

    min = max;
}

float p = (target - min) / (max - min);
float lowTime = arcTimeLengthMap[low].ArcTime;
float highTime = arcTimeLengthMap[high].ArcTime;
float lowHighDelta = highTime - lowTime;
return arcTimeLengthMap[low].ArcTime + (lowHighDelta * p);
}

ここには 2 つの重要な変更点があることに注意してください。

arcLength += Mathf.Abs(p1.x - p0.x);

int resolution = 25 * SelectedSpline.CurveCount;

2 番目の変更は、曲線が追加されたときに解像度が低下しないようにすることです。そうしないと、返される時間の精度に誤差が生じる場合があります。曲線ごとに 25 の間隔が非常に正確で非常に高速であることがわかりました。とはいえ、このコードにはいくつかの明確な最適化が行われていますが、これも理解できない場合は、うまくいくはずです。

これが結果のスクリーンショットです。黄色の点は、新しい時間を使用して評価するポイントです。緑色の点は、私の最高点と最低点を表しています。

IMAGE - 結果のグラフ - 3 次ベジエ曲線上の一定時間

于 2015-11-15T18:52:29.617 に答える