332 lines
16 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|