Create Bezier Path

I have to create a path with Bezier curves. The problem is that I can only get the results on the first 3 waypoints. How can I implement the algorithm to use multiple points?

  public void DrawLine()
    {
      
            for (int point = 0;  point < path.Length; point++)
            {
                if (point == 0)
             {
positions[point] = Bezier(0, path[point].position, path[point + 1].position, path[point + 2].position, path[point + 3].position);

               }
                    for (int i = 1; i <= 80; i++)
                     {
                     tt = (i / (float)numPoinr);
                      positions[i] = Bezier(node, path[point].position, path[point + 1].position, path[point + 2].position, path[point + 3].position);
                      inst = Instantiate(node, positions[i], Quaternion.identity) as GameObject;
                      
                    } 
              
            }
      
    }

    private Vector3 Bezier(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3)
    {
        float u = 1 - t;
        float tt = t * t;
        float uu = u * u;
        float uuu = uu + u;
        float ttt = tt * t;
        Vector3 p = uuu * p0;
        p += 3 * uu * t * p1;
        p += 3 * u * tt * p2;
        p += ttt * p3;
        return p;
      
    }

On line 15 you call the bezier function but i dont think your parameters are correct, you should be passing tt instead of node as first param?

you might also need to make your point loop shorter, path[point + 3] will be invalid once the point loop gets to path.length

I was relying on this design. In theory I should use recursion but in this case I would not know how to do it

3143123--238552--ricorsione.png

in that case you need to step your loop by 3 each time, because p1 and p2 are just control points, and you dont want to actually visit them in the loop

also i just notcies you are instantiating your node in the sub loop, 80 times per point, this is probably wrong depending on how you are drawing the line

if you are using linerenderer you should only need one gameobject, and you assign the calculated bezier positions to it

I’m not using the line renderer I’m using small spheres. This is a trial file after I will use Bezier only for the movements. I was interested in seeing the various instances

Ah thats ok then
So its “tt” intead of “node” on line 15, and “point+=3” on line 5
also check “numPoinr” on line 14 (numPoint?)

I was able to trace Bezier curves, the problem is that if I wanted to use it to make a path does not work well. The player skips the first loop. Can you tell me why? Written so does not seem good to me but is the only solution I have found

private void Update()
    {

        //don't work
        for (int point = 0;  point < path.Length - 2; point +=2)
            {
               

                curr += Time.deltaTime;
                perc = curr / 50f;
                tr.transform.position = Bezier(perc, path[point].position, path[point + 1].position, path[point + 2].position);
                Debug.Log(point);   
            }
    }

Because of the mathematical complexity it takes to calculate the binomial coefficients for an increasing number of points. its usually cheaper if you subdivide a long bezier into a group of 3-5 point beziers and stitch them together. but if you really want a high point count…

        public int BinomialCoefficient(int size, int choose)
        {
            int result = 1;
            // use symmetry to reduce calculations
            if (choose > size - 1 - choose)
            {
                choose = size - 1 - choose;
            }

            for (int i = 1; i <= choose; i++,size--)
            {
                if (result / i > Int16.MaxValue)
                    return 0; //result overflowed, so we lost the value

                result = result / i * (size-1) + result % i; // divide before multiply to better avoid reaching overflow
            }

            return result;
        }

        public Vector3 Bezier(Vector3[] points, float lerp)
        {
            Vector3 point = Vector3.zero;

            if (points == null) 
            {
                return point;
            }

            lerp = Mathf.Clamp01(lerp);
            float inverseLerp = 1 - lerp;

            for (int i = 0; i < points.Length; i++) 
            {
                //this is were the function can get expensive
                float coef = BinomialCoefficient (points.Length, i);
                float power = Mathf.Pow (lerp, i);
                float inversePower = Mathf.Pow (inverseLerp, points.Length - i-1);

                if(power < float.Epsilon)  power = 0;
                if(inversePower< float.Epsilon)  inversePower = 0;

                Vector3 weightedPosition = points [i] * coef * power * inversePower;

                point += weightedPosition;
            }

            return point;
        }

however if you do subdivide them, to ensure a smooth transition you simply need to make the last 2 points of bezier A be Colinear with the 1st two points of bezier B (meaning all four of those points run along the same line and in order), and then have the last point of Bezier A and the 1st point of Bezier B have the same position

You’re looping incorrectly and also incrementing the curr value by the deltaTime several times per frame. actually I’m not quite certain what you’re trying to do there as its all redundant in the end.

if you’re trying to animate something flying along the path you need to perform it differently (this is using the code I provided)

public float lerp = 0f;
public float travelDuration = 3f;
public Tranform target;
public Vector3[] path;

private void Update()
{
    if(!target) return;

    lerp  = (travelDuration > float.Epsilon)
        ? lerp + Time.deltaTime / travelDuration
        :1;

    lerp = Mathf.Clamp(lerp,0,1) ;

    target.position = Bezier(path,lerp);
}

This code will make tr.transform visit all points on the curve at the same time in a single frame.
You need to spread out the movement across multiple frames.
Either use a coroutine and yield in the loop, or don’t use a loop at all, stepping the value only once per frame

Thanks for your answer. I was violent asking you: how did you say the code? I would never have been so

Thanks for your answer. I had also thought of using the coroutiner but wanted to avoid it if I had to implement the algorithm in another graphical engine