#How to create meshes at runtime?

1 messages · Page 1 of 1 (latest)

minor cedar
#

I have a basic "voxel engine" wich I'm now refactoring to use ECS.
I'm having trouble understanding how I can add meshes or modify them at runtime.

I tried an approach where I had a chunk prefab wich an authoring system that would bake the ChunkComponent and let Unity itself bake the MeshFilter, MeshRenderer and MeshCollider.
Then I wanted to modify these at runtime, but that doesn't seem to be possible.

I also tried not having a baker for my chunks at all, nor a prefab. I'm creating the entities at runtime and trying to a mesh at runtime with the values i'll calculate. However, that also doesn't seem possible.

What's the proper way for me to handle this?

brittle crescent
#

a quick old code i have that generates a single box and adds it to the subscene, good starting point for you
i basically use a managed component (you can use an unmanaged one with UnityObjectRef), register the material and mesh from the component i retrieve, and using batchid and materialid create a new mesh
if you have voxel terrain, you want to avoid creating mesh with rendermesharray and make it as burstable as possible which i am doing in newer version of my terrain gen

public void OnUpdate(ref SystemState state)
{
    state.Enabled = false;
    
    Entity managedPoolEntity = _entityQuery.GetSingletonEntity();
    MaterialMeshPoolComponent matMeshPool = _entityQuery.GetSingleton<MaterialMeshPoolComponent>();
    EntitiesGraphicsSystem egs = state.World.GetExistingSystemManaged<EntitiesGraphicsSystem>();
    
    // convert pointers to gpu handles
    NativeList<BatchMeshID> meshIDs = new(matMeshPool.TileMeshes.Length, Allocator.Temp);
    foreach (UnityObjectRef<Mesh> meshes in matMeshPool.TileMeshes) meshIDs.Add(egs.RegisterMesh(meshes));
    
    NativeList<  BatchMaterialID> matIDs = new(matMeshPool.TileMaterials.Length, Allocator.Temp);
    foreach (UnityObjectRef<Material> materials in matMeshPool.TileMaterials) matIDs.Add(egs.RegisterMaterial(materials));
    
    // build blob
    BlobBuilder builder = new BlobBuilder(Allocator.Temp);
    ref MaterialMeshPoolBlob root = ref builder.ConstructRoot<MaterialMeshPoolBlob>();
    
    builder.Construct(ref root.MeshIDs, meshIDs);
    builder.Construct(ref root.MaterialIDs, matIDs);
    
    BlobAssetReference<MaterialMeshPoolBlob> blobRef = builder.CreateBlobAssetReference<MaterialMeshPoolBlob>(Allocator.Persistent);
    MaterialMeshPoolSingleton materialMeshPoolSingleton = new() { Blob = blobRef };
    
    builder.Dispose();
    meshIDs.Dispose();
    matIDs.Dispose();
    
    Entity singleton = state.EntityManager.CreateEntity();
    
    state.EntityManager.SetName(singleton, "MaterialMeshPoolSingleton");
    state.EntityManager.AddComponentData(singleton, materialMeshPoolSingleton);
    
    SceneTag sceneTag   = state.EntityManager.GetSharedComponent<SceneTag>(managedPoolEntity);
    SceneSection sceneSect  = state.EntityManager.GetSharedComponent<SceneSection>(managedPoolEntity);
    
    Entity testEntity = state.EntityManager.CreateEntity();
    state.EntityManager.SetName(testEntity, "TestEntity");
    RenderMeshDescription rmd = new RenderMeshDescription
    {
        FilterSettings = RenderFilterSettings.Default
    };
    MaterialMeshInfo mmi = new MaterialMeshInfo(materialMeshPoolSingleton.Blob.Value.MaterialIDs[0],
                                                materialMeshPoolSingleton.Blob.Value.MeshIDs[0]);
    
    state.EntityManager.AddSharedComponent(testEntity, sceneTag);
    state.EntityManager.AddSharedComponent(testEntity, sceneSect);
    state.EntityManager.AddComponent<BlendProbeTag>(testEntity);
    RenderMeshUtility.AddComponents(testEntity, state.EntityManager, rmd, mmi);
    
    state.EntityManager.AddComponentData(testEntity, new LocalTransform {
        Position = new float3(0f, 0f, 0f),
        Rotation = quaternion.identity,
        Scale    = 1f
    });

    Debug.Log("done");
}
minor cedar
low plover
#

the key parts are (un)registering dynamic meshes and dynamic materials with EntityGraphicsSystem, and using MaterialMeshInfo to assign them to the entity

you can create all the required components at runtime with RenderMeshUtility.AddComponents

I thkn you also want to modify RenderBounds if you modify an existing entity

minor cedar
#

Thanks for the help!

I managed to generate the meshes but I had to split the logic between the calculation of the vertices and triangles and the actual mesh generation.

The calculation is burst compatible but the actual mesh generation is not, I couldn't figure out how or if it's possible, since i'm not really using a predifined mesh like in the example above.

brittle crescent
minor cedar
#

Is it normal for meshes created this way to not show their triangles during wireframe mode?
They only show the edges

brittle crescent
uncut echo
brittle crescent
#

weird, because i could the wireframe of meshes i built
🤨