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

Question How to instantiate multiple entities from a prefab during Bake() in a Baker ?

Discussion in 'Entity Component System' started by XRA, Apr 16, 2023.

  1. XRA

    XRA

    Joined:
    Aug 26, 2010
    Posts:
    265
    Imagine you have a Grid baker that should populate various prefabs when adjusted, these all need to be entities. It needs to be reactive in scene view.

    How would you go about doing this using the Baker class? there is no way to make use of
    RenderMeshUtility.AddComponents and the other RenderMeshUtility methods are internal.

    Would an ISystem using [WorldSystemFilter(WorldSystemFilterFlags.BakingSystem)] be the correct approach?

    How do you get around the duplicate entity guids from instantiating the prefabs when baking?
     
  2. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,983
    Call GetEntity() on each unique tile prefab, and then store the returned entity references in your grid in a DynamicBuffer. Then at runtime instantiate those entities.
     
  3. XRA

    XRA

    Joined:
    Aug 26, 2010
    Posts:
    265
    thanks for the reply, I'm trying to do it in edit mode, because I want to see the results while editing.
    I've changed my approach to use a BakingSystem but now the entities only render when the SubScene is closed.
    When the SubScene is open, I can see that the entities and components are created, but they don't render which is odd.

    here is the general idea with the Grid authoring,

    I use GridCell to designate which entities created by the baker need to be operated on further in the baking system (because I cannot access RenderMeshUtility.AddComponents in a Baker)

    Code (CSharp):
    1. [TemporaryBakingType]
    2. public struct GridCell : IComponentData
    3. {
    4.     public float3 Value;
    5.     public UnityObjectRef<Mesh> mesh;
    6.     public UnityObjectRef<Material> material;
    7. }
    8.  
    9. public class GridAuthoringBaker : Baker<GridAuthoring>
    10. {
    11.     public override void Bake(GridAuthoring authoring)
    12.     {
    13.         var aabb = authoring.aabb;
    14.  
    15.         var entity = GetEntity(authoring, TransformUsageFlags.WorldSpace);
    16.         // was trying to pass this in.. but cannot instantiate during Baking due to duplicate GUID issue
    17.         //var cellPrefab = GetEntity(authoring.prefab, TransformUsageFlags.Renderable);
    18.      
    19.         var grid = new Grid { aabb = aabb, dimension = (int3)(aabb.Max - aabb.Min) };
    20.         AddComponent(entity, grid );
    21.  
    22.         // create baking entities... ????
    23.         for (int i = 0; i < grid.Length; i++)
    24.         {
    25.             var e = CreateAdditionalEntity(TransformUsageFlags.WorldSpace, false, $"{authoring.name}_{i.ToString()}");
    26.          
    27.             var pos = Util.ConvertIndexToWorldPosition(i, grid.dimension, grid.aabb);
    28.          
    29.             Debug.DrawRay(pos,Vector3.up,Color.cyan,1f);
    30.          
    31.             AddComponent(e, new GridCell { Value = pos, mesh = authoring.mesh, material = authoring.material});
    32.         }
    33.      
    34.     }
    35. }
    And here is the baking system:

    Code (CSharp):
    1. [WorldSystemFilter(WorldSystemFilterFlags.BakingSystem)]
    2. public partial struct GridBakeSystem : ISystem
    3. {
    4.     private EntityQuery _gridCellQuery;
    5.  
    6.     public void OnCreate(ref SystemState state)
    7.     {
    8.         _gridCellQuery = new EntityQueryBuilder(Allocator.Temp)
    9.             .WithAll<GridCell>()
    10.             .WithOptions(EntityQueryOptions.IncludePrefab | EntityQueryOptions.IncludeDisabledEntities)
    11.             .Build(ref state);
    12.     }
    13.  
    14.     [BurstCompile]
    15.     public void OnUpdate(ref SystemState state)
    16.     {
    17.         var cells = _gridCellQuery.ToComponentDataArray<GridCell>(Allocator.TempJob);
    18.         var entities = _gridCellQuery.ToEntityArray(Allocator.TempJob);
    19.      
    20.         for (var i = 0; i < cells.Length; i++)
    21.         {
    22.             var entity = entities[i];
    23.             //var entity = state.EntityManager.CreateEntity();
    24.             var cell = cells[i];
    25.          
    26.             var desc = new RenderMeshDescription(shadowCastingMode: ShadowCastingMode.Off, receiveShadows: false);
    27.             var renderMeshArray = new RenderMeshArray(new [] { cell.material.Value }, new [] { cell.mesh.Value });
    28.          
    29.             RenderMeshUtility.AddComponents(
    30.                 entity,
    31.                 state.EntityManager,
    32.                 desc,
    33.                 renderMeshArray,
    34.                 MaterialMeshInfo.FromRenderMeshArrayIndices(0, 0));
    35.      
    36.             state.EntityManager.AddComponentData(entity, new LocalToWorld{Value = float4x4.TRS(cell.Value,quaternion.identity,new float3(1f,1f,1f) * Util.CELL_RADIUS)});
    37.             state.EntityManager.AddComponentData(entity, new CellInfluence{delta = 1f,value = 0f});
    38.             state.EntityManager.AddBuffer<CellNeighbors>(entity);
    39.             state.EntityManager.AddBuffer<PropagationValue>(entity);
    40.         }
    41.      
    42.         entities.Dispose(state.Dependency);
    43.         cells.Dispose(state.Dependency);
    44.     }
    45. }
     
  4. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,983
    I think really what you want is a system that does the procedural spawning in the Editor World. You can make a runtime system run in the Editor World via WorldSystemFilter attribute.