using HTraceWSGI.Scripts.Globals; using HTraceWSGI.Scripts.Pipeline; using HTraceWSGI.Scripts.Structs; using UnityEngine; using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering; using UnityEngine.Rendering.HighDefinition; namespace HTraceWSGI.Scripts.Passes { internal class VoxelizationPassPartial : CustomPass { #region Shaders Properties ID //globals private static readonly int g_OffsetAxisIndex = Shader.PropertyToID("_OffsetAxisIndex"); private static readonly int g_AxisOffset = Shader.PropertyToID("_AxisOffset"); private static readonly int g_CullingTrim = Shader.PropertyToID("_CullingTrim"); private static readonly int g_OctantOffset = Shader.PropertyToID("_OctantOffset"); private static readonly int g_CullingTrimAxis = Shader.PropertyToID("_CullingTrimAxis"); private static readonly int g_VoxelCameraPos = Shader.PropertyToID("_VoxelCameraPos"); private static readonly int g_VoxelCameraPosActual = Shader.PropertyToID("_VoxelCameraPosActual"); private static readonly int g_VoxelResolution = Shader.PropertyToID("_VoxelResolution"); private static readonly int g_VoxelBounds = Shader.PropertyToID("_VoxelBounds"); private static readonly int g_VoxelPerMeter = Shader.PropertyToID("_VoxelPerMeter"); private static readonly int g_VoxelSize = Shader.PropertyToID("_VoxelSize"); private static readonly int g_VoxelizationAABB_Min = Shader.PropertyToID("_VoxelizationAABB_Min"); private static readonly int g_VoxelizationAABB_Max = Shader.PropertyToID("_VoxelizationAABB_Max"); private static readonly int g_DirLightMatrix = Shader.PropertyToID("_DirLightMatrix"); private static readonly int g_HTraceShadowmap = Shader.PropertyToID("_HTraceShadowmap"); private static readonly int g_VoxelData = Shader.PropertyToID("_VoxelData"); private static readonly int g_VoxelPositionPyramid = Shader.PropertyToID("_VoxelPositionPyramid"); //locals private static readonly int _OctantCopyOffset = Shader.PropertyToID("_OctantCopyOffset"); private static readonly int _VoxelOffset = Shader.PropertyToID("_VoxelOffset"); private static readonly int _VoxelData_A = Shader.PropertyToID("_VoxelData_A"); private static readonly int _VoxelData_B = Shader.PropertyToID("_VoxelData_B"); private static readonly int _DirectionalShadowmapStatic = Shader.PropertyToID("_DirectionalShadowmapStatic"); private static readonly int _Shadowmap = Shader.PropertyToID("_Shadowmap"); private static readonly int _Shadowmap_Output = Shader.PropertyToID("_Shadowmap_Output"); private static readonly int _OctantShadowOffset = Shader.PropertyToID("_OctantShadowOffset"); private static readonly int _VoxelPositionPyramid_Mip0 = Shader.PropertyToID("_VoxelPositionPyramid_MIP0"); private static readonly int _VoxelPositionPyramid_Mip1 = Shader.PropertyToID("_VoxelPositionPyramid_MIP1"); private static readonly int _VoxelPositionPyramid_Mip2 = Shader.PropertyToID("_VoxelPositionPyramid_MIP2"); private static readonly int _VoxelPositionIntermediate_Output = Shader.PropertyToID("_VoxelPositionIntermediate_Output"); private static readonly int _VoxelPositionIntermediate = Shader.PropertyToID("_VoxelPositionIntermediate"); private static readonly int _VoxelPositionPyramid_Mip3 = Shader.PropertyToID("_VoxelPositionPyramid_MIP3"); private static readonly int _VoxelPositionPyramid_Mip4 = Shader.PropertyToID("_VoxelPositionPyramid_MIP4"); private static readonly int _VoxelPositionPyramid_Mip5 = Shader.PropertyToID("_VoxelPositionPyramid_MIP5"); #endregion Shaders Properties ID private static readonly ProfilingSampler s_ClearVoxelTexturesProfilingSampler = new ProfilingSampler("Clear Voxel Textures"); private static readonly ProfilingSampler s_CopyVoxelsProfilingSampler = new ProfilingSampler("Copy Voxels"); private static readonly ProfilingSampler s_RenderShadowmapProfilingSampler = new ProfilingSampler("Render Shadowmap"); private static readonly ProfilingSampler s_MergeShadowmapStaticProfilingSampler = new ProfilingSampler("Merge Shadowmap Static"); private static readonly ProfilingSampler s_GeneratePositionPyramidProfilingSampler = new ProfilingSampler("Generate Position Pyramid"); // Shaders & Materials private Shader VoxelizationShader; private Material ShadowmapMaterial; private ComputeShader HVoxelization; private ComputeShader HShadowmap; // Buffers & Textures ComputeBuffer DummyVoxelBuffer; RTHandle DummyVoxelizationStaticTarget; RTHandle DummyVoxelizationDynamicTarget; RTHandle DirectionalDepthTargetCombined; RTHandle DirectionalDepthTargetStatic; RTHandle DirectionalShadowmapStatic; RTHandle VoxelPositionPyramid; RTHandle VoxelPositionIntermediate; RTHandle VoxelData_A; RTHandle VoxelData_B; // Constants & Variables private readonly Vector2 _shadowmapResolution = new Vector2(2048, 2048); private Vector3 _prevCameraPos = Vector3.zero; private int _textureOutputCounter; private int _textureSwapCounter; private int _localFrameCounter; private int _octantSyncCounter; private int _waitCounter; private bool _initialized = false; private void AllocateMainBuffers(bool onlyRelease = false) { void ReleaseBuffersAndTextures() { HExtensions.HRelease(DummyVoxelizationStaticTarget); HExtensions.HRelease(DummyVoxelizationDynamicTarget); HExtensions.HRelease(DirectionalDepthTargetCombined); HExtensions.HRelease(DirectionalDepthTargetStatic); HExtensions.HRelease(DirectionalShadowmapStatic); HExtensions.HRelease(VoxelPositionPyramid); HExtensions.HRelease(VoxelPositionIntermediate); HExtensions.HRelease(VoxelData_A); HExtensions.HRelease(VoxelData_B); HExtensions.HRelease(DummyVoxelBuffer); } if (onlyRelease) { ReleaseBuffersAndTextures(); return; } ReleaseBuffersAndTextures(); DummyVoxelBuffer = new ComputeBuffer(1, sizeof(int)); int voxelResX = HResources.VoxelizationData.ExactData.Resolution.x; int voxelResY = HResources.VoxelizationData.ExactData.Resolution.z; int voxelResZ = HResources.VoxelizationData.ExactData.Resolution.y; DummyVoxelizationStaticTarget = RTHandles.Alloc(voxelResX, voxelResZ, dimension: TextureDimension.Tex2D, colorFormat: GraphicsFormat.R8_UNorm, name: "_DummyVoxelizationStaticTarget"); DummyVoxelizationDynamicTarget = RTHandles.Alloc(voxelResX * 2, voxelResZ * 2, dimension: TextureDimension.Tex2D, colorFormat: GraphicsFormat.R8_UNorm, name: "_DummyVoxelizationDynamicTarget"); DirectionalDepthTargetStatic = RTHandles.Alloc((int)_shadowmapResolution.x / 2, (int)_shadowmapResolution.y / 2, dimension: TextureDimension.Tex2D, colorFormat: GraphicsFormat.R8_SNorm, name: "_DirectionalDepthTargetStatic", depthBufferBits: DepthBits.Depth32); DirectionalDepthTargetCombined = RTHandles.Alloc((int)_shadowmapResolution.x, (int)_shadowmapResolution.y, dimension: TextureDimension.Tex2D, colorFormat: GraphicsFormat.R8_SNorm, name: "_DirectionalDepthTargetCombined", depthBufferBits: DepthBits.Depth32); DirectionalShadowmapStatic = RTHandles.Alloc((int)_shadowmapResolution.x, (int)_shadowmapResolution.y, dimension: TextureDimension.Tex2D, colorFormat: GraphicsFormat.R32_SFloat, name: "_DirectionalShadowmapStatic", enableRandomWrite: true); VoxelPositionPyramid = RTHandles.Alloc(voxelResX, voxelResY, voxelResZ, dimension: TextureDimension.Tex3D, useMipMap: true, autoGenerateMips: false, colorFormat: GraphicsFormat.R8_UInt, name: "_VoxelPositionPyramid", enableRandomWrite: true); VoxelPositionIntermediate = RTHandles.Alloc(voxelResX / 4, voxelResY / 4, voxelResZ / 4, dimension: TextureDimension.Tex3D, useMipMap: false, autoGenerateMips: false, colorFormat: GraphicsFormat.R8_UInt, name: "_VoxelPositionIntermediate", enableRandomWrite: true); VoxelData_A = RTHandles.Alloc(voxelResX, voxelResY, voxelResZ, dimension: TextureDimension.Tex3D, useMipMap: false, autoGenerateMips: false, colorFormat: GraphicsFormat.R32_UInt, name: "_VoxelData_A", enableRandomWrite: true); VoxelData_B = RTHandles.Alloc(voxelResX, voxelResY, voxelResZ, dimension: TextureDimension.Tex3D, useMipMap: false, autoGenerateMips: false, colorFormat: GraphicsFormat.R32_UInt, name: "_VoxelData_B", enableRandomWrite: true); } protected internal void Initialize() { enabled = true; VoxelizationRuntimeData.OnReallocTextures += ReAllocateMainBuffers; ReAllocateMainBuffers(); _initialized = true; } protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd) { name = HTraceNames.HTRACE_VOXEL_PARTIAL_PASS_NAME_FRAME_DEBUG; VoxelizationShader = Shader.Find("HTrace/Voxelization"); ShadowmapMaterial = CoreUtils.CreateEngineMaterial(Shader.Find("HTrace/Shadowmap")); ShadowmapMaterial.enableInstancing = true; HVoxelization = HExtensions.LoadComputeShader("Voxelization"); HShadowmap = HExtensions.LoadComputeShader("Shadowmap"); } private void ReAllocateMainBuffers() { VoxelizationRuntimeData.FullVoxelization = true; AllocateMainBuffers(); } // Calculates offset data for voxelization private void CalculateOctantOffsets(CustomPassContext ctx) { Vector2 cullingTrim = Vector2.zero; Vector2 cullingTrimAxis = Vector2.zero; Vector3 octantOffset = Vector3.zero; Vector3 axisOffset = Vector3.zero; Vector3 voxelResolutionSwizzled = new Vector3(HResources.VoxelizationData.ExactData.Resolution.x, HResources.VoxelizationData.ExactData.Resolution.z, HResources.VoxelizationData.ExactData.Resolution.y); Vector3 axisOffsetSign = VoxelizationRuntimeData.VoxelOctantCamera.transform.position - VoxelizationRuntimeData.VoxelCamera.transform.position; int offsetAxisIndex = (int)VoxelizationRuntimeData.OffsetAxisIndex > 2 ? (int)VoxelizationRuntimeData.OffsetAxisIndex - 3 : (int)VoxelizationRuntimeData.OffsetAxisIndex; int octantIndex = (int)VoxelizationRuntimeData.OctantIndex; if (offsetAxisIndex == 0) // X axis { axisOffset = axisOffsetSign.x > 0 ? new Vector3(voxelResolutionSwizzled.x / 2, 0, 0) : new Vector3(0, 0, 0); int cullingFarPlane = axisOffsetSign.x > 0 ? Mathf.RoundToInt(VoxelizationRuntimeData.CullingCamera.Camera.farClipPlane * HResources.VoxelizationData.ExactData.VoxelsPerMeter) : Mathf.FloorToInt(VoxelizationRuntimeData.CullingCamera.Camera.farClipPlane * HResources.VoxelizationData.ExactData.VoxelsPerMeter); cullingTrim = axisOffsetSign.x > 0 ? new Vector2((int)voxelResolutionSwizzled.x - cullingFarPlane, (int)voxelResolutionSwizzled.x) : new Vector2(0, cullingFarPlane); cullingTrimAxis = axisOffsetSign.x > 0 ? new Vector2(1, 0) : new Vector2(0, 1); if (octantIndex == 1) octantOffset = new Vector3(0, voxelResolutionSwizzled.y / 2, 0); if (octantIndex == 2) octantOffset = new Vector3(0, voxelResolutionSwizzled.y / 2, voxelResolutionSwizzled.z / 2); if (octantIndex == 3) octantOffset = new Vector3(0, 0, 0); if (octantIndex == 4) octantOffset = new Vector3(0, 0, voxelResolutionSwizzled.z / 2); } if (offsetAxisIndex == 1) // Y axis { axisOffset = axisOffsetSign.y > 0 ? new Vector3(0, voxelResolutionSwizzled.y / 2, 0) : new Vector3(0, 0, 0); int cullingFarPlane = axisOffsetSign.y > 0 ? Mathf.RoundToInt(VoxelizationRuntimeData.CullingCamera.Camera.farClipPlane * HResources.VoxelizationData.ExactData.VoxelsPerMeter) : Mathf.FloorToInt(VoxelizationRuntimeData.CullingCamera.Camera.farClipPlane * HResources.VoxelizationData.ExactData.VoxelsPerMeter); cullingTrim = axisOffsetSign.y > 0 ? new Vector2((int)voxelResolutionSwizzled.y - cullingFarPlane, (int)voxelResolutionSwizzled.y) : new Vector2(0, cullingFarPlane); cullingTrimAxis = axisOffsetSign.y > 0 ? new Vector2(1, 0) : new Vector2(0, 1); if (octantIndex == 1) octantOffset = new Vector3(0, 0, 0); if (octantIndex == 2) octantOffset = new Vector3(0, 0, voxelResolutionSwizzled.z / 2); if (octantIndex == 3) octantOffset = new Vector3(voxelResolutionSwizzled.x / 2, 0, 0); if (octantIndex == 4) octantOffset = new Vector3(voxelResolutionSwizzled.x / 2, 0, voxelResolutionSwizzled.z / 2); } if (offsetAxisIndex == 2) // Z axis { axisOffset = axisOffsetSign.z > 0 ? new Vector3(0, 0, voxelResolutionSwizzled.z / 2) : new Vector3(0, 0, 0); int cullingFarPlane = axisOffsetSign.z > 0 ? Mathf.RoundToInt(VoxelizationRuntimeData.CullingCamera.Camera.farClipPlane * HResources.VoxelizationData.ExactData.VoxelsPerMeter) : Mathf.FloorToInt(VoxelizationRuntimeData.CullingCamera.Camera.farClipPlane * HResources.VoxelizationData.ExactData.VoxelsPerMeter); cullingTrim = axisOffsetSign.z > 0 ? new Vector2((int)voxelResolutionSwizzled.z - cullingFarPlane, (int)voxelResolutionSwizzled.z) : new Vector2(0, cullingFarPlane); cullingTrimAxis = axisOffsetSign.z > 0 ? new Vector2(1, 0) : new Vector2(0, 1); if (octantIndex == 1) octantOffset = new Vector3(voxelResolutionSwizzled.x / 2, voxelResolutionSwizzled.y / 2, 0); if (octantIndex == 2) octantOffset = new Vector3(0, voxelResolutionSwizzled.y / 2, 0); if (octantIndex == 3) octantOffset = new Vector3(voxelResolutionSwizzled.x / 2, 0, 0); if (octantIndex == 4) octantOffset = new Vector3(0, 0, 0); } ctx.cmd.SetGlobalInt(g_OffsetAxisIndex, offsetAxisIndex); ctx.cmd.SetGlobalVector(g_AxisOffset, axisOffset); ctx.cmd.SetGlobalVector(g_CullingTrim, cullingTrim); ctx.cmd.SetGlobalVector(g_OctantOffset, octantOffset); ctx.cmd.SetGlobalVector(g_CullingTrimAxis, cullingTrimAxis); } // Calculates offset data for copying compute shader Vector3 CalculateOctantOffsetsForCopyShader() { Vector3 octantOffset = Vector3.zero; Vector3 voxelResolutionSwizzled = new Vector3(HResources.VoxelizationData.ExactData.Resolution.x, HResources.VoxelizationData.ExactData.Resolution.z, HResources.VoxelizationData.ExactData.Resolution.y); Vector3 axisOffsetSign = VoxelizationRuntimeData.VoxelOctantCamera.transform.position - VoxelizationRuntimeData.VoxelCamera.transform.position; int offsetAxisIndex = (int)VoxelizationRuntimeData.OffsetAxisIndex > 2 ? (int)VoxelizationRuntimeData.OffsetAxisIndex - 3 : (int)VoxelizationRuntimeData.OffsetAxisIndex; int octantIndex = (int)VoxelizationRuntimeData.OctantIndex; if (offsetAxisIndex == 0) // X axis { if (axisOffsetSign.x < 0) { if (octantIndex == 1) octantOffset = new Vector3(0, 0, 0); if (octantIndex == 2) octantOffset = new Vector3(0, 0, voxelResolutionSwizzled.z / 2); if (octantIndex == 3) octantOffset = new Vector3(voxelResolutionSwizzled.x / 2, 0, voxelResolutionSwizzled.z / 2); if (octantIndex == 4) octantOffset = new Vector3(voxelResolutionSwizzled.x / 2, 0, 0); } else { if (octantIndex == 1) octantOffset = new Vector3(voxelResolutionSwizzled.x / 2, 0, 0); if (octantIndex == 2) octantOffset = new Vector3(voxelResolutionSwizzled.x / 2, 0, voxelResolutionSwizzled.z / 2); if (octantIndex == 3) octantOffset = new Vector3(0, 0, 0); if (octantIndex == 4) octantOffset = new Vector3(0, 0, voxelResolutionSwizzled.z / 2); } } if (offsetAxisIndex == 1) // Y axis { if (octantIndex == 1) octantOffset = new Vector3(0, 0, 0); if (octantIndex == 2) octantOffset = new Vector3(0, 0, voxelResolutionSwizzled.z / 2); if (octantIndex == 3) octantOffset = new Vector3(voxelResolutionSwizzled.x / 2, 0, 0); if (octantIndex == 4) octantOffset = new Vector3(voxelResolutionSwizzled.x / 2, 0, voxelResolutionSwizzled.z / 2); } if (offsetAxisIndex == 2) // Z axis { if (axisOffsetSign.z < 0) { if (octantIndex == 1) octantOffset = new Vector3(voxelResolutionSwizzled.x / 2, 0, 0); if (octantIndex == 2) octantOffset = new Vector3(0, 0, 0); if (octantIndex == 3) octantOffset = new Vector3(0, 0, voxelResolutionSwizzled.z / 2); if (octantIndex == 4) octantOffset = new Vector3(voxelResolutionSwizzled.x / 2, 0, voxelResolutionSwizzled.z / 2); } else { if (octantIndex == 1) octantOffset = new Vector3(voxelResolutionSwizzled.x / 2, 0, voxelResolutionSwizzled.z / 2); if (octantIndex == 2) octantOffset = new Vector3(0, 0, voxelResolutionSwizzled.z / 2); if (octantIndex == 3) octantOffset = new Vector3(0, 0, 0); if (octantIndex == 4) octantOffset = new Vector3(voxelResolutionSwizzled.x / 2, 0, 0); } } return octantOffset; } protected override void Execute(CustomPassContext ctx) { if (ctx.hdCamera.camera.cameraType == CameraType.Reflection || _initialized == false) return; #if UNITY_EDITOR if (UnityEditor.EditorApplication.isPaused && VoxelizationRuntimeData.OctantIndex != OctantIndex.DynamicObjects) return; if (HExtensions.PipelineSupportsSSGI == false) return; #endif if (VoxelizationRuntimeData.VoxelCamera == null || VoxelizationRuntimeData.FakeDirectionalCamera == null) return; VoxelizationRuntimeData.VoxelCamera.ExecuteUpdate(ctx.hdCamera.camera); // Wait for the start of the cycle to do full voxelization if (VoxelizationRuntimeData.FullVoxelization == true && (int)VoxelizationRuntimeData.OctantIndex > 1) return; if (VoxelizationRuntimeData.FullVoxelization != true) // TODO: once framecounter is fixed revisit it and remove if possible { // Reset sync counter at the end of every cycle if (_octantSyncCounter == 5) _octantSyncCounter = 0; // Increment wait counter after each index = 1 if ((int)VoxelizationRuntimeData.OctantIndex == 1) _waitCounter++; // Cycle is still broken, skip and wait if (_waitCounter < 1) return; // Cycle went out of sync, skip and wait if (_localFrameCounter != 0 && (int)VoxelizationRuntimeData.OctantIndex != _octantSyncCounter + 1) return; // Set sync counter to the current octant index _octantSyncCounter = (int)VoxelizationRuntimeData.OctantIndex; } bool isFullVoxelization = VoxelizationRuntimeData.FullVoxelization; bool isDynamicOctant = (int)VoxelizationRuntimeData.OctantIndex == 5 ? true : false; bool isFirstOctant = (int)VoxelizationRuntimeData.OctantIndex == 1 ? true : false; // Swap counter, flips at the start of every cycle if (isFirstOctant && !isFullVoxelization) _textureSwapCounter++; // Output counter, flips at the end of every cycle if (isDynamicOctant && !isFullVoxelization) _textureOutputCounter++; // Clear 3D textures using (new ProfilingScope(ctx.cmd, s_ClearVoxelTexturesProfilingSampler)) { if (isDynamicOctant || isFullVoxelization) { CoreUtils.SetRenderTarget(ctx.cmd, VoxelPositionPyramid, ClearFlag.Color, Color.clear, 0, CubemapFace.Unknown, -1); CoreUtils.SetRenderTarget(ctx.cmd, VoxelPositionPyramid, ClearFlag.Color, Color.clear, 1, CubemapFace.Unknown, -1); CoreUtils.SetRenderTarget(ctx.cmd, VoxelPositionPyramid, ClearFlag.Color, Color.clear, 2, CubemapFace.Unknown, -1); CoreUtils.SetRenderTarget(ctx.cmd, VoxelPositionPyramid, ClearFlag.Color, Color.clear, 3, CubemapFace.Unknown, -1); CoreUtils.SetRenderTarget(ctx.cmd, VoxelPositionPyramid, ClearFlag.Color, Color.clear, 4, CubemapFace.Unknown, -1); CoreUtils.SetRenderTarget(ctx.cmd, VoxelPositionPyramid, ClearFlag.Color, Color.clear, 5, CubemapFace.Unknown, -1); CoreUtils.SetRenderTarget(ctx.cmd, VoxelPositionIntermediate, ClearFlag.Color, Color.clear, 0, CubemapFace.Unknown, -1); } if (isFirstOctant || isFullVoxelization) CoreUtils.SetRenderTarget(ctx.cmd, _textureSwapCounter % 2 == 0 ? VoxelData_B : VoxelData_A, ClearFlag.Color, Color.clear, 0, CubemapFace.Unknown, -1); } // Pass voxel camera pos to shaders at the end of the cycle if (isDynamicOctant || isFullVoxelization) ctx.cmd.SetGlobalVector(g_VoxelCameraPos, VoxelizationRuntimeData.VoxelCamera.transform.position); // Pass actual voxel camera pos to voxelization shader for geometry trimming if (isFirstOctant || isFullVoxelization) ctx.cmd.SetGlobalVector(g_VoxelCameraPosActual, VoxelizationRuntimeData.VoxelCamera.transform.position); // Scroll voxels by copying them using (new ProfilingScope(ctx.cmd, s_CopyVoxelsProfilingSampler)) { if (!isDynamicOctant && !isFullVoxelization) { Vector3 octantCopyOffset = CalculateOctantOffsetsForCopyShader(); int voxelCopyKernel = HVoxelization.FindKernel("CopyData"); ctx.cmd.SetComputeVectorParam(HVoxelization, _OctantCopyOffset, octantCopyOffset); ctx.cmd.SetComputeVectorParam(HVoxelization, _VoxelOffset, VoxelizationRuntimeData.VoxelCamera.transform.position - _prevCameraPos); ctx.cmd.SetComputeTextureParam(HVoxelization, voxelCopyKernel, _VoxelData_A, _textureSwapCounter % 2 == 0 ? VoxelData_B : VoxelData_A); ctx.cmd.SetComputeTextureParam(HVoxelization, voxelCopyKernel, _VoxelData_B, _textureSwapCounter % 2 == 0 ? VoxelData_A : VoxelData_B); ctx.cmd.DispatchCompute(HVoxelization, voxelCopyKernel, Mathf.CeilToInt(HResources.VoxelizationData.ExactData.Resolution.x / 8f / 2), Mathf.CeilToInt(HResources.VoxelizationData.ExactData.Resolution.z / 4f / 2), Mathf.CeilToInt(HResources.VoxelizationData.ExactData.Resolution.y / 8f / 2)); } } // Cache main camera matrices var viewMatrixCached = ctx.hdCamera.camera.worldToCameraMatrix; var projectionMatrixCached = ctx.hdCamera.camera.projectionMatrix; // Render voxels if (true) { // Pass main voxelization parameters to shaders ctx.cmd.SetGlobalVector(g_VoxelResolution, (Vector3)HResources.VoxelizationData.ExactData.Resolution); ctx.cmd.SetGlobalVector(g_VoxelBounds, HResources.VoxelizationData.ExactData.Bounds); ctx.cmd.SetGlobalFloat(g_VoxelPerMeter, HResources.VoxelizationData.ExactData.VoxelsPerMeter); ctx.cmd.SetGlobalFloat(g_VoxelSize, HResources.VoxelizationData.ExactData.VoxelSize); Vector3 BoundsSwizzled = new Vector3(HResources.VoxelizationData.ExactData.Bounds.x, HResources.VoxelizationData.ExactData.Bounds.z, HResources.VoxelizationData.ExactData.Bounds.y); Bounds voxelizationAABB = new Bounds(VoxelizationRuntimeData.VoxelCamera.transform.position, BoundsSwizzled); ctx.cmd.SetGlobalVector(g_VoxelizationAABB_Min, voxelizationAABB.min); ctx.cmd.SetGlobalVector(g_VoxelizationAABB_Max, voxelizationAABB.max); // Load our culling & voxelization camera Camera cullingCamera = isFullVoxelization ? VoxelizationRuntimeData.VoxelCamera.Camera : VoxelizationRuntimeData.CullingCamera.Camera; Camera voxelizationCamera = isFullVoxelization ? VoxelizationRuntimeData.VoxelCamera.Camera : VoxelizationRuntimeData.VoxelOctantCamera.Camera; if (cullingCamera.farClipPlane > 0) { // Set voxelization camera matrices ctx.cmd.SetViewProjectionMatrices(voxelizationCamera.worldToCameraMatrix, voxelizationCamera.projectionMatrix); // Calculate octant offsets if ((int)VoxelizationRuntimeData.OctantIndex != 5) CalculateOctantOffsets(ctx); // Set rendering targets ctx.cmd.ClearRandomWriteTargets(); ctx.cmd.SetRandomWriteTarget(1, _textureSwapCounter % 2 == 0 ? VoxelData_B : VoxelData_A); ctx.cmd.SetRandomWriteTarget(2, DummyVoxelBuffer, false); #if UNITY_6000_0_OR_NEWER ScriptableRenderContext.PopDisableApiRenderers(); #endif // Prepare culling params and select LOD level cullingCamera.TryGetCullingParameters(out ScriptableCullingParameters voxelizationCullingParams); voxelizationCullingParams.cullingOptions = CullingOptions.None; voxelizationCullingParams.isOrthographic = true; LODParameters lodParameters = voxelizationCullingParams.lodParameters; lodParameters.cameraPosition = voxelizationCamera.transform.position; lodParameters.isOrthographic = true; lodParameters.orthoSize = 0; voxelizationCullingParams.lodParameters = lodParameters; QualitySettings.SetLODSettings(1, HResources.VoxelizationData.LODMax, false); // Cull meshes ctx.cullingResults = ctx.renderContext.Cull(ref voxelizationCullingParams); #if UNITY_6000_0_OR_NEWER ScriptableRenderContext.PushDisableApiRenderers(); #endif LayerMask voxelizationLayer = HResources.VoxelizationData.VoxelizationMask & ~HResources.VoxelizationData.DynamicObjectsMask; var voxelizationRenderTarget = DummyVoxelizationStaticTarget; int voxelizationShaderPass = 0; Shader.EnableKeyword("PARTIAL_VOXELIZATION"); Shader.DisableKeyword("DYNAMIC_VOXELIZATION"); Shader.DisableKeyword("CONSTANT_VOXELIZATION"); if (isFullVoxelization) { voxelizationRenderTarget = DummyVoxelizationDynamicTarget; voxelizationShaderPass = 0; Shader.EnableKeyword("CONSTANT_VOXELIZATION"); Shader.DisableKeyword("PARTIAL_VOXELIZATION"); Shader.DisableKeyword("DYNAMIC_VOXELIZATION"); } else if ((int)VoxelizationRuntimeData.OctantIndex == 5) { voxelizationLayer = HResources.VoxelizationData.DynamicObjectsMask & HResources.VoxelizationData.VoxelizationMask; voxelizationRenderTarget = DummyVoxelizationDynamicTarget; voxelizationShaderPass = 0; Shader.EnableKeyword("DYNAMIC_VOXELIZATION"); Shader.DisableKeyword("PARTIAL_VOXELIZATION"); Shader.DisableKeyword("CONSTANT_VOXELIZATION"); } // Render voxels RenderingExtensions.RenderVoxels(ctx, voxelizationCamera, voxelizationRenderTarget, voxelizationLayer, OverriderShader: VoxelizationShader, OverrideMaterial: null, voxelizationShaderPass); // Reset rendering targets ctx.cmd.ClearRandomWriteTargets(); } } // Render directional light shadowmap using (new ProfilingScope(ctx.cmd, s_RenderShadowmapProfilingSampler)) { // Load our directional light camera and set its matrices var directionalLightCamera = VoxelizationRuntimeData.FakeDirectionalCamera.GetDirectionalCamera; ctx.cmd.SetViewProjectionMatrices(directionalLightCamera.worldToCameraMatrix, directionalLightCamera.projectionMatrix); #if UNITY_6000_0_OR_NEWER ScriptableRenderContext.PopDisableApiRenderers(); #endif // Prepare culling params and select LOD level directionalLightCamera.TryGetCullingParameters(out ScriptableCullingParameters shadowCullingParams); shadowCullingParams.cullingOptions = CullingOptions.None; shadowCullingParams.isOrthographic = true; LODParameters lodParameters = shadowCullingParams.lodParameters; lodParameters.cameraPosition = directionalLightCamera.transform.position; lodParameters.isOrthographic = true; lodParameters.orthoSize = 0; shadowCullingParams.lodParameters = lodParameters; // Cull meshes ctx.cullingResults = ctx.renderContext.Cull(ref shadowCullingParams); #if UNITY_6000_0_OR_NEWER ScriptableRenderContext.PushDisableApiRenderers(); #endif LayerMask shadowmapLayer = HResources.VoxelizationData.VoxelizationMask & ~HResources.VoxelizationData.DynamicObjectsMask; RTHandle shadowmapRenderTarget = DirectionalDepthTargetStatic; ClearFlag clearDepthFlag = ClearFlag.Depth; if ((int)VoxelizationRuntimeData.OctantIndex == 5) { // Pass directional light matrices to shaders for shadowmap sampling at hit points var viewMatrix = directionalLightCamera.worldToCameraMatrix; var projectionMatrix = directionalLightCamera.projectionMatrix; projectionMatrix = GL.GetGPUProjectionMatrix(projectionMatrix, false); ctx.cmd.SetGlobalMatrix(g_DirLightMatrix, projectionMatrix * viewMatrix); // Copy merged static depth to the final depth render target where dynamic objects will be added ShadowmapMaterial.SetTexture(_DirectionalShadowmapStatic, DirectionalShadowmapStatic); CoreUtils.SetRenderTarget(ctx.cmd, DirectionalDepthTargetCombined, ClearFlag.Depth, 0, CubemapFace.Unknown, -1); CoreUtils.DrawFullScreen(ctx.cmd, ShadowmapMaterial, DirectionalDepthTargetCombined, DirectionalDepthTargetCombined, shaderPassId: 1, properties: ctx.propertyBlock); shadowmapLayer = HResources.VoxelizationData.DynamicObjectsMask; shadowmapRenderTarget = DirectionalDepthTargetCombined; clearDepthFlag = ClearFlag.None; } // Render shadowmap RenderingExtensions.RenderShadowmap(ctx, directionalLightCamera, shadowmapRenderTarget, shadowmapRenderTarget, shadowmapLayer, OverriderShader: null, OverrideMaterial: ShadowmapMaterial, ClearFlag: clearDepthFlag, UseShadowCasterPass: true); } // Merge shadowmap octants with static objects into a single texture using (new ProfilingScope(ctx.cmd, s_MergeShadowmapStaticProfilingSampler)) { if ((int)VoxelizationRuntimeData.OctantIndex != 5) { Vector2 octantShadowOffset = Vector2.zero; int octantIndex = (int)VoxelizationRuntimeData.OctantIndex; if (octantIndex == 1) octantShadowOffset = new Vector2(0, _shadowmapResolution.y / 2); if (octantIndex == 2) octantShadowOffset = new Vector2(_shadowmapResolution.x / 2, _shadowmapResolution.y / 2); if (octantIndex == 3) octantShadowOffset = new Vector2(0, 0); if (octantIndex == 4) octantShadowOffset = new Vector2(_shadowmapResolution.x / 2, 0); int shadowmapMerge_Kernel = HShadowmap.FindKernel("ShadowmapMerge"); ctx.cmd.SetComputeTextureParam(HShadowmap, shadowmapMerge_Kernel, _Shadowmap, DirectionalDepthTargetStatic); ctx.cmd.SetComputeTextureParam(HShadowmap, shadowmapMerge_Kernel, _Shadowmap_Output, DirectionalShadowmapStatic); ctx.cmd.SetComputeVectorParam(HShadowmap, _OctantShadowOffset, octantShadowOffset); ctx.cmd.DispatchCompute(HShadowmap, shadowmapMerge_Kernel, (int)_shadowmapResolution.x / 2 / 8, (int)_shadowmapResolution.y / 2 / 8, 1); } } // Pass rendered shadowmap to shaders ctx.cmd.SetGlobalTexture(g_HTraceShadowmap, DirectionalDepthTargetCombined); // Restore matrices and culling of the main camera ctx.cmd.SetViewProjectionMatrices(viewMatrixCached, projectionMatrixCached); ctx.cullingResults = ctx.cameraCullingResults; // Generate mip pyramid for 3D position texture using (new ProfilingScope(ctx.cmd, s_GeneratePositionPyramidProfilingSampler)) { if (isDynamicOctant || isFullVoxelization) { // Generate 0-2 mip levels int positionPyramid1_Kernel = HVoxelization.FindKernel("GeneratePositionPyramid1"); ctx.cmd.SetComputeTextureParam(HVoxelization, positionPyramid1_Kernel, g_VoxelData, _textureSwapCounter % 2 == 0 ? VoxelData_B : VoxelData_A); ctx.cmd.SetComputeTextureParam(HVoxelization, positionPyramid1_Kernel, _VoxelPositionPyramid_Mip0, VoxelPositionPyramid, 0); ctx.cmd.SetComputeTextureParam(HVoxelization, positionPyramid1_Kernel, _VoxelPositionPyramid_Mip1, VoxelPositionPyramid, 1); ctx.cmd.SetComputeTextureParam(HVoxelization, positionPyramid1_Kernel, _VoxelPositionPyramid_Mip2, VoxelPositionPyramid, 2); ctx.cmd.SetComputeTextureParam(HVoxelization, positionPyramid1_Kernel, _VoxelPositionIntermediate_Output, VoxelPositionIntermediate); ctx.cmd.DispatchCompute(HVoxelization, positionPyramid1_Kernel, Mathf.CeilToInt(HResources.VoxelizationData.ExactData.Resolution.x / 8f), Mathf.CeilToInt(HResources.VoxelizationData.ExactData.Resolution.z / 8f), Mathf.CeilToInt(HResources.VoxelizationData.ExactData.Resolution.y / 8f)); // Generate 3-5 mip levels int positionPyramid2_Kernel = HVoxelization.FindKernel("GeneratePositionPyramid2"); ctx.cmd.SetComputeTextureParam(HVoxelization, positionPyramid2_Kernel, _VoxelPositionIntermediate, VoxelPositionIntermediate); ctx.cmd.SetComputeTextureParam(HVoxelization, positionPyramid2_Kernel, _VoxelPositionPyramid_Mip3, VoxelPositionPyramid, 3); ctx.cmd.SetComputeTextureParam(HVoxelization, positionPyramid2_Kernel, _VoxelPositionPyramid_Mip4, VoxelPositionPyramid, 4); ctx.cmd.SetComputeTextureParam(HVoxelization, positionPyramid2_Kernel, _VoxelPositionPyramid_Mip5, VoxelPositionPyramid, 5); ctx.cmd.DispatchCompute(HVoxelization, positionPyramid2_Kernel, Mathf.CeilToInt(HResources.VoxelizationData.ExactData.Resolution.x / 32f), Mathf.CeilToInt(HResources.VoxelizationData.ExactData.Resolution.z / 32f), Mathf.CeilToInt(HResources.VoxelizationData.ExactData.Resolution.y / 32f)); } } if (isDynamicOctant || isFullVoxelization) _prevCameraPos = VoxelizationRuntimeData.VoxelCamera.transform.position; // Pass voxelized textures to shaders in the Main Pass ctx.cmd.SetGlobalTexture(g_VoxelPositionPyramid, VoxelPositionPyramid); ctx.cmd.SetGlobalTexture(g_VoxelData, _textureOutputCounter % 2 == 0 ? VoxelData_B : VoxelData_A); // Copy to the opposite data buffer to make sure we have full voxelization in both of them if (isFullVoxelization) ctx.cmd.CopyTexture(_textureSwapCounter % 2 == 0 ? VoxelData_B : VoxelData_A, _textureSwapCounter % 2 == 0 ? VoxelData_A : VoxelData_B); VoxelizationRuntimeData.FullVoxelization = false; _localFrameCounter++; } // We don't need Cleanup here because all buffers in this pass are allocated with explicit (e.g. 512 x 512) res // and not with a scale factor (e.g. 1.0), so we don't get "RTHandleSystem.Initialize should be called once..." error. protected internal void Release() { AllocateMainBuffers(true); VoxelizationRuntimeData.OnReallocTextures -= ReAllocateMainBuffers; _initialized = false; } } }