No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DecalUpdateCachedSystem.cs 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. using Unity.Collections;
  2. using Unity.Mathematics;
  3. using UnityEngine.Jobs;
  4. namespace UnityEngine.Rendering.Universal
  5. {
  6. /// <summary>
  7. /// Contains <see cref="DecalProjector"/> cached properties needed for rendering.
  8. /// </summary>
  9. internal class DecalCachedChunk : DecalChunk
  10. {
  11. public MaterialPropertyBlock propertyBlock;
  12. public int passIndexDBuffer;
  13. public int passIndexEmissive;
  14. public int passIndexScreenSpace;
  15. public int passIndexGBuffer;
  16. public int drawOrder;
  17. public bool isCreated;
  18. public NativeArray<float4x4> decalToWorlds;
  19. public NativeArray<float4x4> normalToWorlds;
  20. public NativeArray<float4x4> sizeOffsets;
  21. public NativeArray<float2> drawDistances;
  22. public NativeArray<float2> angleFades;
  23. public NativeArray<float4> uvScaleBias;
  24. public NativeArray<int> layerMasks;
  25. public NativeArray<ulong> sceneLayerMasks;
  26. public NativeArray<float> fadeFactors;
  27. public NativeArray<BoundingSphere> boundingSpheres;
  28. public NativeArray<DecalScaleMode> scaleModes;
  29. public NativeArray<uint> renderingLayerMasks;
  30. public NativeArray<float3> positions;
  31. public NativeArray<quaternion> rotation;
  32. public NativeArray<float3> scales;
  33. public NativeArray<bool> dirty;
  34. public BoundingSphere[] boundingSphereArray;
  35. public override void RemoveAtSwapBack(int entityIndex)
  36. {
  37. RemoveAtSwapBack(ref decalToWorlds, entityIndex, count);
  38. RemoveAtSwapBack(ref normalToWorlds, entityIndex, count);
  39. RemoveAtSwapBack(ref sizeOffsets, entityIndex, count);
  40. RemoveAtSwapBack(ref drawDistances, entityIndex, count);
  41. RemoveAtSwapBack(ref angleFades, entityIndex, count);
  42. RemoveAtSwapBack(ref uvScaleBias, entityIndex, count);
  43. RemoveAtSwapBack(ref layerMasks, entityIndex, count);
  44. RemoveAtSwapBack(ref sceneLayerMasks, entityIndex, count);
  45. RemoveAtSwapBack(ref fadeFactors, entityIndex, count);
  46. RemoveAtSwapBack(ref boundingSphereArray, entityIndex, count);
  47. RemoveAtSwapBack(ref boundingSpheres, entityIndex, count);
  48. RemoveAtSwapBack(ref scaleModes, entityIndex, count);
  49. RemoveAtSwapBack(ref renderingLayerMasks, entityIndex, count);
  50. RemoveAtSwapBack(ref positions, entityIndex, count);
  51. RemoveAtSwapBack(ref rotation, entityIndex, count);
  52. RemoveAtSwapBack(ref scales, entityIndex, count);
  53. RemoveAtSwapBack(ref dirty, entityIndex, count);
  54. count--;
  55. }
  56. public override void SetCapacity(int newCapacity)
  57. {
  58. decalToWorlds.ResizeArray(newCapacity);
  59. normalToWorlds.ResizeArray(newCapacity);
  60. sizeOffsets.ResizeArray(newCapacity);
  61. drawDistances.ResizeArray(newCapacity);
  62. angleFades.ResizeArray(newCapacity);
  63. uvScaleBias.ResizeArray(newCapacity);
  64. layerMasks.ResizeArray(newCapacity);
  65. sceneLayerMasks.ResizeArray(newCapacity);
  66. fadeFactors.ResizeArray(newCapacity);
  67. boundingSpheres.ResizeArray(newCapacity);
  68. scaleModes.ResizeArray(newCapacity);
  69. renderingLayerMasks.ResizeArray(newCapacity);
  70. positions.ResizeArray(newCapacity);
  71. rotation.ResizeArray(newCapacity);
  72. scales.ResizeArray(newCapacity);
  73. dirty.ResizeArray(newCapacity);
  74. ArrayExtensions.ResizeArray(ref boundingSphereArray, newCapacity);
  75. capacity = newCapacity;
  76. }
  77. public override void Dispose()
  78. {
  79. if (capacity == 0)
  80. return;
  81. decalToWorlds.Dispose();
  82. normalToWorlds.Dispose();
  83. sizeOffsets.Dispose();
  84. drawDistances.Dispose();
  85. angleFades.Dispose();
  86. uvScaleBias.Dispose();
  87. layerMasks.Dispose();
  88. sceneLayerMasks.Dispose();
  89. fadeFactors.Dispose();
  90. boundingSpheres.Dispose();
  91. scaleModes.Dispose();
  92. renderingLayerMasks.Dispose();
  93. positions.Dispose();
  94. rotation.Dispose();
  95. scales.Dispose();
  96. dirty.Dispose();
  97. count = 0;
  98. capacity = 0;
  99. }
  100. }
  101. /// <summary>
  102. /// Caches <see cref="DecalProjector"/> properties into <see cref="DecalCachedChunk"/>.
  103. /// Uses jobs with <see cref="IJobParallelForTransform"/>.
  104. /// </summary>
  105. internal class DecalUpdateCachedSystem
  106. {
  107. private DecalEntityManager m_EntityManager;
  108. private ProfilingSampler m_Sampler;
  109. private ProfilingSampler m_SamplerJob;
  110. public DecalUpdateCachedSystem(DecalEntityManager entityManager)
  111. {
  112. m_EntityManager = entityManager;
  113. m_Sampler = new ProfilingSampler("DecalUpdateCachedSystem.Execute");
  114. m_SamplerJob = new ProfilingSampler("DecalUpdateCachedSystem.ExecuteJob");
  115. }
  116. public void Execute()
  117. {
  118. using (new ProfilingScope(m_Sampler))
  119. {
  120. for (int i = 0; i < m_EntityManager.chunkCount; ++i)
  121. Execute(m_EntityManager.entityChunks[i], m_EntityManager.cachedChunks[i], m_EntityManager.entityChunks[i].count);
  122. }
  123. }
  124. private void Execute(DecalEntityChunk entityChunk, DecalCachedChunk cachedChunk, int count)
  125. {
  126. if (count == 0)
  127. return;
  128. cachedChunk.currentJobHandle.Complete();
  129. // Make sure draw order is up to date
  130. var material = entityChunk.material;
  131. if (material.HasProperty("_DrawOrder"))
  132. cachedChunk.drawOrder = material.GetInt("_DrawOrder");
  133. // Shader can change any time in editor, so we have to update passes each time
  134. #if !UNITY_EDITOR
  135. if (!cachedChunk.isCreated)
  136. #endif
  137. {
  138. int passIndexDBuffer = material.FindPass(DecalShaderPassNames.DBufferProjector);
  139. cachedChunk.passIndexDBuffer = passIndexDBuffer;
  140. int passIndexEmissive = material.FindPass(DecalShaderPassNames.DecalProjectorForwardEmissive);
  141. cachedChunk.passIndexEmissive = passIndexEmissive;
  142. int passIndexScreenSpace = material.FindPass(DecalShaderPassNames.DecalScreenSpaceProjector);
  143. cachedChunk.passIndexScreenSpace = passIndexScreenSpace;
  144. int passIndexGBuffer = material.FindPass(DecalShaderPassNames.DecalGBufferProjector);
  145. cachedChunk.passIndexGBuffer = passIndexGBuffer;
  146. cachedChunk.isCreated = true;
  147. }
  148. using (new ProfilingScope(m_SamplerJob))
  149. {
  150. UpdateTransformsJob updateTransformJob = new UpdateTransformsJob()
  151. {
  152. positions = cachedChunk.positions,
  153. rotations = cachedChunk.rotation,
  154. scales = cachedChunk.scales,
  155. dirty = cachedChunk.dirty,
  156. scaleModes = cachedChunk.scaleModes,
  157. sizeOffsets = cachedChunk.sizeOffsets,
  158. decalToWorlds = cachedChunk.decalToWorlds,
  159. normalToWorlds = cachedChunk.normalToWorlds,
  160. boundingSpheres = cachedChunk.boundingSpheres,
  161. minDistance = System.Single.Epsilon,
  162. };
  163. var handle = updateTransformJob.Schedule(entityChunk.transformAccessArray);
  164. cachedChunk.currentJobHandle = handle;
  165. }
  166. }
  167. #if ENABLE_BURST_1_0_0_OR_NEWER
  168. [Unity.Burst.BurstCompile]
  169. #endif
  170. public unsafe struct UpdateTransformsJob : IJobParallelForTransform
  171. {
  172. private static readonly quaternion k_MinusYtoZRotation = quaternion.EulerXYZ(-math.PI / 2.0f, 0, 0);
  173. public NativeArray<float3> positions;
  174. public NativeArray<quaternion> rotations;
  175. public NativeArray<float3> scales;
  176. public NativeArray<bool> dirty;
  177. [ReadOnly] public NativeArray<DecalScaleMode> scaleModes;
  178. [ReadOnly] public NativeArray<float4x4> sizeOffsets;
  179. [WriteOnly] public NativeArray<float4x4> decalToWorlds;
  180. [WriteOnly] public NativeArray<float4x4> normalToWorlds;
  181. [WriteOnly] public NativeArray<BoundingSphere> boundingSpheres;
  182. public float minDistance;
  183. private float DistanceBetweenQuaternions(quaternion a, quaternion b)
  184. {
  185. return math.distancesq(a.value, b.value);
  186. }
  187. public void Execute(int index, TransformAccess transform)
  188. {
  189. // Check if transform changed
  190. bool positionChanged = math.distancesq(transform.position, positions[index]) > minDistance;
  191. if (positionChanged)
  192. positions[index] = transform.position;
  193. bool rotationChanged = DistanceBetweenQuaternions(transform.rotation, rotations[index]) > minDistance;
  194. if (rotationChanged)
  195. rotations[index] = transform.rotation;
  196. bool scaleChanged = math.distancesq(transform.localScale, scales[index]) > minDistance;
  197. if (scaleChanged)
  198. scales[index] = transform.localScale;
  199. // Early out if transform did not changed
  200. if (!positionChanged && !rotationChanged && !scaleChanged && !dirty[index])
  201. return;
  202. float4x4 localToWorld;
  203. if (scaleModes[index] == DecalScaleMode.InheritFromHierarchy)
  204. {
  205. localToWorld = transform.localToWorldMatrix;
  206. localToWorld = math.mul(localToWorld, new float4x4(k_MinusYtoZRotation, float3.zero));
  207. }
  208. else
  209. {
  210. quaternion rotation = math.mul(transform.rotation, k_MinusYtoZRotation);
  211. localToWorld = float4x4.TRS(positions[index], rotation, new float3(1, 1, 1));
  212. }
  213. float4x4 decalRotation = localToWorld;
  214. // z/y axis swap for normal to decal space, Unity is column major
  215. float4 temp = decalRotation.c1;
  216. decalRotation.c1 = decalRotation.c2;
  217. decalRotation.c2 = temp;
  218. normalToWorlds[index] = decalRotation;
  219. float4x4 sizeOffset = sizeOffsets[index];
  220. float4x4 decalToWorld = math.mul(localToWorld, sizeOffset);
  221. decalToWorlds[index] = decalToWorld;
  222. boundingSpheres[index] = GetDecalProjectBoundingSphere(decalToWorld);
  223. dirty[index] = false;
  224. }
  225. private BoundingSphere GetDecalProjectBoundingSphere(Matrix4x4 decalToWorld)
  226. {
  227. float4 min = new float4(-0.5f, -0.5f, -0.5f, 1.0f);
  228. float4 max = new float4(0.5f, 0.5f, 0.5f, 1.0f);
  229. min = math.mul(decalToWorld, min);
  230. max = math.mul(decalToWorld, max);
  231. float3 position = ((max + min) / 2f).xyz;
  232. float radius = math.length(max - min) / 2f;
  233. BoundingSphere res = new BoundingSphere();
  234. res.position = position;
  235. res.radius = radius;
  236. return res;
  237. }
  238. }
  239. }
  240. }