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

What is the best/proper way to separate Rendering from Physics

Discussion in 'Graphics for ECS' started by Opeth001, Nov 30, 2019.

  1. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,129
    Hello Everyone

    as you guys know, the Hybred renderer is currently not supporting the URP which is really sad.

    so as workaround i'm trying to separate the Rendering from Physics and Game logic.

    i have 3 GameObjects Types:
    1) Gameobjects (Rendering Only + Static)
    2) Gameobjects (Rendering + Physics + Static)
    3) GameObjects (Rendering + Physics + Desctructable) // will never move but can be destroyed

    i need to get 2 differents builds:

    Server: Containing only (2),(3) but without rendering.

    Client: Containing (2),(3) physics stuff only as subscene and (1),(2),(3) as game objects. but i need to get a link between the (3) generated Entities in subscene and their original GameObjects.

    any suggestion will be highly appreciated!
    Thank you!
     
    Nyanpas likes this.
  2. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,319
    Perhaps I might be biased because I am a bit of a graphics guy, but why not just write a simple alternative to the hybrid renderer instead of writing some fancy link system? While it is true that GameObject instancing can be faster than DrawMeshInstanced, I don't think it will be faster than DrawMeshInstanced and the syncing to the GameObjects.
     
  3. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,129
    by writing an alternative to the hybred renderer, will URP be able to render the Entities correctly ?
    if yes, it will be much easier to me for handling builds and even gameplay
     
  4. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,319
    The hybrid renderer uses a specialized batched instanced rendering API and I suspect that is what breaks URP. I would be surprised if using Graphics.DrawMeshInstanced (like what Hybrid Renderer version 1 did) is also broken in URP. That would be a major URP bug.
     
    Opeth001 likes this.
  5. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,129
    i see, ill read and try to understand how the hybred renderer works and see if by using Graphics.DrawMeshInstanced the URP will work correctly, this can be really awesome!
    Thank you!!!
     
  6. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,154
    Check the thread by Joachim (animation system) or the one labeled 200k sprites (ended up much more + principle also works for 3D)
     
    MNNoxMortem and Opeth001 like this.
  7. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,129
    Im trying to modify the RenderMeshSystemV2 to make it use the Graphics.DrawMeshInstanced.
    but the system is drawing the scene once then everything disappear.

    Code:
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using Unity.Burst;
    3. using Unity.Collections;
    4. using Unity.Collections.LowLevel.Unsafe;
    5. using Unity.Entities;
    6. using Unity.Jobs;
    7. using Unity.Mathematics;
    8. using Unity.Transforms;
    9. using UnityEngine;
    10. using UnityEngine.Assertions;
    11. using UnityEngine.Profiling;
    12.  
    13. namespace Unity.Rendering
    14. {
    15.    
    16.     /// <summary>
    17.     /// Renders all Entities containing both RenderMesh & LocalToWorld components.
    18.     /// </summary>
    19.     [ExecuteAlways]
    20.     //@TODO: Necessary due to empty component group. When Component group and archetype chunks are unified this should be removed
    21.     [AlwaysUpdateSystem]
    22.     [UpdateInGroup(typeof(PresentationSystemGroup))]
    23.     [UpdateAfter(typeof(LodRequirementsUpdateSystem))]
    24.     public class RenderMeshSystemV1 : JobComponentSystem
    25.     {
    26.         int m_LastFrozenChunksOrderVersion = -1;
    27.  
    28.         EntityQuery m_FrozenGroup;
    29.         EntityQuery m_DynamicGroup;
    30.  
    31.         EntityQuery m_CullingJobDependencyGroup;
    32.  
    33.  
    34.         Matrix4x4[] m_MatricesArray = new Matrix4x4[1023];
    35.  
    36.         NativeHashMap<FrozenRenderSceneTag, int> m_SubsceneTagVersion;
    37.         NativeList<SubSceneTagOrderVersion> m_LastKnownSubsceneTagVersion;
    38.  
    39.         #if UNITY_EDITOR
    40.         EditorRenderData m_DefaultEditorRenderData = new EditorRenderData { SceneCullingMask = UnityEditor.SceneManagement.EditorSceneManager.DefaultSceneCullingMask };
    41.         #else
    42.         EditorRenderData m_DefaultEditorRenderData = new EditorRenderData { SceneCullingMask = ~0UL };
    43.         #endif
    44.  
    45.         protected override void OnCreate()
    46.         {
    47.             //@TODO: Support SetFilter with EntityQueryDesc syntax
    48.  
    49.             m_FrozenGroup = GetEntityQuery(
    50.                 ComponentType.ChunkComponentReadOnly<ChunkWorldRenderBounds>(),
    51.                 ComponentType.ReadOnly<WorldRenderBounds>(),
    52.                 ComponentType.ReadOnly<LocalToWorld>(),
    53.                 ComponentType.ReadOnly<RenderMesh>(),
    54.                 ComponentType.ReadOnly<FrozenRenderSceneTag>()
    55.             );
    56.             m_DynamicGroup = GetEntityQuery(
    57.                 ComponentType.ChunkComponentReadOnly<ChunkWorldRenderBounds>(),
    58.                 ComponentType.Exclude<FrozenRenderSceneTag>(),
    59.                 ComponentType.ReadOnly<WorldRenderBounds>(),
    60.                 ComponentType.ReadOnly<LocalToWorld>(),
    61.                 ComponentType.ReadOnly<RenderMesh>()
    62.             );
    63.  
    64.             // This component group must include all types that are being used by the culling job
    65.             m_CullingJobDependencyGroup = GetEntityQuery(
    66.                 ComponentType.ChunkComponentReadOnly<ChunkWorldRenderBounds>(),
    67.                 ComponentType.ReadOnly<RootLodRequirement>(),
    68.                 ComponentType.ReadOnly<LodRequirement>(),
    69.                 ComponentType.ReadOnly<WorldRenderBounds>()
    70.             );
    71.            
    72.             m_SubsceneTagVersion = new NativeHashMap<FrozenRenderSceneTag, int>(1000,Allocator.Persistent);
    73.             m_LastKnownSubsceneTagVersion = new NativeList<SubSceneTagOrderVersion>(Allocator.Persistent);
    74.         }
    75.  
    76.         protected override void OnDestroy()
    77.         {
    78.             m_SubsceneTagVersion.Dispose();
    79.             m_LastKnownSubsceneTagVersion.Dispose();
    80.         }
    81.  
    82.         public void CacheMeshBatchRendererGroup(FrozenRenderSceneTag tag, NativeArray<ArchetypeChunk> chunks, int chunkCount)
    83.         {
    84.             var RenderMeshType = GetArchetypeChunkSharedComponentType<RenderMesh>();
    85.             var LocalToWorldType = GetArchetypeChunkComponentType<LocalToWorld>();
    86.  
    87.             var meshInstanceFlippedTagType = GetArchetypeChunkComponentType<RenderMeshFlippedWindingTag>();
    88.             var editorRenderDataType = GetArchetypeChunkSharedComponentType<EditorRenderData>();
    89.  
    90.             Profiler.BeginSample("Sort Shared Renderers");
    91.             var chunkRenderer = new NativeArray<int>(chunkCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
    92.             var sortedChunks = new NativeArraySharedValues<int>(chunkRenderer, Allocator.TempJob);
    93.  
    94.             var gatherChunkRenderersJob = new GatherChunkRenderers
    95.             {
    96.                 Chunks = chunks,
    97.                 RenderMeshType = RenderMeshType,
    98.                 ChunkRenderer = chunkRenderer
    99.             };
    100.             var gatherChunkRenderersJobHandle = gatherChunkRenderersJob.Schedule(chunkCount, 64);
    101.             var sortedChunksJobHandle = sortedChunks.Schedule(gatherChunkRenderersJobHandle);
    102.             sortedChunksJobHandle.Complete();
    103.             Profiler.EndSample();
    104.  
    105.  
    106.             var sharedRenderCount = sortedChunks.SharedValueCount;
    107.             var sharedRendererCounts = sortedChunks.GetSharedValueIndexCountArray();
    108.             var sortedChunkIndices = sortedChunks.GetSortedIndices();
    109.            
    110.             Profiler.BeginSample("Add New Batches");
    111.             {
    112.                 var sortedChunkIndex = 0;
    113.                 for (int i = 0; i < sharedRenderCount; i++)
    114.                 {
    115.                     var startSortedChunkIndex = sortedChunkIndex;
    116.                     var endSortedChunkIndex = startSortedChunkIndex + sharedRendererCounts[i];
    117.  
    118.                     while (sortedChunkIndex < endSortedChunkIndex)
    119.                     {
    120.                         var chunkIndex = sortedChunkIndices[sortedChunkIndex];
    121.                         var chunk = chunks[chunkIndex];
    122.                         var rendererSharedComponentIndex = chunk.GetSharedComponentIndex(RenderMeshType);
    123.  
    124.                         var editorRenderDataIndex = chunk.GetSharedComponentIndex(editorRenderDataType);
    125.                         var editorRenderData = m_DefaultEditorRenderData;
    126.                         if (editorRenderDataIndex != -1)
    127.                             editorRenderData = EntityManager.GetSharedComponentData<EditorRenderData>(editorRenderDataIndex);
    128.  
    129.                         var remainingEntitySlots = 1023;
    130.                         var flippedWinding = chunk.Has(meshInstanceFlippedTagType);
    131.                         int instanceCount = chunk.Count;
    132.                         int startSortedIndex = sortedChunkIndex;
    133.                         int batchChunkCount = 1;
    134.  
    135.                         remainingEntitySlots -= chunk.Count;
    136.                         sortedChunkIndex++;
    137.  
    138.                         while (remainingEntitySlots > 0)
    139.                         {
    140.                             if (sortedChunkIndex >= endSortedChunkIndex)
    141.                                 break;
    142.  
    143.                             var nextChunkIndex = sortedChunkIndices[sortedChunkIndex];
    144.                             var nextChunk = chunks[nextChunkIndex];
    145.                             if (nextChunk.Count > remainingEntitySlots)
    146.                                 break;
    147.  
    148.                             var nextFlippedWinding = nextChunk.Has(meshInstanceFlippedTagType);
    149.                             if (nextFlippedWinding != flippedWinding)
    150.                                 break;
    151.  
    152. #if UNITY_EDITOR
    153.                             if (editorRenderDataIndex != nextChunk.GetSharedComponentIndex(editorRenderDataType))
    154.                                 break;
    155. #endif
    156.  
    157.                             remainingEntitySlots -= nextChunk.Count;
    158.                             instanceCount += nextChunk.Count;
    159.                             batchChunkCount++;
    160.                             sortedChunkIndex++;
    161.                         }
    162.  
    163.                         // m_InstancedRenderMeshBatchGroup.AddBatch(tag, rendererSharedComponentIndex, instanceCount, chunks, sortedChunkIndices, startSortedIndex, batchChunkCount, flippedWinding, editorRenderData);
    164.  
    165.                         var renderer = EntityManager.GetSharedComponentData<RenderMesh>(rendererSharedComponentIndex);
    166.                         var LocalToWorldArray = chunk.GetNativeArray(LocalToWorldType);
    167.                         // var Matrix4x4Array = LocalToWorldArray.Reinterpret<Matrix4x4>();
    168.  
    169.  
    170.                         CopyTo(LocalToWorldArray, ref m_MatricesArray);
    171.  
    172.                         Graphics.DrawMeshInstanced(renderer.mesh, renderer.subMesh, renderer.material, m_MatricesArray, LocalToWorldArray.Length, null, renderer.castShadows, renderer.receiveShadows, renderer.layer, null);
    173.                     }
    174.                 }
    175.             }
    176.             Profiler.EndSample();
    177.  
    178.             chunkRenderer.Dispose();
    179.             sortedChunks.Dispose();
    180.         }
    181.  
    182.        
    183.  
    184.         static unsafe void CopyTo(NativeArray<LocalToWorld> LocalToWorldArray,ref Matrix4x4[] outMatrices)
    185.         {
    186.             // @TODO: This is using unsafe code because the Unity DrawInstances API takes a Matrix4x4[] instead of NativeArray.
    187.             Assert.AreEqual(sizeof(Matrix4x4), sizeof(LocalToWorld));
    188.             fixed (Matrix4x4* resultMatrices = outMatrices)
    189.             {
    190.                 LocalToWorld* sourceMatrices = (LocalToWorld*)NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(LocalToWorldArray);
    191.                 UnsafeUtility.MemCpy(resultMatrices, sourceMatrices, UnsafeUtility.SizeOf<Matrix4x4>() * LocalToWorldArray.Length);
    192.             }
    193.         }
    194.  
    195.  
    196.  
    197.         void UpdateFrozenRenderBatches()
    198.         {
    199.             var staticChunksOrderVersion = EntityManager.GetComponentOrderVersion<FrozenRenderSceneTag>();
    200.             if (staticChunksOrderVersion == m_LastFrozenChunksOrderVersion)
    201.                 return;
    202.  
    203.             for (int i = 0; i < m_LastKnownSubsceneTagVersion.Length; i++)
    204.             {
    205.                 var scene = m_LastKnownSubsceneTagVersion[i].Scene;
    206.                 var version = m_LastKnownSubsceneTagVersion[i].Version;
    207.  
    208.                 if (EntityManager.GetSharedComponentOrderVersion(scene) != version)
    209.                 {
    210.                     // Debug.Log($"Removing scene:{scene:X8} batches");
    211.                     Profiler.BeginSample("Remove Subscene");
    212.                     m_SubsceneTagVersion.Remove(scene);
    213.                   //  m_InstancedRenderMeshBatchGroup.RemoveTag(scene);
    214.                     Profiler.EndSample();
    215.                 }
    216.             }
    217.  
    218.             m_LastKnownSubsceneTagVersion.Clear();
    219.  
    220.             var loadedSceneTags = new List<FrozenRenderSceneTag>();
    221.             EntityManager.GetAllUniqueSharedComponentData(loadedSceneTags);
    222.  
    223.             for (var i = 0; i < loadedSceneTags.Count; i++)
    224.             {
    225.                 var subsceneTag = loadedSceneTags[i];
    226.                 int subsceneTagVersion = EntityManager.GetSharedComponentOrderVersion(subsceneTag);
    227.  
    228.                 m_LastKnownSubsceneTagVersion.Add(new SubSceneTagOrderVersion
    229.                 {
    230.                     Scene = subsceneTag,
    231.                     Version = subsceneTagVersion
    232.                 });
    233.  
    234.                 var alreadyTrackingSubscene = m_SubsceneTagVersion.TryGetValue(subsceneTag, out var _);
    235.                 if (alreadyTrackingSubscene)
    236.                     continue;
    237.  
    238.                 m_FrozenGroup.SetSharedComponentFilter(subsceneTag);
    239.  
    240.                 var filteredChunks = m_FrozenGroup.CreateArchetypeChunkArray(Allocator.TempJob);
    241.  
    242.                 m_FrozenGroup.ResetFilter();
    243.  
    244.                 m_SubsceneTagVersion.TryAdd(subsceneTag, subsceneTagVersion);
    245.  
    246.                 Profiler.BeginSample("CacheMeshBatchRenderGroup");
    247.                 CacheMeshBatchRendererGroup(subsceneTag, filteredChunks, filteredChunks.Length);
    248.                 Profiler.EndSample();
    249.  
    250.                 filteredChunks.Dispose();
    251.             }
    252.  
    253.             m_LastFrozenChunksOrderVersion = staticChunksOrderVersion;
    254.         }
    255.  
    256.         void UpdateDynamicRenderBatches()
    257.         {
    258.            // m_InstancedRenderMeshBatchGroup.RemoveTag(new FrozenRenderSceneTag());
    259.  
    260.             Profiler.BeginSample("CreateArchetypeChunkArray");
    261.             var chunks = m_DynamicGroup.CreateArchetypeChunkArray(Allocator.TempJob);
    262.             Profiler.EndSample();
    263.  
    264.             if (chunks.Length > 0)
    265.             {
    266.                 CacheMeshBatchRendererGroup(new FrozenRenderSceneTag(), chunks, chunks.Length);
    267.             }
    268.             chunks.Dispose();
    269.         }
    270.  
    271.  
    272.         protected override JobHandle OnUpdate(JobHandle inputDeps)
    273.         {
    274.             inputDeps.Complete(); // #todo
    275.            
    276.            // m_InstancedRenderMeshBatchGroup.CompleteJobs();
    277.           //  m_InstancedRenderMeshBatchGroup.ResetLod();
    278.  
    279.             Profiler.BeginSample("UpdateFrozenRenderBatches");
    280.             UpdateFrozenRenderBatches();
    281.             Profiler.EndSample();
    282.  
    283.             Profiler.BeginSample("UpdateDynamicRenderBatches");
    284.             UpdateDynamicRenderBatches();
    285.             Profiler.EndSample();
    286.  
    287.            // m_InstancedRenderMeshBatchGroup.LastUpdatedOrderVersion = EntityManager.GetComponentOrderVersion<RenderMesh>();
    288.            
    289.             return new JobHandle();
    290.         }
    291.  
    292. #if UNITY_EDITOR
    293.         //public CullingStats ComputeCullingStats() { return m_InstancedRenderMeshBatchGroup.ComputeCullingStats(); }
    294. #endif
    295.     }
    296. }
    297.  
     
    Last edited: Dec 2, 2019
  8. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,319
    I'm pretty sure the API that V2 uses is stateful and only needs to be called on changes.
     
    GilCat likes this.