Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Fabricating mesh for procedural path/spline

Discussion in 'Scripting' started by Sendatsu_Yoshimitsu, Jun 13, 2019.

  1. Sendatsu_Yoshimitsu

    Sendatsu_Yoshimitsu

    Joined:
    May 19, 2014
    Posts:
    691
    I'm working on building roads and footpaths for my thing, my system currently generates both an array of points to be connected (which I can link with a spline), and a list of segments, where each segment contains a start and end point.

    What I'm struggling with is how I should go about generating the actual road mesh. It seems like there are two possible approaches;

    1) Build the actual mesh in code, generate the UVs from the spline, and texture it with something that tiles well, or
    2) Handmake a short, modular section of road as a prefab, scale one prefab per section so its ends match the ends of that segment, and tinker with the prefab's materials so that they tile nicely without deforming.

    Option #2 is vastly preferable, since it's much easier to build a snazzy looking road/sidewalk/whatever in Blender than it is from code, but it has some pretty nasty drawbacks: one is that it wouldn't be able to handle curves well unless I build a system to rebuild the prefab's mesh in order to twist it, and the other is that it wouldn't be able to handle junctions- since any road can intersect any other road from any angle, I would need to do fairly enormous amounts of mesh editing at runtime just to make all the roads merge without z-fighting and looking weird.

    So is there a third option I'm missing? Given all of the drawbacks to #2 I'm thinking that the best path forward is to run with #1 and accept that there's going to be a ton of debugging and frustrating math tinkering to get the UVs, smoothing, and all that jazz looking acceptable.
     
  2. grizzly

    grizzly

    Joined:
    Dec 5, 2012
    Posts:
    356
    The procedural route (option #1) sounds like fun. See here;

     
  3. Sendatsu_Yoshimitsu

    Sendatsu_Yoshimitsu

    Joined:
    May 19, 2014
    Posts:
    691
    Thanks for the link! That's a great tutorial, I don't mean to turn this into a spline/procgen tech support extravaganza but if anyone has a bit, there are two somewhat fundamental questions I had after going through it:

    1) The method he showcases uses four points to define a spline, which implies that it can't curve multiple times- for generating road networks, is the implied use case to generate hundreds of road segments, each segment being one spline, then simply stitch nearby spline coordinates together when I generate the mesh (so I'm not rendering hundreds of objects)?

    2) When defining the curve's trajectory with four points, I find that it never actually touches the fourth vector- is that intended, or does it mean I fudged my math somewhere? For reference, I expected the following screenshot to look like a slightly lopsided rainbow but the left edge is nowhere close to touching p3:



    3) Lastly, I'm having trouble understanding how he's computing the V value of his UVs to make the curve tile correctly. My own implementation during the extrusion phase just calculates v as distance/length, but he went on this whole spiel about writing an extension method to sample t from an array of floats that I didn't follow- apparently I'm supposed to building a lookup table of floats somewhere, and interpolating along that to get my V value? For reference, here's how I'm currently getting it:
    Code (csharp):
    1.  
    2.         float totalLength = 0;
    3.         float distanceCovered = 0;
    4.  
    5.         for (int i = 0; i < path.Length - 1; i++)
    6.         {
    7.             var d = Vector3.Distance(path[i].position, path[i + 1].position);
    8.             totalLength += d;
    9.         }
    10.  
    11.         for (int i = 0; i < path.Length; i++)
    12.         {
    13.             int offset = i * vertsInShape;
    14.             if (i > 0)
    15.             {
    16.                 var d = Vector3.Distance(path[i].position, path[i - 1].position);
    17.                 distanceCovered += d;
    18.             }
    19.             float v = distanceCovered / totalLength;
    20.            
    21.             for (int j = 0; j < vertsInShape; j++)
    22.             {
    23.                 int id = offset + j;
    24.                 vertices[id] = path[i].LocalToWorld(shape.verts[j].point);
    25.                 normals[id] = path[i].LocalToWorldDirection(shape.verts[j].normal);
    26.                 uvs[id] = new Vector2(shape.verts[j].uCoord, v);
    27.             }
    28.         }
    29.  
     
  4. grizzly

    grizzly

    Joined:
    Dec 5, 2012
    Posts:
    356
    Although the video implies that splines are curves and curves are splines, technically speaking they are separate things. A curve is shown in your screenshot. Using four points (2 anchors P0 & P3 and two handles P1 & P2) it's a Cubic Bezier where as with three points (2 anchors & 1 handle) it's a Quadratic Bezier. A spline on the other hand is just the general term for a network of curves (regardless of what type of curve it is). Therefore a Cubic Bezier Spline is composed of 2 or more piecewise Cubic Bezier Curves.

    A road spline composed from two curves would be formed like this;

    C1. [P0, P1, P2, P3]
    C2. [P3, P4, P5, P6]

    So the last anchor from the first curve is the first anchor for the second curve. You don't have to build your mesh in chunks. Just walk through your curves and loop through T to build one big continuous mesh.
    No, that's not intended. A Bezier Curve should pass through its anchor points. Looking at the verts in your screenshot, it appears that you're not looping all the way to the end. Take an extra step of T to close the gap.
    He's using a lookup table for speed, I think. The speaker has implemented a realtime generator which works well for demonstration purposes, but since it sounds like you only need to generate the roads offline, you can ignore this step and just use the summation of your distance along the spline as you build it. You don't need the total length, only the distance, so just divide it by some arbitrary divisor (whatever looks right for your texture).
     
    gaolei_nls likes this.
  5. Sendatsu_Yoshimitsu

    Sendatsu_Yoshimitsu

    Joined:
    May 19, 2014
    Posts:
    691
    That's all super-duper helpful, thank you for taking the time to write clarifications. :)
     
  6. Lethn

    Lethn

    Joined:
    May 18, 2015
    Posts:
    1,583
    I know you got your answer but as it so happens I have been trying to research all of this as well and I came across some very detailed tutorials that might help you understand it even better.



    https://catlikecoding.com/unity/tutorials/curves-and-splines/

    The difference is I was wanting to use these methods to make an influence border that could dynamically expand and change during runtime.
     
  7. Sendatsu_Yoshimitsu

    Sendatsu_Yoshimitsu

    Joined:
    May 19, 2014
    Posts:
    691
    That link is great, thank you!! It's certainly not as technical as the Unity talk, but it was much easier to follow. :)
     
  8. Reahreic

    Reahreic

    Joined:
    Mar 23, 2011
    Posts:
    254
    His videos are really good, however i'm struggling to get my UV's to loop around my meshes cleanly as my shapes are generated in 2D and then lofted down the spline and not a simple 2 vertex wide flat plane.

    My textures are also specifically directional, so when it comes to forming a "closed" mesh i end up with at least one set of tri's that have verts at both 0 and 1 on the UV chart, and as such distort. The Sebastian Lague videos avoid this by reversing the UV's mid way which won't work for me. I need tiling along both u and v and not mirrored tiling on v.

    The closest i could get was to add a duplicate set of vert's where the end verts UV seam would normally be and keep them locked to the same position as the starting verts, but this seems wrong as the mesh isn't "water-tight" despite visually looking so, and contains a bunch of duplicate verts.

    I'm open to any suggestions.
     
  9. PLSMajesticUnity

    PLSMajesticUnity

    Joined:
    Aug 30, 2020
    Posts:
    10
    Me talking 1 week to copy a fps character controller from YouTube and debuging for 4 straight days and then coming here seeing all the nerds talking in here like it's nothing well I am impressed I would probably need 4 more years to write clean code like that.
     
    timmehhhhhhh likes this.
  10. KoolGamez

    KoolGamez

    Joined:
    Apr 11, 2020
    Posts:
    29
    How would one go about making a procedural generated curve like in endless games such as alto's adventure. It should also have gaps and what other protocols do we follow (using chunks, floating origin, etc)? Also, for this type of game, do we keep player in same position and just alter the curve or vice versa?