210 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			210 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|  | using Unity.Collections; | ||
|  | using UnityEngine.Experimental.Rendering; | ||
|  | 
 | ||
|  | namespace UnityEngine.Rendering.Universal | ||
|  | { | ||
|  |     /// <summary> | ||
|  |     /// Abstract class that render decals using <see cref="DecalDrawCallChunk"/>. | ||
|  |     /// Supports rendering with <see cref="CommandBuffer"/> and graphics draw calls. | ||
|  |     /// </summary> | ||
|  |     internal abstract class DecalDrawSystem | ||
|  |     { | ||
|  |         readonly static internal uint MaxBatchSize = 250; | ||
|  | 
 | ||
|  |         protected DecalEntityManager m_EntityManager; | ||
|  |         private Matrix4x4[] m_WorldToDecals; | ||
|  |         private Matrix4x4[] m_NormalToDecals; | ||
|  |         private float[] m_DecalLayerMasks; | ||
|  |         private ProfilingSampler m_Sampler; | ||
|  | 
 | ||
|  |         public Material overrideMaterial { get; set; } | ||
|  | 
 | ||
|  |         public DecalDrawSystem(string sampler, DecalEntityManager entityManager) | ||
|  |         { | ||
|  |             m_EntityManager = entityManager; | ||
|  | 
 | ||
|  |             m_WorldToDecals = new Matrix4x4[MaxBatchSize]; | ||
|  |             m_NormalToDecals = new Matrix4x4[MaxBatchSize]; | ||
|  |             m_DecalLayerMasks = new float[MaxBatchSize]; | ||
|  | 
 | ||
|  |             m_Sampler = new ProfilingSampler(sampler); | ||
|  |         } | ||
|  | 
 | ||
|  |         public void Execute(CommandBuffer cmd) | ||
|  |         { | ||
|  |             Execute(CommandBufferHelpers.GetRasterCommandBuffer(cmd)); | ||
|  |         } | ||
|  | 
 | ||
|  |         internal void Execute(RasterCommandBuffer cmd) | ||
|  |         { | ||
|  |             using (new ProfilingScope(cmd, m_Sampler)) | ||
|  |             { | ||
|  |                 for (int i = 0; i < m_EntityManager.chunkCount; ++i) | ||
|  |                 { | ||
|  |                     Execute( | ||
|  |                         cmd, | ||
|  |                         m_EntityManager.entityChunks[i], | ||
|  |                         m_EntityManager.cachedChunks[i], | ||
|  |                         m_EntityManager.drawCallChunks[i], | ||
|  |                         m_EntityManager.entityChunks[i].count); | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         protected virtual Material GetMaterial(DecalEntityChunk decalEntityChunk) => decalEntityChunk.material; | ||
|  | 
 | ||
|  |         protected abstract int GetPassIndex(DecalCachedChunk decalCachedChunk); | ||
|  | 
 | ||
|  |         private void Execute(RasterCommandBuffer cmd, DecalEntityChunk decalEntityChunk, DecalCachedChunk decalCachedChunk, DecalDrawCallChunk decalDrawCallChunk, int count) | ||
|  |         { | ||
|  |             decalCachedChunk.currentJobHandle.Complete(); | ||
|  |             decalDrawCallChunk.currentJobHandle.Complete(); | ||
|  | 
 | ||
|  |             Material material = GetMaterial(decalEntityChunk); | ||
|  |             int passIndex = GetPassIndex(decalCachedChunk); | ||
|  | 
 | ||
|  |             if (count == 0 || passIndex == -1 || material == null) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             if (SystemInfo.supportsInstancing && material.enableInstancing) | ||
|  |             { | ||
|  |                 DrawInstanced(cmd, decalEntityChunk, decalCachedChunk, decalDrawCallChunk, passIndex); | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 Draw(cmd, decalEntityChunk, decalCachedChunk, decalDrawCallChunk, passIndex); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         private void Draw(RasterCommandBuffer cmd, DecalEntityChunk decalEntityChunk, DecalCachedChunk decalCachedChunk, DecalDrawCallChunk decalDrawCallChunk, int passIndex) | ||
|  |         { | ||
|  |             var mesh = m_EntityManager.decalProjectorMesh; | ||
|  |             var material = GetMaterial(decalEntityChunk); | ||
|  |             decalCachedChunk.propertyBlock.SetVector("unity_LightData", new Vector4(1, 1, 1, 0)); // GetMainLight requires z component to be set | ||
|  | 
 | ||
|  |             int subCallCount = decalDrawCallChunk.subCallCount; | ||
|  |             for (int i = 0; i < subCallCount; ++i) | ||
|  |             { | ||
|  |                 var subCall = decalDrawCallChunk.subCalls[i]; | ||
|  | 
 | ||
|  |                 for (int j = subCall.start; j < subCall.end; ++j) | ||
|  |                 { | ||
|  |                     decalCachedChunk.propertyBlock.SetMatrix("_NormalToWorld", decalDrawCallChunk.normalToDecals[j]); | ||
|  |                     decalCachedChunk.propertyBlock.SetFloat("_DecalLayerMaskFromDecal", decalDrawCallChunk.renderingLayerMasks[j]); | ||
|  |                     cmd.DrawMesh(mesh, decalDrawCallChunk.decalToWorlds[j], material, 0, passIndex, decalCachedChunk.propertyBlock); | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         private void DrawInstanced(RasterCommandBuffer cmd, DecalEntityChunk decalEntityChunk, DecalCachedChunk decalCachedChunk, DecalDrawCallChunk decalDrawCallChunk, int passIndex) | ||
|  |         { | ||
|  |             var mesh = m_EntityManager.decalProjectorMesh; | ||
|  |             var material = GetMaterial(decalEntityChunk); | ||
|  |             decalCachedChunk.propertyBlock.SetVector("unity_LightData", new Vector4(1, 1, 1, 0)); // GetMainLight requires z component to be set | ||
|  | 
 | ||
|  |             int subCallCount = decalDrawCallChunk.subCallCount; | ||
|  |             for (int i = 0; i < subCallCount; ++i) | ||
|  |             { | ||
|  |                 var subCall = decalDrawCallChunk.subCalls[i]; | ||
|  | 
 | ||
|  |                 var decalToWorldSlice = decalDrawCallChunk.decalToWorlds.Reinterpret<Matrix4x4>(); | ||
|  |                 NativeArray<Matrix4x4>.Copy(decalToWorldSlice, subCall.start, m_WorldToDecals, 0, subCall.count); | ||
|  | 
 | ||
|  |                 var normalToWorldSlice = decalDrawCallChunk.normalToDecals.Reinterpret<Matrix4x4>(); | ||
|  |                 NativeArray<Matrix4x4>.Copy(normalToWorldSlice, subCall.start, m_NormalToDecals, 0, subCall.count); | ||
|  | 
 | ||
|  |                 var decalLayerMaskSlice = decalDrawCallChunk.renderingLayerMasks.Reinterpret<float>(); | ||
|  |                 NativeArray<float>.Copy(decalLayerMaskSlice, subCall.start, m_DecalLayerMasks, 0, subCall.count); | ||
|  | 
 | ||
|  |                 decalCachedChunk.propertyBlock.SetMatrixArray("_NormalToWorld", m_NormalToDecals); | ||
|  |                 decalCachedChunk.propertyBlock.SetFloatArray("_DecalLayerMaskFromDecal", m_DecalLayerMasks); | ||
|  |                 cmd.DrawMeshInstanced(mesh, 0, material, passIndex, m_WorldToDecals, subCall.end - subCall.start, decalCachedChunk.propertyBlock); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public void Execute(in CameraData cameraData) | ||
|  |         { | ||
|  |             using (new ProfilingScope(m_Sampler)) | ||
|  |             { | ||
|  |                 for (int i = 0; i < m_EntityManager.chunkCount; ++i) | ||
|  |                 { | ||
|  |                     Execute( | ||
|  |                         cameraData, | ||
|  |                         m_EntityManager.entityChunks[i], | ||
|  |                         m_EntityManager.cachedChunks[i], | ||
|  |                         m_EntityManager.drawCallChunks[i], | ||
|  |                         m_EntityManager.entityChunks[i].count); | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         private void Execute(in CameraData cameraData, DecalEntityChunk decalEntityChunk, DecalCachedChunk decalCachedChunk, DecalDrawCallChunk decalDrawCallChunk, int count) | ||
|  |         { | ||
|  |             decalCachedChunk.currentJobHandle.Complete(); | ||
|  |             decalDrawCallChunk.currentJobHandle.Complete(); | ||
|  | 
 | ||
|  |             Material material = GetMaterial(decalEntityChunk); | ||
|  |             int passIndex = GetPassIndex(decalCachedChunk); | ||
|  | 
 | ||
|  |             if (count == 0 || passIndex == -1 || material == null) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             if (SystemInfo.supportsInstancing && material.enableInstancing) | ||
|  |             { | ||
|  |                 DrawInstanced(cameraData, decalEntityChunk, decalCachedChunk, decalDrawCallChunk); | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 Draw(cameraData, decalEntityChunk, decalCachedChunk, decalDrawCallChunk); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         private void Draw(in CameraData cameraData, DecalEntityChunk decalEntityChunk, DecalCachedChunk decalCachedChunk, DecalDrawCallChunk decalDrawCallChunk) | ||
|  |         { | ||
|  |             var mesh = m_EntityManager.decalProjectorMesh; | ||
|  |             var material = GetMaterial(decalEntityChunk); | ||
|  |             int subCallCount = decalDrawCallChunk.subCallCount; | ||
|  |             for (int i = 0; i < subCallCount; ++i) | ||
|  |             { | ||
|  |                 var subCall = decalDrawCallChunk.subCalls[i]; | ||
|  | 
 | ||
|  |                 for (int j = subCall.start; j < subCall.end; ++j) | ||
|  |                 { | ||
|  |                     decalCachedChunk.propertyBlock.SetMatrix("_NormalToWorld", decalDrawCallChunk.normalToDecals[j]); | ||
|  |                     decalCachedChunk.propertyBlock.SetFloat("_DecalLayerMaskFromDecal", decalDrawCallChunk.renderingLayerMasks[j]); | ||
|  |                     // RENDERGRAPH TODO: schedule drawmesh through commandBuffer? | ||
|  |                     Graphics.DrawMesh(mesh, decalDrawCallChunk.decalToWorlds[j], material, decalCachedChunk.layerMasks[j], cameraData.camera, 0, decalCachedChunk.propertyBlock); | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         private void DrawInstanced(in CameraData cameraData, DecalEntityChunk decalEntityChunk, DecalCachedChunk decalCachedChunk, DecalDrawCallChunk decalDrawCallChunk) | ||
|  |         { | ||
|  |             var mesh = m_EntityManager.decalProjectorMesh; | ||
|  |             var material = GetMaterial(decalEntityChunk); | ||
|  |             decalCachedChunk.propertyBlock.SetVector("unity_LightData", new Vector4(1, 1, 1, 0)); // GetMainLight requires z component to be set | ||
|  | 
 | ||
|  |             int subCallCount = decalDrawCallChunk.subCallCount; | ||
|  |             for (int i = 0; i < subCallCount; ++i) | ||
|  |             { | ||
|  |                 var subCall = decalDrawCallChunk.subCalls[i]; | ||
|  | 
 | ||
|  |                 var decalToWorldSlice = decalDrawCallChunk.decalToWorlds.Reinterpret<Matrix4x4>(); | ||
|  |                 NativeArray<Matrix4x4>.Copy(decalToWorldSlice, subCall.start, m_WorldToDecals, 0, subCall.count); | ||
|  | 
 | ||
|  |                 var normalToWorldSlice = decalDrawCallChunk.normalToDecals.Reinterpret<Matrix4x4>(); | ||
|  |                 NativeArray<Matrix4x4>.Copy(normalToWorldSlice, subCall.start, m_NormalToDecals, 0, subCall.count); | ||
|  | 
 | ||
|  |                 var decalLayerMaskSlice = decalDrawCallChunk.renderingLayerMasks.Reinterpret<float>(); | ||
|  |                 NativeArray<float>.Copy(decalLayerMaskSlice, subCall.start, m_DecalLayerMasks, 0, subCall.count); | ||
|  | 
 | ||
|  |                 decalCachedChunk.propertyBlock.SetMatrixArray("_NormalToWorld", m_NormalToDecals); | ||
|  |                 decalCachedChunk.propertyBlock.SetFloatArray("_DecalLayerMaskFromDecal", m_DecalLayerMasks); | ||
|  |                 // RENDERGRAPH TODO: schedule drawmesh through commandBuffer? | ||
|  |                 Graphics.DrawMeshInstanced(mesh, 0, material, | ||
|  |                     m_WorldToDecals, subCall.count, decalCachedChunk.propertyBlock, ShadowCastingMode.On, true, 0, cameraData.camera); | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | } |