Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Generating a ground plane for a collection of gameobjects

Discussion in 'World Building' started by ProtagonistKun, May 25, 2019.

  1. ProtagonistKun

    ProtagonistKun

    Joined:
    Nov 26, 2015
    Posts:
    352
    Hello,

    I am trying to create a plane based on a collection of passed gameobjects but I have run into an issue that I am not sure how to fix. I am trying to draw a plane that connects all the corners of a building (between 4-10 or so)

    When I tried this code with 4 vertices it worked pretty well, although the face was flipped.
    When I tried with 6 this crashed my editor... No idea why.

    Image of an example of what I would like to fill in. The question is how to connect the gameobject (pivot) to make sure the correct order is done and the elements are drawn correctly.
    upload_2019-5-25_18-5-30.png

    upload_2019-5-25_18-8-5.png

    The shapes I provide here are an example, I am hoping to achieve an effect that will allow any shape to be filled in.

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. using UnityEngine.ProBuilder;
    4.  
    5. public static class CreateFloor
    6. {
    7.     private static ProBuilderMesh ground;
    8.  
    9.     public static void CreateGround(List<GameObject> points)
    10.     {
    11.         if(ground) Object.DestroyImmediate(ground.gameObject);
    12.  
    13.         var vertices = GetPositions(points);
    14.         List<Face> faces = new List<Face>();
    15.  
    16.         for (var index = 0; index < vertices.Count; index += 4)
    17.         {
    18.             faces.AddFace(index, index + 1, index + 2);
    19.             faces.AddFace(index + 2, index + 1, index + 3);
    20.         }
    21.  
    22.         ground =  ProBuilderMesh.Create(GetPositions(points), faces);
    23.     }
    24.  
    25.     private static List<Vector3> GetPositions(List<GameObject> list)
    26.     {
    27.         List<Vector3> l = new List<Vector3>();
    28.         foreach (var o in list)
    29.         {
    30.             l.Add(o.transform.position);
    31.         }
    32.  
    33.         return l;
    34.     }
    35.  
    36.     private static void AddFace(this List<Face> list, int a, int b, int c)
    37.     {
    38.         list.Add(new Face(new[] {a, b, c}));
    39.     }
    40. }
     
  2. Ritchie-J

    Ritchie-J

    Joined:
    Feb 26, 2018
    Posts:
    26
    Easiest way is to use ‘CreateShapeFromPolygon’
    In Unity’s documentation it’s under ‘UnityEngine.ProBuilder.MeshOperations > AppendElements’
    Code (CSharp):
    1. // Add this namespace
    2. using UnityEngine.ProBuilder.MeshOperations;
    3. . . .
    4. . . .
    5. List<Vector3> points;
    6. float thickness = 0; // Or something larger
    7. . . .
    8. . . .
    9. ProBuilderMesh mesh = ProBuilderMesh.Create();
    10. mesh.CreateShapeFromPolygon(points, thickness, false);
    11. MeshRenderer meshRend = mesh.GetComponent<MeshRenderer>();
    12. meshRend.material = yourMaterial;
     
    Last edited: May 25, 2019
    ProtagonistKun likes this.
  3. ProtagonistKun

    ProtagonistKun

    Joined:
    Nov 26, 2015
    Posts:
    352
    Thanks for the response, that seems like a step in the right direction.
    However passing in the data returns a mesh that is empty...
    No faces are created but there is an empty gameobject in the scene.

    upload_2019-5-26_0-24-17.png upload_2019-5-26_0-31-55.png

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. using UnityEngine.ProBuilder;
    4. using UnityEngine.ProBuilder.MeshOperations;
    5.  
    6. public static class CreateFloor
    7. {
    8.     private static ProBuilderMesh ground;
    9.  
    10.     public static void CreateGround(List<GameObject> points)
    11.     {
    12.         if (ground)
    13.         {
    14.             Object.DestroyImmediate(ground.gameObject);
    15.         }
    16.  
    17.         var vertices = GetPositions(points);
    18.  
    19.         ground = ProBuilderMesh.Create();
    20.         ground.CreateShapeFromPolygon(vertices, 0, false);
    21.         ground.GetComponent<MeshRenderer>().material = AssetDatabase.GetBuiltinExtraResource<Material>("Default-Diffuse.mat");
    22.     }
    23.  
    24.     private static List<Vector3> GetPositions(List<GameObject> list)
    25.     {
    26.         List<Vector3> l = new List<Vector3>();
    27.         foreach (var o in list)
    28.         {
    29.             l.Add(o.transform.position);
    30.         }
    31.  
    32.         return l;
    33.     }
    34.  
    35.     private static void AddFace(this List<Face> list, int a, int b, int c)
    36.     {
    37.         list.Add(new Face(new[] {a, b, c}));
    38.     }
    39. }
     
    Last edited: May 25, 2019
  4. Ritchie-J

    Ritchie-J

    Joined:
    Feb 26, 2018
    Posts:
    26
    Your updated code with ‘CreateShapeFromPolygon’ worked for me.
    I called ‘CreateGround’ with a List of 10 GameObjects in the correct perimeter sequence.
    Only line I had to add was a ‘using UnityEditor;’ so that the ‘AssetDatabase’ was recognised.

    Suggest you sketch out the path of your points list sequence – there seem to be a number of intersecting lines
     
  5. ProtagonistKun

    ProtagonistKun

    Joined:
    Nov 26, 2015
    Posts:
    352
    Yeah ok, the generation was failing cuz of the shape I was using for the ground (the 2nd image).
    But its still not as it should be... Using the same code and points are provided clockwise starting from lower left.
    Ignore the planes not being connected to the actual corners, its just the gameobjects pivot isnt exactly right.

    upload_2019-5-26_11-9-12.png
     
  6. Ritchie-J

    Ritchie-J

    Joined:
    Feb 26, 2018
    Posts:
    26
    Suggest you double-check the points ordering sequence in your List.
    Looks like an adjacent pair need to be swapped.
     
  7. ProtagonistKun

    ProtagonistKun

    Joined:
    Nov 26, 2015
    Posts:
    352
    Ok that makes sense, however I would like to find a way to make the vertices sort themselves in the list so it does it correctly based on the vertices.

    Edit: The order I get from the scene isnt always the same and as such isnt always correct. I have no idea on how I can get that fixed though.
     
  8. Ritchie-J

    Ritchie-J

    Joined:
    Feb 26, 2018
    Posts:
    26
    Given your current set of 6 points:-
    I can see at least 5 different ways of creating ‘correct’ and valid PolyShapes from them without any lines intersecting.

    You need to revise your design strategy rather than ‘throwing’ points at code.
     
    Kurt-Dekker likes this.
  9. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,514
    Or if you insist on throwing points, you can also pre-group the points into square-ish things like rooms, and you might have greater overall success.
     
    ProtagonistKun likes this.