Безье работает неправильно

Я пытаюсь внедрить простую кривую Безье в свою игру Unity, но, похоже, это не работает. вот скриншот того, как рисуется:

введите здесь описание изображения

4 зеленые сферы — это опорные точки Безье, а белые сферы — фактически вычисляемые Безье. Как видите, это как-то неправильно.

Вот мой код Безье (я взял его с форумов Unity):

using UnityEngine;

[System.Serializable]
public class Bezier : System.Object
{

    public Vector3 p0;
    public Vector3 p1;
    public Vector3 p2;
    public Vector3 p3;

    public float ti = 0f;

    private Vector3 b0 = Vector3.zero;
    private Vector3 b1 = Vector3.zero;
    private Vector3 b2 = Vector3.zero;
    private Vector3 b3 = Vector3.zero;

    private float Ax;
    private float Ay;
    private float Az;

    private float Bx;
    private float By;
    private float Bz;

    private float Cx;
    private float Cy;
    private float Cz;

    // Init function v0 = 1st point, v1 = handle of the 1st point , v2 = handle of the 2nd point, v3 = 2nd point
    // handle1 = v0 + v1
    // handle2 = v3 + v2
    public Bezier( Vector3 v0, Vector3 v1, Vector3 v2, Vector3 v3 )
    {
        this.p0 = v0;
        this.p1 = v1;
        this.p2 = v2;
        this.p3 = v3;
    }

    // 0.0 >= t <= 1.0
    public Vector3 GetPointAtTime( float t )
    {
        this.CheckConstant();
        float t2 = t * t;
        float t3 = t * t * t;
        float x = this.Ax * t3 + this.Bx * t2 + this.Cx * t + p0.x;
        float y = this.Ay * t3 + this.By * t2 + this.Cy * t + p0.y;
        float z = this.Az * t3 + this.Bz * t2 + this.Cz * t + p0.z;
        return new Vector3( x, y, z );

    }

    private void SetConstant()
    {
        this.Cx = 3f * ( ( this.p0.x + this.p1.x ) - this.p0.x );
        this.Bx = 3f * ( ( this.p3.x + this.p2.x ) - ( this.p0.x + this.p1.x ) ) - this.Cx;
        this.Ax = this.p3.x - this.p0.x - this.Cx - this.Bx;

        this.Cy = 3f * ( ( this.p0.y + this.p1.y ) - this.p0.y );
        this.By = 3f * ( ( this.p3.y + this.p2.y ) - ( this.p0.y + this.p1.y ) ) - this.Cy;
        this.Ay = this.p3.y - this.p0.y - this.Cy - this.By;

        this.Cz = 3f * ( ( this.p0.z + this.p1.z ) - this.p0.z );
        this.Bz = 3f * ( ( this.p3.z + this.p2.z ) - ( this.p0.z + this.p1.z ) ) - this.Cz;
        this.Az = this.p3.z - this.p0.z - this.Cz - this.Bz;

    }

    // Check if p0, p1, p2 or p3 have changed
    private void CheckConstant()
    {
        if( this.p0 != this.b0 || this.p1 != this.b1 || this.p2 != this.b2 || this.p3 != this.b3 )
        {
            this.SetConstant();
            this.b0 = this.p0;
            this.b1 = this.p1;
            this.b2 = this.p2;
            this.b3 = this.p3;
        }
    }
}

А вот мой скрипт реализации (он находится на пустом игровом объекте в сцене):

public class arrowPath : MonoBehaviour {
    public Transform[] pontos=new Transform[4];
    public Bezier bezier;

    // Use this for initialization
    void Start () {
    }

    // Update is called once per frame
    void Update () {
        bezier=new Bezier(pontos[0].position, pontos[1].position, pontos[2].position, pontos[3].position);

        for(float u= 0.0f; u<=1.0f; u+=0.05f)
        {
            Graphics.DrawMesh(pontos[0].GetComponent<MeshFilter>().sharedMesh, bezier.GetPointAtTime(u), Quaternion.Euler(Vector3.zero), pontos[0].renderer.sharedMaterial, 0);
        }
    }
}

Массив «pontos» — это массив Transform для сохранения сфер. Я заполняю его через инспектор Unity.

Я ценю любую помощь.

Спасибо.


person markus    schedule 21.08.2014    source источник


Ответы (1)


Очень похоже, что GetPointAtTime предназначен для генерации точки Безье. Если это так, вы вообще не оцениваете правильную функцию: для кубического Безье функция:

a ‧ t³ + 3 ‧ b ‧ t² ‧ (1-t) + 3 ‧ c ‧ t ‧ (1-t)² + d ‧ (1-t)³

Таким образом, ваш код не использует биномы, он просто использует прямой полином t, который будет генерировать действительно неправильные вещи =)

Итак, изменив свою функцию:

public float ComputeBezierValue( float t, float a, float b, float c, float d )
{
    float t2 = t * t,
          t3 = t2 * t,
          mt = 1 - t,
          mt2 = mt * mt,
          mt3 = mt2 * mt;
    return a * t3 + 3 * b * t2 * mt + 3 * c * t * mt2 + d * mt3;
}

public Vector3 GetPointAtTime( float t )
{
    this.CheckConstant();
    float x = ComputeBezierValue(t, this.Ax, this.Bx, this.Cx, this.Dx);
    float y = ComputeBezierValue(t, this.Ay, this.By, this.Cy, this.Dy);
    float z = ComputeBezierValue(t, this.Az, this.Bz, this.Cz, this.Dz);
    return new Vector3( x, y, z );
}

Также обратите внимание, что я написал это, чтобы явно использовать четыре координаты. Для кубических кривых Безье нужны все четыре, для квадратичных кривых используются только три (но, как правило, они очень плохи для представления равномерно изогнутых сегментов, таких как круговые/эллиптические сегменты, а также синоиды)

person Mike 'Pomax' Kamermans    schedule 21.08.2014