- Home /
[ECS] Set data to a SharedComponent of Type RenderMesh from EntityCommandBuffer
Hello there,
i currently try to create a Cube while in a Job. This Cube is an entity and needs a RenderMesh component to be able to get rendered.
Problem here is the following. While i can add a MeshRender component i am not able to actually feed the needed data (Mesh, Material) in the component to get it to render. Only Entities that i created in the main thread are rendered. If i use the EntityCommandBuffer to create an entity in a job the sharedComponent RenderMesh has no data. (Which kind of makes sense) I tried feeding the Mesh/Material data directly to the job to set it there but since reference type variables are not allowed in jobs this is not possible.
Does anyone here have insight on this? If you need more info on the current setup let me know.
Cheers
I know this is old, but I have the same problem. Still looking for a solution
Answer by andrew-lukasik · Sep 28, 2020 at 04:10 PM
Entities Version 0.14.0-preview.19 - September 10, 2020
One answer to this is instantiating from pre-defined pool of entity prefabs and not touching reference types after that at all. This system below, for example, will destroy & instantiate 1000 mesh entities every frame < 1ms (Burst enabled) while sourcing prefab entities from world entities (differentiated by id/hash calculated as "specific string name id".GetHashcode()
).
Note: filter_prefabs_job
can be removed once you figure out a way to create a persistent NativeArray<Entity> prefabs
, NativeHashMap<int,Entity> prefabs_lookup
or even just a single valid Entity prefab
for this system to use.
PrefabPoolTestSystem.cs
using Debug = UnityEngine.Debug;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;
using Unity.Rendering;
using Random = Unity.Mathematics.Random;
public class PrefabPoolTestSystem : SystemBase
{
int _poolId = "grey capsule".GetHashCode();
protected override void OnCreate ()
{
Debug.Log($"{GetType().Name} will be looking for {nameof(EntityMeshPrefab)} hash: '{_poolId}'");
}
protected override void OnUpdate ()
{
var ecb = new EntityCommandBuffer( Allocator.TempJob );
var ecbpw = ecb.AsParallelWriter();
Entities
.WithName("delete_existing_instances_job")
.WithNone<Prefab>()// do not delete prefabs
.WithAll<EntityMeshPrefab>()
.ForEach( ( in int entityInQueryIndex , in Entity entity ) =>
{
ecbpw.DestroyEntity( entityInQueryIndex , entity );
} )
.WithBurst().ScheduleParallel();
NativeList<Entity> prefabs = new NativeList<Entity>( 100 , Allocator.TempJob );
NativeList<Entity>.ParallelWriter prefabs_writer = prefabs.AsParallelWriter();
int poolId = _poolId;
Entities
.WithName("filter_prefabs_job")
.WithAll<Prefab>()
.ForEach( ( in int entityInQueryIndex , in Entity entity , in EntityMeshPrefab entityMeshPrefab ) =>
{
if( entityMeshPrefab.id==poolId )
prefabs_writer.AddNoResize( entity );
} )
.WithBurst().ScheduleParallel();
uint seed = (uint) math.pow(Time.ElapsedTime+1,2).GetHashCode();
Job
.WithName("instantiate_job")
.WithReadOnly( prefabs )
.WithCode( () =>
{
int numPrefabs = prefabs.Length;
if( numPrefabs!=0 )
{
var rnd = new Random( seed );
for( int i=0 ; i<1000 ; i++ )
{
Entity prefab = prefabs[ rnd.NextInt(0,numPrefabs) ];
ecb.Instantiate( prefab );
ecb.SetComponent( prefab , new Translation{
Value = rnd.NextFloat3( new float3{ x=-10 , y=-10 , z=-10 } , new float3{ x=10 , y=10 , z=10 } )
} );
}
}
} )
.WithBurst().Schedule();
Job
.WithName("disposal_job")
.WithCode( () =>
{
prefabs.Dispose();
})
.WithoutBurst().Run();
Job
.WithName("playback_commands")
.WithCode( () =>
{
ecb.Playback( EntityManager );
ecb.Dispose();
})
.WithoutBurst().Run();
}
}
EntityMeshPrefab.cs
using Unity.Entities;
public struct EntityMeshPrefab : IComponentData
{
public int id;
}
This component allows you to create entity prefabs from scene gameobjects in, so called, hybrid approach (GameObject to Entity workflow):
EntityMeshPrefabComponent.cs
using UnityEngine;
using Unity.Entities;
[DisallowMultipleComponent]
[RequireComponent( typeof(MeshFilter) , typeof(MeshRenderer) )]
[RequiresEntityConversion]
public class EntityMeshPrefabComponent : MonoBehaviour, IConvertGameObjectToEntity
{
[SerializeField] string _id = "grey capsule";
void IConvertGameObjectToEntity.Convert ( Entity entity , EntityManager dstManager , GameObjectConversionSystem conversionSystem )
{
dstManager.AddComponent<Prefab>( entity );
int hash = _id.GetHashCode();
dstManager.AddComponentData<EntityMeshPrefab>( entity , new EntityMeshPrefab{
id = hash
} );
Debug.Log($"{name} created an {nameof(EntityMeshPrefab)} with id '{hash}'");
}
}