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 Loading an entity prefab into any scene.

Discussion in 'Entity Component System' started by Mockarutan, Jan 15, 2023.

  1. Mockarutan

    Mockarutan

    Joined:
    May 22, 2011
    Posts:
    158
    In ECS 1.0. I must be missing something here, is there a way to get pre baked entitles that you can dynamically instantiate into any loaded scene that you happen to be in? From my research it looks like the bake system only triggers from sub scenes? So it seems to me that I have to load a scene with a sub sene inside to then get access to the bake system inside a mono behavior inside that sub scene? And you cannot make a sub scene outside of a scene so I need to make a unique sub scene in every scene I want to access my prefabs in?

    The concept of a scene is totally irrelevant to my game, everything is procedurally generated on the fly, I and just want some way to get a big inventory of all my entity prefabs so I can start the generation code and build my level.

    There must be something I'm missing? Are we completely tied into manual sub scene creations for every ECS based level?
     
  2. muntes

    muntes

    Joined:
    Nov 24, 2021
    Posts:
    16
    @Mockarutan

    Hi, I'm in the exact same case as you are. Previously this was possible in older versions of ECS.
    Currently, I'm having multiple assets downloaded from the network and the scene being put together without any other sub-scene.

    I managed to get all the data inside the ECS but not on the actual scene.
    First, you need an Archetype for your data in order to let ECS know what you will put in the memory.

    Code (CSharp):
    1. private static readonly EntityArchetype ItemArchetype = World.DefaultGameObjectInjectionWorld.EntityManager.CreateArchetype(
    2.     typeof(LocalToParentTransform),
    3.     typeof(LocalToWorld),
    4.     typeof(GameObjectParent),
    5.     typeof(RenderMesh),
    6.     typeof(MeshLODComponent));
    Using an EntityArchetype, you can instantiate

    Code (CSharp):
    1. var itemEntities = new NativeArray<Entity>(entitiesCount, Allocator.Persistent, NativeArrayOptions.ClearMemory);
    2. World.DefaultGameObjectInjectionWorld.EntityManager.CreateEntity(ItemArchetype, itemEntities);
    3.  
    After you have them into the memory, you can fill them in:

    Code (CSharp):
    1.          
    2.             var entityPositionIndex = 0;
    3.             foreach (var data in renderData)
    4.             {
    5.                 var meshRenderer = new RenderMesh
    6.                 {
    7.                     material = data.Material,
    8.                     mesh = data.Mesh,
    9.                     subMesh = data.SubmeshIndex
    10.                 };
    11.  
    12.                 foreach (var localMatrix in data.Matrices)
    13.                 {
    14.                     var itemEntity = itemEntities[entityPositionIndex];
    15.                     SetupEntities(worldMatrix, itemEntity, id, localMatrix, parent, ref meshRenderer, 1);
    16.                     entityPositionIndex++;
    17.                 }
    18.             }
    So the data is sent from MonoBehaviour to ECS. You could see them in the hierarchy but not on the screen.
    This is where I blocked. If anyone has any suggestions please fill in the gaps.
     

    Attached Files:

    • 1.png
      1.png
      File size:
      253.4 KB
      Views:
      73
  3. bb8_1

    bb8_1

    Joined:
    Jan 20, 2019
    Posts:
    98
    If this is question about procedural generation in 1.0 - in that case for me works RenderMeshArray and RenderMeshDescription which i first fill with data after that i use RenderMeshUtility.AddComponents and after code above execute entity is visible (my ring world or halo entity) - though this is done from SystemBase class
     
    Last edited: Jan 16, 2023
  4. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,653
    In 1.0 RenderMesh using ONLY for baking, at runtime, as suggested above, RenderMeshArray RenderMeshDescription should be used instead.
     
    bb8_1 and muntes like this.
  5. muntes

    muntes

    Joined:
    Nov 24, 2021
    Posts:
    16
    I also tried with RenderMeshUtility, and even the sample doesn't seem to work alright.
    https://docs.unity3d.com/Packages/c...phics@1.0/manual/runtime-entity-creation.html

    Code (CSharp):
    1. using Unity.Collections;
    2. using Unity.Entities;
    3. using Unity.Jobs;
    4. using Unity.Mathematics;
    5. using Unity.Rendering;
    6. using Unity.Transforms;
    7. using UnityEngine;
    8. using UnityEngine.Rendering;
    9.  
    10. public class AddComponentsExample : MonoBehaviour
    11. {
    12.     public Material Material;
    13.     public int EntityCount;
    14.  
    15.     // Example Burst job that creates many entities
    16.     [GenerateTestsForBurstCompatibility]
    17.     public struct SpawnJob : IJobParallelFor
    18.     {
    19.         public Entity Prototype;
    20.         public int EntityCount;
    21.         public EntityCommandBuffer.ParallelWriter Ecb;
    22.  
    23.         public void Execute(int index)
    24.         {
    25.             // Clone the Prototype entity to create a new entity.
    26.             var e = Ecb.Instantiate(index, Prototype);
    27.             // Prototype has all correct components up front, can use SetComponent to
    28.             // set values unique to the newly created entity, such as the transform.
    29.             Ecb.SetComponent(index, e, new LocalToWorld {Value = ComputeTransform(index)});
    30.         }
    31.  
    32.         public float4x4 ComputeTransform(int index)
    33.         {
    34.             return float4x4.Translate(new float3(index, 0, 0));
    35.         }
    36.     }
    37.  
    38.     private Mesh CreateCube () {
    39.         Vector3[] vertices = {
    40.             new Vector3 (0, 0, 0),
    41.             new Vector3 (1, 0, 0),
    42.             new Vector3 (1, 1, 0),
    43.             new Vector3 (0, 1, 0),
    44.             new Vector3 (0, 1, 1),
    45.             new Vector3 (1, 1, 1),
    46.             new Vector3 (1, 0, 1),
    47.             new Vector3 (0, 0, 1),
    48.         };
    49.  
    50.         int[] triangles = {
    51.             0, 2, 1, //front
    52.             0, 3, 2,
    53.             2, 3, 4, //top
    54.             2, 4, 5,
    55.             1, 2, 5, //right
    56.             1, 5, 6,
    57.             0, 7, 4, //left
    58.             0, 4, 3,
    59.             5, 4, 7, //back
    60.             5, 7, 6,
    61.             0, 6, 7, //bot
    62.             0, 1, 6
    63.         };
    64.  
    65.         var mesh = new Mesh {vertices = vertices, triangles = triangles};
    66.         mesh.Optimize ();
    67.         mesh.RecalculateNormals ();
    68.         return mesh;
    69.     }
    70.  
    71.     void Start()
    72.     {
    73.         var world = World.DefaultGameObjectInjectionWorld;
    74.         var entityManager = world.EntityManager;
    75.  
    76.         EntityCommandBuffer ecb = new EntityCommandBuffer(Allocator.TempJob);
    77.  
    78.         // Create a RenderMeshDescription using the convenience constructor
    79.         // with named parameters.
    80.         var desc = new RenderMeshDescription(
    81.             shadowCastingMode: ShadowCastingMode.Off,
    82.             receiveShadows: false);
    83.  
    84.         // Create an array of mesh and material required for runtime rendering.
    85.         var renderMeshArray = new RenderMeshArray(new Material[] {Material}, new Mesh[] {CreateCube()});
    86.  
    87.         // Create empty base entity
    88.         var prototype = entityManager.CreateEntity();
    89.  
    90.         // Call AddComponents to populate base entity with the components required
    91.         // by Entities Graphics
    92.         RenderMeshUtility.AddComponents(
    93.             prototype,
    94.             entityManager,
    95.             desc,
    96.             renderMeshArray,
    97.             MaterialMeshInfo.FromRenderMeshArrayIndices(0, 0));
    98.         entityManager.AddComponentData(prototype, new LocalToWorld());
    99.  
    100.         // Spawn most of the entities in a Burst job by cloning a pre-created prototype entity,
    101.         // which can be either a Prefab or an entity created at run time like in this sample.
    102.         // This is the fastest and most efficient way to create entities at run time.
    103.         var spawnJob = new SpawnJob
    104.         {
    105.             Prototype = prototype,
    106.             Ecb = ecb.AsParallelWriter(),
    107.             EntityCount = EntityCount,
    108.         };
    109.  
    110.         var spawnHandle = spawnJob.Schedule(EntityCount, 128);
    111.         spawnHandle.Complete();
    112.  
    113.         ecb.Playback(entityManager);
    114.         ecb.Dispose();
    115.         entityManager.DestroyEntity(prototype);
    116.     }
    117. }
    In theory, this piece of code should render me as many cubes as asked by the Inspector, but this doesn't happen.
    Even with a SubScene and the principal object inside it instead of using a single scene.

    What am I missing here? The Mesh/Material is alright inside of the Render Mesh Array but still not in the scene.
     

    Attached Files:

    Last edited: Jan 16, 2023
  6. bb8_1

    bb8_1

    Joined:
    Jan 20, 2019
    Posts:
    98
    Did you maybe miss to add some components that entity should have like(can't see it in code above) : typeof(LocalToWorld), typeof(RenderMesh), typeof(RenderBounds), typeof(LocalTransform)
    i think this ^^^ is minimum required for entity with mesh to be visible(though not sure for LocalToWorld but at least this works in my case)?
     
  7. muntes

    muntes

    Joined:
    Nov 24, 2021
    Posts:
    16
    On the sample provided in the documentation
    Code (CSharp):
    1.  new LocalToWorld {Value = ComputeTransform(index)});
    this was used to set it, so it should work, I guess?
     
  8. TieSKey

    TieSKey

    Joined:
    Apr 14, 2011
    Posts:
    219
    Check that the scale and render bounds of the entities are set to something not 0 (which is the default). Check the render mask to, it is a mask so set it to int.MaxValue if u don't use the feature. (I think the default for this value is not 0 as the others).

    As for the original question, "entity prefabs" don't exist, I don't really understand why.... prefabs is the "unity way", I don't get why they went an introduced such a weird concept as "sub-scene" instead of making a custom prefab type for entities (with baking and all the things a sub-scene does, but in a prefab).

    Previous to 1 you could load a gameobject prefab and convert it but that use case was deprecated. Suck to be us T_T
     
    Last edited: Jan 16, 2023
    defic and muntes like this.
  9. bb8_1

    bb8_1

    Joined:
    Jan 20, 2019
    Posts:
    98
    Here is my very simple code that actually creates simple triangle(my first try in 1.0 procedural generation in order to create 25km radius ring world :) ). You need to add
    1. bool meshCreated ; // as field of SB class
    2. material RWMaterial into Resources folder
    3. code is in SystemBase class
    4. some things can be done better for example use simple c# arrays instead of List in RenderMeshArray etc
    5. You can put this code in protected override void OnUpdate() method of SystemBase

    In 1.0 this works in my case :
    Code (CSharp):
    1. if (!meshCreated)
    2.         {
    3.             var em = EntityManager;
    4.             var ea = em.CreateArchetype(
    5.                 typeof(LocalToWorld),
    6.                 typeof(RenderMesh),
    7.                 typeof(RenderBounds),
    8.                 typeof(LocalTransform)
    9.             );
    10.             var entity = em.CreateEntity(ea);
    11.             em.SetComponentData(entity, new LocalTransform { Position = Vector3.zero, Rotation = quaternion.identity,
    12.             Scale = 1});
    13.             em.SetName(entity, new FixedString64Bytes("RING-WORLD"));
    14.  
    15.             Mesh mesh = new Mesh();
    16.             mesh.MarkDynamic();
    17.  
    18.             var vertices = new NativeArray<float3>(3, Allocator.Persistent);
    19.             vertices[0] = new float3(0, 0, 100);
    20.             vertices[1] = new float3(100, 0, 100);
    21.             vertices[0] = new float3(0, 100, 100);
    22.             mesh.SetVertices(vertices);
    23.  
    24.             var normals = new NativeArray<float3>(3, Allocator.Persistent);
    25.             normals[0] = normals[1] = normals[2] = new float3(0, 0, -1);
    26.             mesh.SetNormals(normals);
    27.  
    28.             var triangles = new NativeArray<int>(3, Allocator.Persistent);
    29.             for(int i=0; i<3; i++)
    30.             {
    31.                 triangles[i] = i;
    32.             }
    33.             mesh.triangles = triangles.ToArray();
    34.  
    35.             var uvs = new NativeArray<float2>(3, Allocator.Persistent);
    36.             uvs[0] = new float2(0, 0);
    37.             uvs[1] = new float2(0, 1);
    38.             uvs[2] = new float2(1, 0);
    39.             mesh.SetUVs(0, uvs);
    40.  
    41.             var genMeshMaterial = Resources.Load("RWMaterial", typeof(Material)) as Material;
    42.             if(genMeshMaterial == null)
    43.             {
    44.                 Debug.Log("RWMaterial not found");
    45.                 return;
    46.             }
    47.  
    48.             var desc = new RenderMeshDescription(ShadowCastingMode.Off,
    49.                 receiveShadows: false);
    50.  
    51.             var renderMeshArray = new RenderMeshArray(
    52.                 (new List<Material> { genMeshMaterial }).ToArray(),
    53.                 (new List<Mesh> { mesh }).ToArray()
    54.             );
    55.  
    56.             RenderMeshUtility.AddComponents(
    57.                 entity,
    58.                 em,
    59.                 desc,
    60.                 renderMeshArray,
    61.                 MaterialMeshInfo.FromRenderMeshArrayIndices(0, 0)
    62.             );
    63.  
    64.             //Debug.Log("after RenderMeshUtility");
    65.  
    66.             meshCreated = true;
    67.         }
    68.  
     
    Last edited: Jan 16, 2023
  10. muntes

    muntes

    Joined:
    Nov 24, 2021
    Posts:
    16
    Thank you very much, guys. The piece from above wasn't compiled due to entities being 15 and graphics being 12 versions of 1.0.0, even if I had them set as 15/15 in the manifest.json. So I started a new project in which I reimported com.unity.entities.graphics 1.0.0-pre.15 again, and that didn't work either. I've removed from the cache unity all packages (AppData\Local\Unity\cache\packages), cleared the library folder for the project with the script from above, and retried the project. It seems to be fixed it somehow.
    I had multiple versions of ECS, the project being on 0.1 and porting from that version to 0.51 and then to 1.0.0.

    Also, another important thing is to use URP or HDRP, of course, for Entities Graphics. We never mentioned this in the topic, but this can be another reason why nothing is happening, you will not get any error/message if you call Entities Graphics functionalities from a built-in pipeline.
     
    bb8_1 likes this.
  11. Mockarutan

    Mockarutan

    Joined:
    May 22, 2011
    Posts:
    158
    This use case is not to create the entity manually and then fill it in.
    I generate a lot of simpler manual entities in runtime and use them right away.
    Problem is that I want to be able to predefine and prebake prefabs that I can use anywhere.
    I am fully aware that creating physics objects or rendering objects in ECS from scratch is a bit of a mess that you should probably avoid, so I want the pre baked prefabs.

    The issue is getting access to the ECS prefabs in any scene and instantiate them into my own World in editor or in runtime, both are required for my use case. I've messed with the sub scene thing now for a few hours and I'm getting more and more convinced that it's just not possible to do what I want.

    With the sub scenes it seems like they are trying to make the conversion stage transparant to the "user". But I need to bake my GameObjects on command through my generation code in the editor, or have them prebaked in the build. Or I guess I could do if the magic transparent bake system would actually bake the GameObject and give me an Entity I could use straight away in the editor. But that seems to not be intended at all. Just bake a premade scene.
     
    defic likes this.
  12. muntes

    muntes

    Joined:
    Nov 24, 2021
    Posts:
    16
  13. Mockarutan

    Mockarutan

    Joined:
    May 22, 2011
    Posts:
    158
    It's not about graphics, and it's not really about creating an entity prefab. I want to use the bake system to prebake (or bake on the fly when i create a new prop) all my GameObject prefabs into Entity prefabs and use them in any scene with my level generator. Instantiate in editor (not in play) and in runtime. But I don't think the new bake system can do that. I think I will have to stay on 0.51 until something more flexible arrives.
     
    Last edited: Jan 16, 2023
  14. TieSKey

    TieSKey

    Joined:
    Apr 14, 2011
    Posts:
    219
    Like I wrote in a previous message, that use case got deprecated in 1.0 so yes, you should stick with .50 if that works for u.
    Baking is editor only and sub-scene only.
    There is the promise of an "entities addressables" , soon... (unity version of soon...)
     
    muntes and bb8_1 like this.
  15. LuisEGV

    LuisEGV

    Joined:
    Jul 21, 2015
    Posts:
    36
    This is extremely important and yet I've seen zero info about it from the Unity team, just the "Entities Addressables coming soon" with no obligation. I hope we don't end up having to recreate the runtime conversion system just to be able to use the latest Entities versions
     
  16. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,653
    There is wouldn't be addressables for entities, there is Content Management and Content Archives developed (and continues) specifically for entity prefabs and subscenes loading from the network\disc\etc.
     
    LuisEGV likes this.
  17. LuisEGV

    LuisEGV

    Joined:
    Jul 21, 2015
    Posts:
    36
    You're right. Thank you
     
  18. TieSKey

    TieSKey

    Joined:
    Apr 14, 2011
    Posts:
    219
    Where did u get that info? a couple months ago some Unity staff said they were working in entities addressables.
    Did they change direction already? :S
     
  19. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,653
    muntes likes this.
  20. alexchisholm343

    alexchisholm343

    Joined:
    Feb 7, 2021
    Posts:
    1
    I feel your pain man, I'm trying so hard to be able to just bake all my entities at runtime so I can spawn them into world I create on the fly whenever I want, seems to be made as hard as possible. Did you ever get it working?