You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
271 lines
15 KiB
271 lines
15 KiB
using Unity.Mathematics;
|
|
using UnityEngine.Experimental.Rendering;
|
|
using UnityEngine.Rendering.RenderGraphModule;
|
|
using static Unity.Mathematics.math;
|
|
|
|
namespace UnityEngine.Rendering.HighDefinition
|
|
{
|
|
partial class VolumetricCloudsSystem
|
|
{
|
|
struct VolumetricCloudsShadowRegion
|
|
{
|
|
public bool valid;
|
|
public float3 origin;
|
|
public float3 dirX;
|
|
public float3 dirY;
|
|
public float3 lightDir;
|
|
public float2 regionSize;
|
|
public float fallbackValue;
|
|
}
|
|
|
|
// The set of kernels that are required
|
|
ComputeShader m_VolumetricCloudsTraceShadowsCS;
|
|
int m_TraceVolumetricCloudsShadowsKernel;
|
|
ComputeShader m_VolumetricCloudsShadowFilterCS;
|
|
int m_FilterShadowCloudsKernel;
|
|
|
|
// Shadow Region for the current frame
|
|
VolumetricCloudsShadowRegion m_VolumetricCloudsShadowRegion = new VolumetricCloudsShadowRegion();
|
|
|
|
void InitializeVolumetricCloudsShadows()
|
|
{
|
|
// Grab the kernels we need
|
|
m_VolumetricCloudsTraceShadowsCS = m_RuntimeResources.volumetricCloudsTraceShadowsCS;
|
|
m_TraceVolumetricCloudsShadowsKernel = m_VolumetricCloudsTraceShadowsCS.FindKernel("TraceVolumetricCloudsShadows");
|
|
m_VolumetricCloudsShadowFilterCS = m_RuntimeResources.volumetricCloudsShadowFilterCS;
|
|
m_FilterShadowCloudsKernel = m_VolumetricCloudsShadowFilterCS.FindKernel("FilterVolumetricCloudsShadow");
|
|
|
|
// Invalidate the shadow region
|
|
m_VolumetricCloudsShadowRegion.valid = false;
|
|
}
|
|
|
|
bool HasVolumetricCloudsShadows(HDCamera hdCamera, in VolumetricClouds settings)
|
|
{
|
|
if (!HasVolumetricClouds(hdCamera, settings) || !settings.shadows.value)
|
|
return false;
|
|
|
|
var sunLight = m_RenderPipeline.GetMainLight();
|
|
var additionalData = m_RenderPipeline.GetMainLightAdditionalData();
|
|
return sunLight != null && sunLight.shadows != LightShadows.None && additionalData.shadowDimmer != 0.0f;
|
|
}
|
|
|
|
internal void EvaluateShadowRegionData(HDCamera hdCamera, CommandBuffer cmd)
|
|
{
|
|
// Invalidate the region in case something goes wrong
|
|
m_VolumetricCloudsShadowRegion.valid = false;
|
|
VolumetricClouds settings = hdCamera.volumeStack.GetComponent<VolumetricClouds>();
|
|
|
|
// Grab the light and make sure it is valid
|
|
if (!HasVolumetricCloudsShadows(hdCamera, in settings))
|
|
{
|
|
// Bind the invalid volumetric clouds shadow texture
|
|
cmd.SetGlobalTexture(HDShaderIDs._VolumetricCloudsShadowsTexture, Texture2D.blackTexture);
|
|
return;
|
|
}
|
|
|
|
// Grab the volume profile of the volumetric clouds
|
|
Light targetLight = m_RenderPipeline.GetMainLight();
|
|
Matrix4x4 wsToLSMat = targetLight.transform.worldToLocalMatrix;
|
|
Matrix4x4 lsToWSMat = targetLight.transform.localToWorldMatrix;
|
|
|
|
// Generate the light space bounds of the camera frustum
|
|
Bounds lightSpaceBounds = new Bounds();
|
|
lightSpaceBounds.SetMinMax(new Vector3(float.MaxValue, float.MaxValue, float.MaxValue), new Vector3(-float.MaxValue, -float.MaxValue, -float.MaxValue));
|
|
lightSpaceBounds.Encapsulate(wsToLSMat.MultiplyPoint(hdCamera.camera.transform.position));
|
|
float perspectiveCorrectedShadowDistance = settings.shadowDistance.value / cos(hdCamera.camera.fieldOfView * Mathf.Deg2Rad * 0.5f);
|
|
for (int cornerIdx = 0; cornerIdx < 4; ++cornerIdx)
|
|
{
|
|
Vector3 corner = hdCamera.frustum.corners[cornerIdx + 4];
|
|
float diag = corner.magnitude;
|
|
corner = corner / diag * Mathf.Min(perspectiveCorrectedShadowDistance, diag);
|
|
Vector3 posLightSpace = wsToLSMat.MultiplyPoint(corner + hdCamera.camera.transform.position);
|
|
lightSpaceBounds.Encapsulate(posLightSpace);
|
|
}
|
|
|
|
// If ray tracing and extended shadow culling is enabled, let's extended the shadow area
|
|
RayTracingSettings rtSettings = hdCamera.volumeStack.GetComponent<RayTracingSettings>();
|
|
if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.RayTracing) && rtSettings.extendShadowCulling.value)
|
|
{
|
|
for (int cornerIdx = 0; cornerIdx < 4; ++cornerIdx)
|
|
{
|
|
Vector3 corner = hdCamera.frustum.corners[cornerIdx + 4];
|
|
float diag = corner.magnitude;
|
|
corner = corner / diag * Mathf.Min(perspectiveCorrectedShadowDistance, diag);
|
|
Vector3 posLightSpace = wsToLSMat.MultiplyPoint(-corner + hdCamera.camera.transform.position);
|
|
lightSpaceBounds.Encapsulate(posLightSpace);
|
|
}
|
|
}
|
|
|
|
// Compute the four corners we need
|
|
float3 c0 = lsToWSMat.MultiplyPoint(lightSpaceBounds.center + new Vector3(-lightSpaceBounds.extents.x, -lightSpaceBounds.extents.y, lightSpaceBounds.extents.z));
|
|
float3 c1 = lsToWSMat.MultiplyPoint(lightSpaceBounds.center + new Vector3(lightSpaceBounds.extents.x, -lightSpaceBounds.extents.y, lightSpaceBounds.extents.z));
|
|
float3 c2 = lsToWSMat.MultiplyPoint(lightSpaceBounds.center + new Vector3(-lightSpaceBounds.extents.x, lightSpaceBounds.extents.y, lightSpaceBounds.extents.z));
|
|
|
|
// Evaluate the shadow region
|
|
m_VolumetricCloudsShadowRegion.origin = c0;
|
|
m_VolumetricCloudsShadowRegion.dirX = c1 - c0;
|
|
m_VolumetricCloudsShadowRegion.dirY = c2 - c0;
|
|
m_VolumetricCloudsShadowRegion.lightDir = -targetLight.transform.forward;
|
|
m_VolumetricCloudsShadowRegion.regionSize = float2(length(m_VolumetricCloudsShadowRegion.dirX), length(m_VolumetricCloudsShadowRegion.dirY));
|
|
m_VolumetricCloudsShadowRegion.fallbackValue = 1.0f - settings.shadowOpacityFallback.value;
|
|
m_VolumetricCloudsShadowRegion.valid = true;
|
|
}
|
|
|
|
internal void UpdateShaderVariablesGlobalVolumetricClouds(ref ShaderVariablesGlobal cb, HDCamera hdCamera)
|
|
{
|
|
// Volumetric Clouds Shadow Data
|
|
cb._VolumetricCloudsShadowScale = m_VolumetricCloudsShadowRegion.regionSize;
|
|
cb._VolumetricCloudsFallBackValue = m_VolumetricCloudsShadowRegion.fallbackValue;
|
|
|
|
cb._VolumetricCloudsShadowOriginToggle = new Vector4(m_VolumetricCloudsShadowRegion.origin.x, m_VolumetricCloudsShadowRegion.origin.y, m_VolumetricCloudsShadowRegion.origin.z, m_VolumetricCloudsShadowRegion.valid ? 1 : 0);
|
|
if (ShaderConfig.s_CameraRelativeRendering != 0)
|
|
cb._VolumetricCloudsShadowOriginToggle -= new Vector4(hdCamera.camera.transform.position.x, hdCamera.camera.transform.position.y, hdCamera.camera.transform.position.z, 0);
|
|
}
|
|
|
|
void UpdateShaderVariablesCloudsShadow(ref ShaderVariablesCloudsShadows cb, HDCamera hdCamera, VolumetricClouds settings, VolumetricCloudsShadowRegion shadowRegion)
|
|
{
|
|
// Resolution of the cloud shadow
|
|
cb._ShadowCookieResolution = (int)settings.shadowResolution.value;
|
|
cb._ShadowIntensity = settings.shadowOpacity.value;
|
|
cb._CloudShadowSunOrigin = float4(shadowRegion.origin - new float3(hdCamera.planet.center), 1);
|
|
cb._CloudShadowSunRight = float4(shadowRegion.dirX, 0);
|
|
cb._CloudShadowSunUp = float4(shadowRegion.dirY, 0);
|
|
cb._CloudShadowSunForward = float4(shadowRegion.lightDir, 0);
|
|
cb._CameraPositionPS = float4(hdCamera.mainViewConstants.worldSpaceCameraPos - hdCamera.planet.center, 0);
|
|
}
|
|
|
|
struct VolumetricCloudsShadowsParameters
|
|
{
|
|
// Data common to all volumetric cloud passes
|
|
public VolumetricCloudCommonData commonData;
|
|
public ComputeShader traceShadowsCS;
|
|
public int shadowsKernel;
|
|
public ComputeShader shadowFilterCS;
|
|
public int filterShadowsKernel;
|
|
public VolumetricCloudsShadowRegion shadowRegion;
|
|
public ShaderVariablesCloudsShadows cloudsShadowCB;
|
|
}
|
|
|
|
VolumetricCloudsShadowsParameters PrepareVolumetricCloudsShadowsParameters(HDCamera hdCamera, VolumetricClouds settings)
|
|
{
|
|
VolumetricCloudsShadowsParameters parameters = new VolumetricCloudsShadowsParameters();
|
|
|
|
// Compute the cloud model data
|
|
CloudModelData cloudModelData = GetCloudModelData(settings);
|
|
|
|
// CS & Kernels
|
|
parameters.traceShadowsCS = m_VolumetricCloudsTraceShadowsCS;
|
|
parameters.shadowsKernel = m_TraceVolumetricCloudsShadowsKernel;
|
|
|
|
parameters.shadowFilterCS = m_VolumetricCloudsShadowFilterCS;
|
|
parameters.filterShadowsKernel = m_FilterShadowCloudsKernel;
|
|
|
|
// Shadow region
|
|
parameters.shadowRegion = m_VolumetricCloudsShadowRegion;
|
|
|
|
// Fill the common data
|
|
FillVolumetricCloudsCommonData(hdCamera, false, settings, TVolumetricCloudsCameraType.Default, in cloudModelData, ref parameters.commonData);
|
|
|
|
// Update the main constant buffer
|
|
VolumetricCloudsCameraData cameraData;
|
|
cameraData.cameraType = parameters.commonData.cameraType;
|
|
cameraData.traceWidth = 1;
|
|
cameraData.traceHeight = 1;
|
|
cameraData.intermediateWidth = 1;
|
|
cameraData.intermediateHeight = 1;
|
|
cameraData.finalWidth = 1;
|
|
cameraData.finalHeight = 1;
|
|
cameraData.enableExposureControl = false;
|
|
cameraData.lowResolution = false;
|
|
cameraData.enableIntegration = false;
|
|
UpdateShaderVariablesClouds(ref parameters.commonData.cloudsCB, hdCamera, settings, cameraData, cloudModelData, true);
|
|
|
|
// Update the shadow constant buffer
|
|
UpdateShaderVariablesCloudsShadow(ref parameters.cloudsShadowCB, hdCamera, settings, parameters.shadowRegion);
|
|
|
|
return parameters;
|
|
}
|
|
|
|
static void TraceVolumetricCloudShadow(CommandBuffer cmd, VolumetricCloudsShadowsParameters parameters, RTHandle intermediateTexture, RTHandle shadowTexture)
|
|
{
|
|
CoreUtils.SetKeyword(cmd, "CLOUDS_SIMPLE_PRESET", parameters.commonData.simplePreset);
|
|
|
|
// Bind the constant buffer for the trace CS
|
|
ConstantBuffer.Push(cmd, parameters.commonData.cloudsCB, parameters.traceShadowsCS, HDShaderIDs._ShaderVariablesClouds);
|
|
ConstantBuffer.Push(cmd, parameters.cloudsShadowCB, parameters.traceShadowsCS, HDShaderIDs._ShaderVariablesCloudsShadows);
|
|
|
|
// Compute the number of tiles to dispatch
|
|
int tileCount = (parameters.cloudsShadowCB._ShadowCookieResolution + 7) / 8;
|
|
|
|
// Input textures
|
|
cmd.SetComputeTextureParam(parameters.traceShadowsCS, parameters.shadowsKernel, HDShaderIDs._CloudMapTexture, parameters.commonData.cloudMapTexture);
|
|
cmd.SetComputeTextureParam(parameters.traceShadowsCS, parameters.shadowsKernel, HDShaderIDs._CloudLutTexture, parameters.commonData.cloudLutTexture);
|
|
cmd.SetComputeTextureParam(parameters.traceShadowsCS, parameters.shadowsKernel, HDShaderIDs._Worley128RGBA, parameters.commonData.worley128RGBA);
|
|
cmd.SetComputeTextureParam(parameters.traceShadowsCS, parameters.shadowsKernel, HDShaderIDs._ErosionNoise, parameters.commonData.erosionNoise);
|
|
|
|
// Output texture
|
|
cmd.SetComputeTextureParam(parameters.traceShadowsCS, parameters.shadowsKernel, HDShaderIDs._VolumetricCloudsShadowRW, shadowTexture);
|
|
|
|
// Evaluate the shadow
|
|
cmd.DispatchCompute(parameters.traceShadowsCS, parameters.shadowsKernel, tileCount, tileCount, 1);
|
|
|
|
// Bind the constant buffer for the other CS
|
|
ConstantBuffer.Push(cmd, parameters.cloudsShadowCB, parameters.shadowFilterCS, HDShaderIDs._ShaderVariablesCloudsShadows);
|
|
|
|
// Given the low number of steps available and the absence of noise in the integration, we try to reduce the artifacts by doing two consecutive 3x3 blur passes.
|
|
cmd.SetComputeTextureParam(parameters.shadowFilterCS, parameters.filterShadowsKernel, HDShaderIDs._VolumetricCloudsShadow, shadowTexture);
|
|
cmd.SetComputeTextureParam(parameters.shadowFilterCS, parameters.filterShadowsKernel, HDShaderIDs._VolumetricCloudsShadowRW, intermediateTexture);
|
|
cmd.DispatchCompute(parameters.shadowFilterCS, parameters.filterShadowsKernel, tileCount, tileCount, 1);
|
|
|
|
// Filter the shadow
|
|
cmd.SetComputeTextureParam(parameters.shadowFilterCS, parameters.filterShadowsKernel, HDShaderIDs._VolumetricCloudsShadow, intermediateTexture);
|
|
cmd.SetComputeTextureParam(parameters.shadowFilterCS, parameters.filterShadowsKernel, HDShaderIDs._VolumetricCloudsShadowRW, shadowTexture);
|
|
cmd.DispatchCompute(parameters.shadowFilterCS, parameters.filterShadowsKernel, tileCount, tileCount, 1);
|
|
}
|
|
|
|
class VolumetricCloudsShadowsData
|
|
{
|
|
public VolumetricCloudsShadowsParameters parameters;
|
|
public TextureHandle intermediateShadowTexture;
|
|
public TextureHandle shadowTexture;
|
|
}
|
|
|
|
internal void RenderVolumetricCloudsShadows(RenderGraph renderGraph, HDCamera hdCamera, in VolumetricClouds settings)
|
|
{
|
|
// Make sure we should compute the shadow otherwise we return
|
|
if (!HasVolumetricCloudsShadows(hdCamera, in settings))
|
|
return;
|
|
|
|
// Evaluate and bind the shadow
|
|
int shadowResolution = (int)settings.shadowResolution.value;
|
|
TextureHandle shadowTexture = renderGraph.CreateTexture(new TextureDesc(shadowResolution, shadowResolution, false, false)
|
|
{ format = GraphicsFormat.R16G16B16A16_SFloat, enableRandomWrite = true, name = "Volumetric Clouds Shadow Texture" });
|
|
|
|
using (var builder = renderGraph.AddRenderPass<VolumetricCloudsShadowsData>("Volumetric Clouds Shadows", out var passData, ProfilingSampler.Get(HDProfileId.VolumetricCloudsShadow)))
|
|
{
|
|
// Disable pass culling
|
|
builder.AllowPassCulling(false);
|
|
|
|
// Evaluate the parameters
|
|
passData.parameters = PrepareVolumetricCloudsShadowsParameters(hdCamera, settings);
|
|
|
|
// Manage the resources
|
|
passData.intermediateShadowTexture = builder.CreateTransientTexture(new TextureDesc(shadowResolution, shadowResolution, false, false)
|
|
{ format = GraphicsFormat.R16G16B16A16_SFloat, enableRandomWrite = true, name = "Volumetric Clouds Shadow Temp Texture" });
|
|
passData.shadowTexture = builder.ReadWriteTexture(shadowTexture);
|
|
|
|
// Evaluate the shadow
|
|
builder.SetRenderFunc((VolumetricCloudsShadowsData data, RenderGraphContext ctx) =>
|
|
{
|
|
TraceVolumetricCloudShadow(ctx.cmd, data.parameters, data.intermediateShadowTexture, data.shadowTexture);
|
|
|
|
// Bind the volumetric clouds shadow
|
|
ctx.cmd.SetGlobalTexture(HDShaderIDs._VolumetricCloudsShadowsTexture, data.shadowTexture);
|
|
});
|
|
}
|
|
|
|
// Given that the rendering of the shadow happens before the render graph execution, we can only have the display debug here (and not during the light data build).
|
|
m_RenderPipeline.PushFullScreenDebugTexture(renderGraph, shadowTexture, FullScreenDebugMode.VolumetricCloudsShadow, xrTexture: false);
|
|
}
|
|
}
|
|
}
|