What is the best way to evenly distribute objects to fill a curved space in Unity 3D?

2.8k Views Asked by At

I would like to fill this auditorium seating area with chairs (in the editor) and have them all face the same focal point (the stage). I will then be randomly filling the chairs with different people (during runtime). After each run the chairs should stay the same, but the people should be cleared so that during the next run the crowd looks different.

The seating area does not currently have a collider attached to it, and neither do the chairs or people.

enter image description here

I found this code which has taken care of rotating the chairs so they target the same focal point. But I'm still curious if there are any better methods to do this.

//C# Example (LookAtPoint.cs)
using UnityEngine;
[ExecuteInEditMode]
public class LookAtPoint : MonoBehaviour
{
    public Vector3 lookAtPoint = Vector3.zero;

    void Update()
    {
        transform.LookAt(lookAtPoint);
    }
}

Additional Screenshots

enter image description here

enter image description here

enter image description here

1

There are 1 best solutions below

6
zwcloud On

You can write a editor script to automatically place them evenly. In this script,

I don't handle world and local/model space in following code. Remember to do it when you need to.

  1. Generate parallel rays that come from +y to -y in a grid. The patch size of this grid depends on how big you chair and the mesh(curved space) is. To get a proper patch size. Get the bounding box of a chair(A) and the curved space mesh(B), and then devide them(B/A) and use the result as the patch size.

    Mesh chairMR;//Mesh of the chair
    Mesh audiMR;//Mesh of the auditorium
    var patchSizeX = audiMR.bounds.size.X;
    var patchSizeZ = audiMR.bounds.size.Z;
    var countX = audiMR.bounds.size.x / chairMR.bounds.size.x;
    var countZ = audiMR.bounds.size.z / chairMR.bounds.size.z;
    

    So the number of rays you need to generate is about countX*countZ. Patch size is (patchSizeX, patchSizeZ).

    Then, origin points of the rays can be determined:

    //Generate parallel rays that come form +y to -y.
    List<Ray> rays = new List<Ray>(countX*countZ);
    for(var i=0; i<countX; ++i)
    {
        var x = audiMR.bounds.min.x + i * sizeX + tolerance /*add some tolerance so the placed chairs not intersect each other when rotate them towards the stage*/;
        for(var i=0; i<countZ; ++i)
        {
            var z = audiMR.bounds.min.z + i * sizeZ + tolerance;
            var ray = new Ray(new Vector3(x, 10000, z), Vector3.down);
            //You can also call `Physics.Raycast` here too.
        }
    }
    
  2. Get postions to place chairs.

    1. attach a MeshCollider to your mesh temporarily
    2. foreach ray, Physics.Raycast it (you can place some obstacles on places that will not have a chair placed. Set special layer for those obstacles.)
    3. get hit point and create a chair at the hit point and rotate it towards the stage
  3. Reuse these hit points to place your people at runtime.

    Convert each of them into a model/local space point. And save them into json or asset via serialization for later use at runtime: place people randomly.