Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

Building procedrual mesh per SCD Nighmare

Discussion in 'Entity Component System' started by RoughSpaghetti3211, Feb 28, 2020.

  1. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,718
    Trying to build a mesh per SCD value and it proving to be a big mess. My Ideal solution would be to build the separate meshes on two different Jobs and only running whenPlanetBuildComponent changed but the mesh is a reference type. This is my best effort below if anyone has any advice please chip in. It works but it clumsy and Im very unhappy with it

    Thanks

    Code (CSharp):
    1.  
    2. protected override JobHandle OnUpdate(JobHandle inputDeps)
    3. {
    4.     JobHandle sequentialDeps = inputDeps;
    5.    
    6.     Entities
    7.         .WithAll<PlanetBuildComponent>()
    8.         .WithChangeFilter<PlanetBuildComponent>()
    9.         .ForEach((int entityInQueryIndex, in Entity e) =>
    10.         {
    11.            Debug.Log(
    12.                "<b> <size=13> <color=#EA70A3>Info : PlanetCreateBiomsSystem : GetPlanetIDs.</color> </size> </b>");
    13.            
    14.            _planetId = new List<PlanetIdComponent>();
    15.            EntityManager.GetAllUniqueSharedComponentData<PlanetIdComponent>(_planetId);
    16.        })
    17.         .WithName("GetPlanetIDs")
    18.         .WithoutBurst()
    19.         .Run();
    20.    
    21.     //
    22.     //
    23.     foreach (PlanetIdComponent id in _planetId)
    24.     {
    25.  
    26.         Entities
    27.             .WithChangeFilter<PlanetBuildComponent>()
    28.             .WithSharedComponentFilter(id)
    29.             .WithReadOnly(id)
    30.             .ForEach((int entityInQueryIndex, in Entity e, in PlanetGraphComponent g, in RenderMesh m, in PlanetBuildComponent b ) =>
    31.             {
    32.                 Debug.Log(
    33.                     "<b> <size=13> <color=#EA70A3>Info : PlanetCreateBiomsSystem : PlanetBuildMesh 1.</color> </size> </b>");
    34.                
    35.                 Mesh newPlanetMesh = new Mesh();
    36.                 int numVertices = b.VertexCount;
    37.                 int numTriangles = numVertices * 2 - 4;
    38.                 var vertexDataArray = new NativeArray<PlanetVertexData>(numTriangles * 3, Allocator.TempJob);
    39.                 var vertexIndexDataArray = new NativeArray<PlanetVertexIndexData>(numTriangles * 3, Allocator.TempJob);
    40.                
    41.                 //
    42.                 // Get mesh data
    43.                 for (var i = 0; i < g.TileGraph.Value.Triangles.Length; i++)
    44.                 {
    45.                     //
    46.                     // GetMeshTrianglePositions
    47.                     var posVertA =
    48.                         new float3(
    49.                             g.TileGraph.Value.Vertices[g.TileGraph.Value.Triangles[i].VertA].PositionX,
    50.                             g.TileGraph.Value.Vertices[g.TileGraph.Value.Triangles[i].VertA].PositionY,
    51.                             g.TileGraph.Value.Vertices[g.TileGraph.Value.Triangles[i].VertA].PositionZ);
    52.                     var posVertB =
    53.                         new float3(
    54.                             g.TileGraph.Value.Vertices[g.TileGraph.Value.Triangles[i].VertB].PositionX,
    55.                             g.TileGraph.Value.Vertices[g.TileGraph.Value.Triangles[i].VertB].PositionY,
    56.                             g.TileGraph.Value.Vertices[g.TileGraph.Value.Triangles[i].VertB].PositionZ);
    57.                     var posVertC =
    58.                         new float3(
    59.                             g.TileGraph.Value.Vertices[g.TileGraph.Value.Triangles[i].VertC].PositionX,
    60.                             g.TileGraph.Value.Vertices[g.TileGraph.Value.Triangles[i].VertC].PositionY,
    61.                             g.TileGraph.Value.Vertices[g.TileGraph.Value.Triangles[i].VertC].PositionZ);
    62.                    
    63.                     //
    64.                     // GetMeshTriangleNormals
    65.                     float3 norVertA =
    66.                         math.normalize(
    67.                             new float3(
    68.                                 g.TileGraph.Value.Vertices[g.TileGraph.Value.Triangles[i].VertA].PositionX,
    69.                                 g.TileGraph.Value.Vertices[g.TileGraph.Value.Triangles[i].VertA].PositionY,
    70.                                 g.TileGraph.Value.Vertices[g.TileGraph.Value.Triangles[i].VertA].PositionZ
    71.                             )
    72.                         );
    73.                     float3 norVertB =
    74.                         math.normalize(
    75.                             new float3(
    76.                                 g.TileGraph.Value.Vertices[g.TileGraph.Value.Triangles[i].VertB].PositionX,
    77.                                 g.TileGraph.Value.Vertices[g.TileGraph.Value.Triangles[i].VertB].PositionY,
    78.                                 g.TileGraph.Value.Vertices[g.TileGraph.Value.Triangles[i].VertB].PositionZ
    79.                             )
    80.                         );
    81.                     float3 norVertC =
    82.                         math.normalize(
    83.                             new float3(
    84.                                 g.TileGraph.Value.Vertices[g.TileGraph.Value.Triangles[i].VertC].PositionX,
    85.                                 g.TileGraph.Value.Vertices[g.TileGraph.Value.Triangles[i].VertC].PositionY,
    86.                                 g.TileGraph.Value.Vertices[g.TileGraph.Value.Triangles[i].VertC].PositionZ
    87.                             )
    88.                         );
    89.                    
    90.                     //
    91.                     // GetMeshTriangleTangents
    92.                     var tanVertA = new float4(-norVertA.z, 0, norVertA.x, -1);
    93.                     var tanVertB = new float4(-norVertB.z, 0, norVertB.x, -1);
    94.                     var tanVertC = new float4(-norVertC.z, 0, norVertC.x, -1);
    95.                
    96.                     //
    97.                     // GetMeshTriangleUv
    98.                     var uvVertA = new
    99.                         float2(
    100.                             math.atan2(norVertA.x, norVertA.z) / (-2f * math.PI),
    101.                             math.asin(norVertA.y) / math.PI + 0.5f
    102.                         );
    103.                     if (uvVertA.x < 0f) uvVertA.x += 1f;
    104.                
    105.                     var uvVertB = new
    106.                         float2(
    107.                             math.atan2(norVertB.x, norVertB.z) / (-2f * math.PI),
    108.                             math.asin(norVertB.y) / math.PI + 0.5f
    109.                         );
    110.                     if (uvVertB.x < 0f) uvVertB.x += 1f;
    111.                
    112.                     var uvVertC = new
    113.                         float2(
    114.                             math.atan2(norVertC.x, norVertC.z) / (-2f * math.PI),
    115.                             math.asin(norVertC.y) / math.PI + 0.5f
    116.                         );
    117.                     if (uvVertC.x < 0f) uvVertC.x += 1f;
    118.                
    119.                     //
    120.                     // TODO : GetMeshTriangleColo
    121.                
    122.                     //
    123.                     // Set VertexDataArray
    124.                     var vertexDataA = new PlanetVertexData
    125.                     {
    126.                         Position = posVertA,
    127.                         Normal = norVertA,
    128.                         Tangent = tanVertA,
    129.                         UVs = uvVertA,
    130.                         Color = new int4(1, 1, 1, 1)
    131.                     };
    132.                     vertexDataArray[3 * i + 0] = vertexDataA;
    133.                
    134.                     var vertexDataB = new PlanetVertexData
    135.                     {
    136.                         Position = posVertB,
    137.                         Normal = norVertB,
    138.                         Tangent = tanVertB,
    139.                         UVs = uvVertB,
    140.                         Color = new int4(1, 1, 1, 1)
    141.                     };
    142.                     vertexDataArray[3 * i + 1] = vertexDataB;
    143.                
    144.                     var vertexDataC = new PlanetVertexData
    145.                     {
    146.                         Position = posVertC,
    147.                         Normal = norVertC,
    148.                         Tangent = tanVertC,
    149.                         UVs = uvVertC,
    150.                         Color = new int4(1, 1, 1, 1)
    151.                     };
    152.                     vertexDataArray[3 * i + 2] = vertexDataC;
    153.                
    154.                     //
    155.                     // GetMeshTriangleIndices
    156.                     vertexIndexDataArray[3 * i + 0] = 3 * i + 0;
    157.                     vertexIndexDataArray[3 * i + 1] = 3 * i + 1;
    158.                     vertexIndexDataArray[3 * i + 2] = 3 * i + 2;
    159.                 }
    160.        
    161.                 //
    162.                 // This descriptor must match VertexData structure.
    163.                 var vertexAttrDescriptor = new[]
    164.                 {
    165.                     new VertexAttributeDescriptor(VertexAttribute.Position),
    166.                     new VertexAttributeDescriptor(VertexAttribute.Normal),
    167.                     new VertexAttributeDescriptor(VertexAttribute.Tangent, VertexAttributeFormat.Float32, 4),
    168.                     new VertexAttributeDescriptor(VertexAttribute.Color, VertexAttributeFormat.UInt32, 4),
    169.                     new VertexAttributeDescriptor(VertexAttribute.TexCoord0, VertexAttributeFormat.Float32, 2)
    170.                 };
    171.                
    172.                 //
    173.                 // Tell the mesh what format the params will be sent. Note the format must match VertexIndexData struct
    174.                 newPlanetMesh.SetVertexBufferParams(vertexDataArray.Length, vertexAttrDescriptor);
    175.                 newPlanetMesh.SetVertexBufferData(vertexDataArray, 0, 0, vertexDataArray.Length);
    176.                 newPlanetMesh.SetIndexBufferParams(vertexIndexDataArray.Length, IndexFormat.UInt32);
    177.                 newPlanetMesh.SetIndexBufferData(vertexIndexDataArray, 0, 0, vertexIndexDataArray.Length);
    178.                 newPlanetMesh.subMeshCount = 1;
    179.                
    180.                 //
    181.                 // Set SubMeshDescriptor
    182.                 var descr = new SubMeshDescriptor
    183.                 {
    184.                     baseVertex = 0,
    185.                     bounds = default,
    186.                     indexCount = vertexDataArray.Length,
    187.                     indexStart = 0,
    188.                     topology = MeshTopology.Triangles
    189.                 };
    190.                 newPlanetMesh.SetSubMesh(0, descr);
    191.                
    192.                 //
    193.                 // Bounds
    194.                 newPlanetMesh.RecalculateBounds();
    195.        
    196.                 //
    197.                 // Set SCD
    198.                 EntityManager.SetSharedComponentData(e, new RenderMesh
    199.                 {
    200.                     material = m.material,
    201.                     mesh = newPlanetMesh,
    202.                     castShadows = m.castShadows,
    203.                     receiveShadows = m.receiveShadows
    204.                 });
    205.                
    206.                 //
    207.                 // Cleanup
    208.                 vertexDataArray.Dispose();
    209.                 vertexIndexDataArray.Dispose();
    210.                    
    211.             })
    212.             .WithStructuralChanges()
    213.             .WithoutBurst()
    214.             .Run();
    215.     }
    216.    
    217.     //
    218.     // Cleanup
    219.     _planetId.Clear();
    220.     return sequentialDeps;
    221. }
    222.  
    223.  
     
  2. TheGabelle

    TheGabelle

    Joined:
    Aug 23, 2013
    Posts:
    242
  3. Sarkahn

    Sarkahn

    Joined:
    Jan 9, 2013
    Posts:
    440
    The job MeshData api is available right now in the latest 2020 version if you want to switch to that.

    If you want to run main thread code after a job it's up to you to manually force the job to complete first. You can schedule your jobs to operate on your mesh data early in the frame and assign the jobhandle to a publicly accessible variable.

    Something like:

    Code (CSharp):
    1.  
    2. // Run early in the frame.
    3. [UpdateInGroup(typeof(InitializationSystemGroup))]
    4. class UpdateMeshDataSystem : SystemBase
    5. {
    6.     List<PlanetIdComponent> _ids = new List();
    7.  
    8.     public JobHandle FinalJobHandle => Dependency;
    9.  
    10.     protected override Jobhandle OnUpdate()
    11.     {
    12.         _ids.Clear();
    13.         EntityManager.GetAllUniqueSharedComponentData(_ids);
    14.      
    15.         foreach(var id in _ids)
    16.         {
    17.             // Schedule your jobs. Only operate on mesh data, don't touch the mesh.
    18.         }
    19.     }
    20. }
    21.  
    22. // Run later in the frame but before rendering
    23. [UpdateInGroup(typeof(LateSimulationSystemGroup))]
    24. class UploadMeshData : SystemBase
    25. {
    26.     protected override Jobhandle OnUpdate()
    27.     {
    28.         World.GetOrCreateSystem<UpdateMeshDataSystem>().FinalJobHandle.Complete();
    29.         // Or check (if FinalJobHandle.IsComplete) first if you want to avoid blocking until the job is finished.
    30.      
    31.         // Query for the updated mesh data, update mesh on main thread.
    32.     }
    33. }
     
    Last edited: Mar 2, 2020
    vildauget likes this.
  4. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,718
    Thank you will give this a try