Files
HauntedBloodlines/Assets/HTraceWSGI/Scripts/Passes/VoxelizationPassConstant.cs
2025-05-29 22:31:40 +03:00

332 lines
16 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 VoxelizationPassConstant : CustomPass
{
#region Shaders Properties ID
//globals
private static readonly int g_VoxelCameraPos = Shader.PropertyToID("_VoxelCameraPos");
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_DirLightPlanes = Shader.PropertyToID("_DirLightPlanes");
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 _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_RenderShadowmapProfilingSampler = new ProfilingSampler("Render Shadowmap");
private static readonly ProfilingSampler s_GeneratePositionPyramidProfilingSampler = new ProfilingSampler("Generate Position Pyramid");
// Shaders & Materials
private Shader VoxelizationShader;
private Material ShadowmapMaterial;
private ComputeShader HVoxelization;
// Buffers & Textures
ComputeBuffer DummyVoxelBuffer;
RTHandle DummyVoxelizationTarget;
RTHandle DirectionalDepthTarget;
RTHandle VoxelPositionPyramid;
RTHandle VoxelPositionIntermediate;
RTHandle VoxelData;
// Constants & Variables
private readonly Vector2 ShadowmapResolution = new Vector2(2048, 2048);
private bool _initialized = false;
private void AllocateMainBuffers(bool onlyRelease = false)
{
void ReleaseBuffersAndTextures()
{
HExtensions.HRelease(DummyVoxelizationTarget);
HExtensions.HRelease(DirectionalDepthTarget);
HExtensions.HRelease(VoxelPositionPyramid);
HExtensions.HRelease(VoxelPositionIntermediate);
HExtensions.HRelease(VoxelData);
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;
DummyVoxelizationTarget = RTHandles.Alloc(VoxelResX * 2, VoxelResZ * 2, dimension: TextureDimension.Tex2D,
colorFormat: GraphicsFormat.R8_UNorm, name: "_DummyVoxelizationDynamicTarget");
DirectionalDepthTarget = RTHandles.Alloc((int)ShadowmapResolution.x, (int)ShadowmapResolution.y, dimension: TextureDimension.Tex2D,
colorFormat: GraphicsFormat.R8_SNorm, name: "_DirectionalDepthTargetCombined", depthBufferBits: DepthBits.Depth32);
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 = RTHandles.Alloc(VoxelResX, VoxelResY, VoxelResZ, dimension: TextureDimension.Tex3D, useMipMap: false, autoGenerateMips: false,
colorFormat: GraphicsFormat.R32_UInt, name: "_VoxelData", 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_CONSTANT_PASS_NAME_FRAME_DEBUG;
VoxelizationShader = Shader.Find("HTrace/Voxelization");
ShadowmapMaterial = CoreUtils.CreateEngineMaterial(Shader.Find("HTrace/Shadowmap"));
ShadowmapMaterial.enableInstancing = true;
HVoxelization = HExtensions.LoadComputeShader("Voxelization");
}
private void ReAllocateMainBuffers()
{
VoxelizationRuntimeData.FullVoxelization = true;
AllocateMainBuffers();
}
protected override void Execute(CustomPassContext ctx)
{
if (ctx.hdCamera.camera.cameraType == CameraType.Reflection || _initialized == false)
return;
#if UNITY_EDITOR
if (HExtensions.PipelineSupportsSSGI == false)
return;
#endif
if (VoxelizationRuntimeData.VoxelCamera == null || VoxelizationRuntimeData.FakeDirectionalCamera == null)
return;
VoxelizationRuntimeData.VoxelCamera.ExecuteUpdate(ctx.hdCamera.camera);
// Clear 3D textures
using (new ProfilingScope(ctx.cmd, s_ClearVoxelTexturesProfilingSampler))
{
CoreUtils.SetRenderTarget(ctx.cmd, VoxelData, ClearFlag.Color, Color.clear, 0, CubemapFace.Unknown, -1);
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);
}
// Pass voxel camera pos to shaders
ctx.cmd.SetGlobalVector(g_VoxelCameraPos, VoxelizationRuntimeData.VoxelCamera.transform.position);
// Cache main camera matrices
var viewMatrixCached = ctx.hdCamera.camera.worldToCameraMatrix;
var projectionMatrixCached = ctx.hdCamera.camera.projectionMatrix;
// Load our voxelization camera //
var voxelizationCamera = VoxelizationRuntimeData.VoxelCamera.Camera;
// 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);
if (voxelizationCamera.farClipPlane > 0)
{
// Set voxelization camera matrices
ctx.cmd.SetViewProjectionMatrices(voxelizationCamera.worldToCameraMatrix, voxelizationCamera.projectionMatrix);
// Set rendering targets
ctx.cmd.ClearRandomWriteTargets();
ctx.cmd.SetRandomWriteTarget(1, VoxelData);
ctx.cmd.SetRandomWriteTarget(2, DummyVoxelBuffer, false);
#if UNITY_6000_0_OR_NEWER
ScriptableRenderContext.PopDisableApiRenderers();
#endif
// Prepare culling params and select LOD level
voxelizationCamera.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
// Set voxelization layer, render target and select shader pass
LayerMask voxelizationLayer = HResources.VoxelizationData.VoxelizationMask;
RTHandle voxelizationRenderTarget = DummyVoxelizationTarget;
int voxelizationShaderPass = 0;
Shader.EnableKeyword("CONSTANT_VOXELIZATION");
Shader.DisableKeyword("PARTIAL_VOXELIZATION");
Shader.DisableKeyword("DYNAMIC_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 = voxelizationCamera.transform.position;
lodParameters.isOrthographic = true;
lodParameters.orthoSize = 0;
shadowCullingParams.lodParameters = lodParameters;
//QualitySettings.SetLODSettings(1, VoxelizationData.LODMax, false);
// Cull meshes
ctx.cullingResults = ctx.renderContext.Cull(ref shadowCullingParams);
#if UNITY_6000_0_OR_NEWER
ScriptableRenderContext.PushDisableApiRenderers();
#endif
LayerMask shadowmapLayer = HResources.VoxelizationData.VoxelizationMask;
var shadowmapRenderTarget = DirectionalDepthTarget;
ClearFlag clearDepthFlag = ClearFlag.Depth;
// 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);
ctx.cmd.SetGlobalVector(g_DirLightPlanes, new Vector2(directionalLightCamera.nearClipPlane, directionalLightCamera.farClipPlane));
// Render shadowmap
RenderingExtensions.RenderShadowmap(ctx, directionalLightCamera, shadowmapRenderTarget, shadowmapRenderTarget, shadowmapLayer,
OverriderShader: null, OverrideMaterial: ShadowmapMaterial, ClearFlag: clearDepthFlag, UseShadowCasterPass: true);
}
// Pass rendered shadowmap to shaders
ctx.cmd.SetGlobalTexture(g_HTraceShadowmap, DirectionalDepthTarget);
// 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))
{
// Generate 0-2 mip levels
int positionPyramid1_Kernel = HVoxelization.FindKernel("GeneratePositionPyramid1");
ctx.cmd.SetComputeTextureParam(HVoxelization, positionPyramid1_Kernel, g_VoxelData, VoxelData);
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));
}
// Pass voxelized textures to shaders in the Main Pass
ctx.cmd.SetGlobalTexture(g_VoxelPositionPyramid, VoxelPositionPyramid);
ctx.cmd.SetGlobalTexture(g_VoxelData, VoxelData);
VoxelizationRuntimeData.FullVoxelization = false;
}
// 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;
}
}
}