Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

ProBuilder Extruding along a line programmatically

Discussion in 'World Building' started by Skaltum, Aug 11, 2019.

  1. Skaltum

    Skaltum

    Joined:
    Nov 1, 2013
    Posts:
    4
    I'm trying to create a script that will extrude a face along a path but I can't quite get there.
    I don't know how I can get the indices of the vertices I created using extrude.

    This is what I currently have:


    What I want is a full ring without the holes.

    This is my code:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using UnityEngine;
    5. using UnityEngine.ProBuilder;
    6. using UnityEngine.ProBuilder.MeshOperations;
    7.  
    8. public class ProbuilderProceduralWall : MonoBehaviour
    9. {
    10.     public int radius = 10;
    11.     public int iterations = 20;
    12.     public bool FlipNormals = false;
    13.     [SerializeField]
    14.     List<Vector2> _face = new List<Vector2>();
    15.     [SerializeField]
    16.     Vector3[] _path = new Vector3[0];
    17.  
    18.     void OnDrawGizmos()
    19.     {
    20.         for (int i = 0; i < _face.Count - 1; i++)
    21.         {
    22.             Debug.DrawLine(_face[i], _face[i + 1]);
    23.         }
    24.         for (int i = 0; i < _path.Length - 1; i++)
    25.         {
    26.             Debug.DrawLine(_path[i], _path[i + 1]);
    27.         }
    28.     }
    29.     void Start()
    30.     {
    31.         if (_path.Length == 0) _path = MakePath(iterations, radius);
    32.         if (_face.Count == 0) _face = new List<Vector2>() { new Vector2(-0.5f, 0), new Vector2(-0.25f, .5f), new Vector2(0, 1), new Vector2(0.25f, 0.5f), new Vector2(0.5f, 0) };
    33.         Do();
    34.     }
    35.     void OnGUI()
    36.     {
    37.         if (GUILayout.Button("Make path"))
    38.         {
    39.             _path = MakePath(iterations, radius);
    40.         }
    41.  
    42.         if (GUILayout.Button("Do"))
    43.         {
    44.             Do();
    45.         }
    46.     }
    47.  
    48.     static Vector3[] MakePath(int iterations, float radius)
    49.     {
    50.         var path = new Vector3[iterations];
    51.         for (var i = 0; i < iterations; i++)
    52.         {
    53.             path[i] = new Vector3(Mathf.Sin((1f / iterations * Mathf.PI * 2) * i) * radius, 0, Mathf.Cos((1f / iterations * Mathf.PI * 2) * i) * radius);
    54.         }
    55.         return path;
    56.     }
    57.  
    58.     void Do()
    59.     {
    60.         var min = _face.Aggregate(new Vector2(Mathf.Infinity, Mathf.Infinity), (agg, p) => Vector2.Min(agg, p));
    61.         var max = _face.Aggregate(new Vector2(Mathf.NegativeInfinity, Mathf.NegativeInfinity), (agg, p) => Vector2.Max(agg, p));
    62.  
    63.         var mesh = ProBuilderMesh.Create();
    64.         var facePoints = new List<Vector3>(_face.Select(p => (Vector3)p));
    65.         facePoints.Sort((a, b) => a.x.CompareTo(b.x));
    66.         facePoints.Insert(0, new Vector3(min.x, min.y - 1));
    67.         facePoints.Add(new Vector3(max.x, min.y - 1));
    68.         mesh.CreateShapeFromPolygon(facePoints, 0, FlipNormals);
    69.         var instance = GameObject.Instantiate(mesh.gameObject);
    70.         var instanceMesh = instance.GetComponent<ProBuilderMesh>();
    71.  
    72.  
    73.         instanceMesh.transform.position = _path[0];
    74.         var toModel = instanceMesh.transform.worldToLocalMatrix;
    75.         var face = instanceMesh.faces.Last();
    76.         var faces = new[] { face };
    77.  
    78.         for (int i = 0; i < _path.Length - 1; i++)
    79.         {
    80.             var start = _path[i];
    81.             var middle = _path[i + 1];
    82.             var end = i + 2 < _path.Length ? _path[i + 2] : _path[i + 1];
    83.  
    84.             var createdFaces = instanceMesh.Extrude(faces, ExtrudeMethod.FaceNormal, 1);
    85.  
    86.             var positions = new List<Vector3>(instanceMesh.positions);
    87.             var dir = ((middle - start).normalized + (end - middle).normalized);
    88.             var rotation = Quaternion.LookRotation(dir, Vector3.up);
    89.             var toWorld = Matrix4x4.TRS(middle, rotation, Vector3.one);
    90.             Debug.DrawRay(middle, dir.normalized, Color.magenta, 30.0f);
    91.          
    92.             foreach (var index in face.distinctIndexes)
    93.             {
    94.                 positions[index] = toModel.MultiplyPoint3x4(toWorld.MultiplyPoint3x4(facePoints[index]));
    95.                 Debug.DrawRay(positions[index], Vector3.up * 0.1f, Color.red, 30.0f);
    96.             }
    97.             instanceMesh.positions = positions;          
    98.         }
    99.  
    100.         instanceMesh.ToMesh();
    101.         instanceMesh.Refresh();
    102.         instanceMesh.name = $"{name}";
    103.         instanceMesh.GetComponentInChildren<Renderer>().sharedMaterial = BuiltinMaterials.defaultMaterial;
    104.         Destroy(mesh.gameObject);
    105.         Debug.Log("Created mesh", instanceMesh);
    106.     }
    107.  
    108. }
    109.