636 lines
33 KiB
C#
636 lines
33 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|