generating endless bezier curve

i am making an endless driving game and i want to generate an endless curved road as my car moves forward
i have been following this tutorial online: http://blog.nick.je/endless-procedural-curved-mesh-generation-in-unity-part-2/

however it is incomplete, and instead of showing how to generate new curves as the player moves forward it only show hot to generate a set amount of curves at the start of the game. i have tried to expand upon the code regardless but what i have so far doesn’t really work. 4uqb5i

as you can see by the past curves doesnt stay consistent as the player moves forward.

here is my code so far:

using UnityEngine;
using System.Collections.Generic;

public class TerrainGeneratorEndless : MonoBehaviour
{
    Mesh mesh;
    public static float Seed = 144765346f;

    // This becomes a list of curves
    List<Vector3[]> curves = new List<Vector3[]> ();
    List<Vector3> vertices = new List<Vector3> ();
    List<int> triangles = new List<int> ();
    List<Vector3> ponts = new List<Vector3> ();
    float xPos;
    float pos;
    private int lastZIndex = -10000;
    float spos;
    public float depth;

    MeshFilter filter;
    Vector3[] curve;
    int zIndex;

    public Transform player;
    void Start ()
    {
        filter = GetComponent<MeshFilter> ();
        mesh = filter.mesh;
        mesh.Clear ();

        xPos = 0f;
        // For simplicity generate 10 curves
        generate(5, true);
    }

    private void Update()
    {
        SpawnTiles();
    }

    private void SpawnTiles()
    {
        Vector3 playerPos = player.position;
        playerPos.z -= depth;

        zIndex = (int)(playerPos.z / depth);
        float lastX = 0;

        //Enable here for the optimization
        if (lastZIndex == zIndex)
        {
            return;//On previour frame I have already changed all time positions for player's position
                   //I do not have to change the positions again because they are exactly same
        }
        lastZIndex = zIndex;
        filter = GetComponent<MeshFilter>();
        mesh = filter.mesh;
        mesh.Clear();

        //Array.Clear(positions, 0, positions.Length);
        generate(5, true);
      

        //BezierPath bezierPath = new BezierPath(positions, false, PathSpace.xyz);
        //GetComponent<PathCreator>().bezierPath = bezierPath;
        //Array.Clear(positions, 0, positions.Length);
    }

    //VertexPath GeneratePath(Vector3[] points, bool closedPath)
    //{
    //    print("yo");
    //    // Create a closed, 2D bezier path from the supplied points array
    //    // These points are treated as anchors, which the path will pass through
    //    // The control points for the path will be generated automatically
    //    BezierPath bezierPath = new BezierPath(points, closedPath, PathSpace.xyz);
    //    // Then create a vertex path from the bezier path, to be used for movement etc
    //    return new VertexPath(bezierPath, test);
    //}

    //void check(int i)
    //{
    //    if (forbiddenPoints.Contains(pos))
    //    {
    //        pos += depth;
    //        check(i);
    //    }
    //    else
    //    {
    //        curve[i] = new Vector3(n1(pos) * 20, /*n1(pos )*5*/ 0, (spos));
    //        GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube);
    //        go.transform.position = curve[i];
    //    }
    //}


    float n1(float z)
    {
        z += Seed;
        z = Mathf.Abs(z);
        return (Mathf.Sin(((z * 123124.2435345f) % 1f)) * 42353245.3245634f) % 1.0f;
    }
    float n2(float z)
    {
        z += Seed;
        z = Mathf.Abs(z);

        return (Mathf.Sin(((z / 123124.2435345f) % 1.2f)) * 65656.346346f) % 1.0f;
    }
    float n3(float z)
    {
        // random.init(z)
        // random.range
        z += Seed;
        z = Mathf.Abs(z);
        return (Mathf.Cos(((z * 36456.346346f) % 2.5f)) * 34634.35765f) % 1.0f;
    }





    void generate(int amount, bool begin)
    {
        mesh.Clear();
        pos = zIndex * depth;
        spos = 0;
        for (int c = 0; c < amount; c++) {
            curve = new Vector3[4];
            //xPos = 0;
            //xPos = (c * depth);
            //xPos += (zIndex) * depth;
            for (int i = 0; i < curve.Length; i++) {
               
                Vector3[] prev = null;
                if (curves.Count > 0) {
                    prev = curves [curves.Count - 1];
                }
                if (prev != null && i == 0) {
                    // Start of a new curve
                    // Set to the last point of the previous
                    curve [i] = prev [curve.Length - 1];
                } else if (prev != null && i == 1) {
                    // First control point of a new curve
                    // Use the end of the previous curve to calculate
                    curve [i] = 2f * prev [curve.Length - 1] - prev [curve.Length - 2];
                } else {
                    curve[i] = new Vector3(n1(pos) * 20, /*n1(pos )*5*/ 0, (pos));
                }
                print(pos);
                pos += depth;
            }
            curves.Add (curve);
           
        }

    //https://www.graphicfilth.com/2014/10/3d-bezier-curves-in-unity/
    //https://www.bitshiftprogrammer.com/2018/01/altos-adventure-style-procedural.html
        // Same drawing code as before but now in a loop
        if (begin)
        {
            foreach (var curve in curves)
            {
                int resolution = 20;
                for (int i = 0; i < resolution; i++)
                {
                    float t = (float)i / (float)(resolution - 1);
                    Vector3 p = CalculateBezierPoint(t, curve[0], curve[1], curve[2], curve[3]);
                    AddTerrainPoint(p);
                    ponts.Add(p);
                    //
                }
            }
        }
        else
        {
            int resolution = 20;
            for (int i = 0; i < resolution; i++)
            {
                float t = (float)i / (float)(resolution - 1);
                Vector3 p = CalculateBezierPoint(t, curve[0], curve[1], curve[2], curve[3]);
                AddTerrainPoint(p);
                ponts.Add(p);
                ////
            }

        }
        mesh.vertices = vertices.ToArray();
        mesh.triangles = triangles.ToArray();
        RoadCreator.Instace.UpdateRoad(ponts);
        ponts.Clear();
        curves.Clear();
    }

    void AddTerrainPoint (Vector3 point)
    {
        // Create a corresponding point along the bottom
        //vertices.Add (new Vector3 (point.x, 0f, 0f)); // Then add our top point
        vertices.Add (point);

        if (vertices.Count >= 4) {
            // Completed a new quad, create 2 triangles
            int start = vertices.Count - 4;
            triangles.Add (start + 0);
            triangles.Add (start + 1);
            triangles.Add (start + 2);
            triangles.Add (start + 1);
            triangles.Add (start + 3);
            triangles.Add (start + 2);
        }
    }

    private Vector3 CalculateBezierPoint (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;
    }
}

//https://gist.github.com/Jakintosh/76b500ed47cc8c8b27e3

bump

You can use a generator (aka “coroutine”) in order to produce an endless stream of curve data.

Here’s a simple example that produces an endless stream of Vector3 positions in space.

It moves an object gradually towards the current destination, and when it gets close it chooses a new one.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// make a sphere, stick this on it, put it in front of the camera, watch it go

public class PathMaker : MonoBehaviour
{
    IEnumerator<Vector3> Maker;

    // produces an endless stream of coordinates
    IEnumerator<Vector3> Generator()
    {
        while(true)
        {
            Vector3 pos = Random.onUnitSphere;
            pos *= Random.Range( 1.0f, 5.0f);
            yield return pos;
        }
    }

    void Start()
    {
        Maker = Generator();

        Maker.MoveNext();
        Destination = Maker.Current;
    }

    Vector3 Destination;

    void Update ()
    {
        // see how close we are
        float distance = Vector3.Distance( Destination, transform.position);

        // when we get close to destination, get a new destination
        if (distance < 0.25f)
        {
            Maker.MoveNext();
            Destination = Maker.Current;
        }

        // I'm using Lerp to make it more squishy smooth... you can
        // produce your next destination however you like...
        transform.position = Vector3.Lerp( transform.position, Destination, Time.deltaTime);
    }
}
1 Like

i think your trying to show me when to generate curves. the problem is i already have a script that knows when to generate curves, its just that when i generate them they aren’t consistent, they don’t properly connect with each other.

Probably because your control points are not on the same line as curve ending.