Advertisement
Guest User

Untitled

a guest
Apr 6th, 2018
1,719
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.70 KB | None | 0 0
  1. using System.Collections.Generic;
  2. using Unity.Collections.LowLevel.Unsafe;
  3. using Unity.Entities;
  4. using Unity.Mathematics;
  5. using Unity.Transforms;
  6. using UnityEngine;
  7. using UnityEngine.Assertions;
  8. using UnityEngine.Experimental.PlayerLoop;
  9. using Unity.Transforms2D;
  10.  
  11. namespace toinfiniityandbeyond.Rendering
  12. {
  13. /// <summary>
  14. /// Renders all Entities containing both SpriteInstanceRenderer & TransformMatrix components.
  15. /// </summary>
  16. // [UpdateAfter(typeof(PreLateUpdate.ParticleSystemBeginUpdateAll))]
  17. // [UnityEngine.ExecuteInEditMode]
  18. public class SpriteInstanceRendererSystem : ComponentSystem
  19. {
  20. private readonly Dictionary<SpriteInstanceRenderer, Material> _cachedMaterialDictionary =
  21. new Dictionary<SpriteInstanceRenderer, Material>();
  22.  
  23. private readonly Dictionary<SpriteInstanceRenderer, Mesh> _cachedMeshDictionary =
  24. new Dictionary<SpriteInstanceRenderer, Mesh>();
  25.  
  26. // Instance renderer takes only batches of 1023
  27. Matrix4x4[] m_MatricesArray = new Matrix4x4[1023];
  28. List<SpriteInstanceRenderer> m_CacheduniqueRendererTypes = new List<SpriteInstanceRenderer>(10);
  29. ComponentGroup m_InstanceRendererGroup;
  30.  
  31. // This is the ugly bit, necessary until Graphics.DrawMeshInstanced supports NativeArrays pulling the data in from a job.
  32. public unsafe static void CopyMatrices(ComponentDataArray<TransformMatrix> transforms, int beginIndex, int length, Matrix4x4[] outMatrices)
  33. {
  34. // @TODO: This is using unsafe code because the Unity DrawInstances API takes a Matrix4x4[] instead of NativeArray.
  35. // We want to use the ComponentDataArray.CopyTo method
  36. // because internally it uses memcpy to copy the data,
  37. // if the nativeslice layout matches the layout of the component data. It's very fast...
  38. fixed (Matrix4x4* matricesPtr = outMatrices)
  39. {
  40. Assert.AreEqual(sizeof(Matrix4x4), sizeof(TransformMatrix));
  41. var matricesSlice = NativeSliceUnsafeUtility.ConvertExistingDataToNativeSlice<TransformMatrix>(matricesPtr, sizeof(Matrix4x4), length);
  42. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  43. NativeSliceUnsafeUtility.SetAtomicSafetyHandle(ref matricesSlice, AtomicSafetyHandle.GetTempUnsafePtrSliceHandle());
  44. #endif
  45. transforms.CopyTo(matricesSlice, beginIndex);
  46. }
  47. }
  48.  
  49. protected override void OnCreateManager(int capacity)
  50. {
  51. // We want to find all MeshInstanceRenderer & TransformMatrix combinations and render them
  52. m_InstanceRendererGroup = GetComponentGroup(typeof(SpriteInstanceRenderer), typeof(TransformMatrix));
  53. }
  54.  
  55. protected override void OnUpdate()
  56. {
  57. // We want to iterate over all unique MeshInstanceRenderer shared component data,
  58. // that are attached to any entities in the world
  59. EntityManager.GetAllUniqueSharedComponentDatas(m_CacheduniqueRendererTypes);
  60. for (int i = 0;i != m_CacheduniqueRendererTypes.Count;i++)
  61. {
  62. // For each unique MeshInstanceRenderer data, we want to get all entities with a TransformMatrix
  63. // SharedComponentData gurantees that all those entities are packed togehter in a chunk with linear memory layout.
  64. // As a result the copy of the matrices out is internally done via memcpy.
  65. var renderer = m_CacheduniqueRendererTypes[i];
  66. if (renderer.sprite == null)
  67. continue;
  68. m_InstanceRendererGroup.SetFilter(renderer);
  69. var transforms = m_InstanceRendererGroup.GetComponentDataArray<TransformMatrix>();
  70.  
  71. Mesh mesh;
  72. Material material;
  73. var size = math.max(renderer.sprite.width, renderer.sprite.height) / (float) renderer.pixelsPerUnit;
  74. float2 meshPivot = renderer.pivot * size;
  75. if (!_cachedMeshDictionary.TryGetValue(renderer, out mesh))
  76. {
  77. mesh = MeshUtils.GenerateQuad(size, meshPivot);
  78. _cachedMeshDictionary.Add(renderer, mesh);
  79. }
  80.  
  81. if (!_cachedMaterialDictionary.TryGetValue(renderer, out material))
  82. {
  83. material = new Material(Shader.Find("Sprites/Instanced"))
  84. {
  85. enableInstancing = true,
  86. mainTexture = renderer.sprite
  87. };
  88. _cachedMaterialDictionary.Add(renderer, material);
  89. }
  90.  
  91. // Graphics.DrawMeshInstanced has a set of limitations that are not optimal for working with ECS.
  92. // Specifically:
  93. // * No way to push the matrices from a job
  94. // * no NativeArray API, currently uses Matrix4x4[]
  95. // As a result this code is not yet jobified.
  96. // We are planning to adjust this API to make it more efficient for this use case.
  97.  
  98. // For now, we have to copy our data into Matrix4x4[] with a specific upper limit of how many instances we can render in one batch.
  99. // So we just have a for loop here, representing each Graphics.DrawMeshInstanced batch
  100. int beginIndex = 0;
  101. while (beginIndex < transforms.Length)
  102. {
  103. int length = math.min(m_MatricesArray.Length, transforms.Length - beginIndex);
  104. CopyMatrices(transforms, beginIndex, length, m_MatricesArray);
  105. Graphics.DrawMeshInstanced(mesh, 0, material, m_MatricesArray, length);
  106.  
  107. beginIndex += length;
  108. }
  109. }
  110.  
  111. m_CacheduniqueRendererTypes.Clear();
  112. }
  113. }
  114. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement