Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions com.unity.render-pipelines.high-definition/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

### changed
- Visual Environment ambient mode is now Dynamic by default.
- Changed the number of steps to evaluate the shadow from 9 to 16.

### Added
- Added an option for the ultra 1024x1024 mode for the volumetric cloud shadows and a filtering pass to reduce the aliasing artifacts of the clouds shadow.

## [12.0.0] - 2021-01-11

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,25 @@ public partial class HDRenderPipeline
{
// Cloud preset maps
RTHandle[] m_VolumetricCloudsShadowTexture = new RTHandle[VolumetricClouds.CloudShadowResolutionCount];
RTHandle m_VolumetricCloudsIntermediateShadowTexture;

// The set of kernels that are required
int m_ComputeShadowCloudsKernel;
int m_FilterShadowCloudsKernel;

void InitializeVolumetricCloudsShadows()
{
// Grab the kernels we need
ComputeShader volumetricCloudsCS = m_Asset.renderPipelineResources.shaders.volumetricCloudsCS;
m_ComputeShadowCloudsKernel = volumetricCloudsCS.FindKernel("ComputeVolumetricCloudsShadow");
m_FilterShadowCloudsKernel = volumetricCloudsCS.FindKernel("FilterVolumetricCloudsShadow");
}

void ReleaseVolumetricCloudsShadows()
{
for (int i = 0; i < VolumetricClouds.CloudShadowResolutionCount; ++i)
{
RTHandles.Release(m_VolumetricCloudsShadowTexture[i]);
}
RTHandles.Release(m_VolumetricCloudsIntermediateShadowTexture);
}

bool HasVolumetricCloudsShadows(HDCamera hdCamera, in VolumetricClouds settings)
Expand Down Expand Up @@ -55,6 +57,7 @@ struct VolumetricCloudsShadowsParameters
// Data common to all volumetric cloud passes
public VolumetricCloudCommonData commonData;
public int shadowsKernel;
public int filterShadowsKernel;
}

VolumetricCloudsShadowsParameters PrepareVolumetricCloudsShadowsParameters(HDCamera hdCamera, VolumetricClouds settings)
Expand All @@ -68,6 +71,7 @@ VolumetricCloudsShadowsParameters PrepareVolumetricCloudsShadowsParameters(HDCam
FillVolumetricCloudsCommonData(false, settings, TVolumetricCloudsCameraType.Default, in cloudModelData, ref parameters.commonData);

parameters.shadowsKernel = m_ComputeShadowCloudsKernel;
parameters.filterShadowsKernel = m_FilterShadowCloudsKernel;

// Update the constant buffer
VolumetricCloudsCameraData cameraData;
Expand All @@ -87,7 +91,7 @@ VolumetricCloudsShadowsParameters PrepareVolumetricCloudsShadowsParameters(HDCam
return parameters;
}

static void TraceVolumetricCloudShadow(CommandBuffer cmd, VolumetricCloudsShadowsParameters parameters, RTHandle shadowTexture)
static void TraceVolumetricCloudShadow(CommandBuffer cmd, VolumetricCloudsShadowsParameters parameters, RTHandle intermediateTexture, RTHandle shadowTexture)
{
using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.VolumetricCloudsShadow)))
{
Expand All @@ -111,6 +115,17 @@ static void TraceVolumetricCloudShadow(CommandBuffer cmd, VolumetricCloudsShadow
// Evaluate the shadow
cmd.DispatchCompute(parameters.commonData.volumetricCloudsCS, parameters.shadowsKernel, shadowTX, shadowTY, 1);

// 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.
// Filter the shadow
cmd.SetComputeTextureParam(parameters.commonData.volumetricCloudsCS, parameters.filterShadowsKernel, HDShaderIDs._VolumetricCloudsShadow, shadowTexture);
cmd.SetComputeTextureParam(parameters.commonData.volumetricCloudsCS, parameters.filterShadowsKernel, HDShaderIDs._VolumetricCloudsShadowRW, intermediateTexture);
cmd.DispatchCompute(parameters.commonData.volumetricCloudsCS, parameters.filterShadowsKernel, shadowTX, shadowTY, 1);

// Filter the shadow
cmd.SetComputeTextureParam(parameters.commonData.volumetricCloudsCS, parameters.filterShadowsKernel, HDShaderIDs._VolumetricCloudsShadow, intermediateTexture);
cmd.SetComputeTextureParam(parameters.commonData.volumetricCloudsCS, parameters.filterShadowsKernel, HDShaderIDs._VolumetricCloudsShadowRW, shadowTexture);
cmd.DispatchCompute(parameters.commonData.volumetricCloudsCS, parameters.filterShadowsKernel, shadowTX, shadowTY, 1);

// Bump the texture version
shadowTexture.rt.IncrementUpdateCount();
}
Expand Down Expand Up @@ -146,12 +161,15 @@ RTHandle RequestVolumetricCloudsShadowTexture(in VolumetricClouds settings)
case VolumetricClouds.CloudShadowResolution.High512:
shadowResIndex = 3;
break;
case VolumetricClouds.CloudShadowResolution.Ultra1024:
shadowResIndex = 4;
break;
}

if (m_VolumetricCloudsShadowTexture[shadowResIndex] == null)
{
m_VolumetricCloudsShadowTexture[shadowResIndex] = RTHandles.Alloc(shadowResolution, shadowResolution, 1, colorFormat: GraphicsFormat.B10G11R11_UFloatPack32,
enableRandomWrite: true, useDynamicScale: false, useMipMap: false, wrapMode: TextureWrapMode.Clamp, name: "Volumetric Clouds Shadow Texture");
enableRandomWrite: true, useDynamicScale: false, useMipMap: false, filterMode: FilterMode.Bilinear, wrapMode: TextureWrapMode.Clamp, name: "Volumetric Clouds Shadow Texture");
}

return m_VolumetricCloudsShadowTexture[shadowResIndex];
Expand All @@ -169,9 +187,18 @@ CookieParameters RenderVolumetricCloudsShadows(CommandBuffer cmd, HDCamera hdCam
// TODO: Right now we can end up with a bunch of textures allocated which should be solved by an other PR.
RTHandle currentHandle = RequestVolumetricCloudsShadowTexture(settings);

// Check if the intermediate texture that we need for the filtering has already been allocated
if (m_VolumetricCloudsIntermediateShadowTexture == null)
{
m_VolumetricCloudsIntermediateShadowTexture = RTHandles.Alloc((int)VolumetricClouds.CloudShadowResolution.Ultra1024, (int)VolumetricClouds.CloudShadowResolution.Ultra1024,
1, colorFormat: GraphicsFormat.B10G11R11_UFloatPack32,
enableRandomWrite: true, useDynamicScale: false, useMipMap: false,
wrapMode: TextureWrapMode.Clamp, name: "Intermediate Volumetric Clouds Shadow Texture");
}

// Evaluate and return the shadow
var parameters = PrepareVolumetricCloudsShadowsParameters(hdCamera, settings);
TraceVolumetricCloudShadow(cmd, parameters, currentHandle);
TraceVolumetricCloudShadow(cmd, parameters, m_VolumetricCloudsIntermediateShadowTexture, currentHandle);

// Grab the current sun light
Light sunLight = GetMainLight();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

// Shadows
#pragma kernel ComputeVolumetricCloudsShadow
#pragma kernel FilterVolumetricCloudsShadow

#pragma multi_compile _ PHYSICALLY_BASED_SUN
#pragma multi_compile _ LOCAL_VOLUMETRIC_CLOUDS
Expand Down Expand Up @@ -1547,9 +1548,9 @@ void ComputeVolumetricCloudsShadow(uint3 currentCoords : SV_DispatchThreadID, ui
float startDistance = intersectionO.x;
float totalDistance = intersectionI.x - intersectionO.x;

float stepSize = totalDistance / 10;
float stepSize = totalDistance / 16;

for (int i = 1; i <= 8; ++i)
for (int i = 0; i < 16; ++i)
{
// Compute the sphere intersection position
float3 positionWS = rayOriginWS + rayDirection * (intersectionO.x + stepSize * i);
Expand All @@ -1564,11 +1565,76 @@ void ComputeVolumetricCloudsShadow(uint3 currentCoords : SV_DispatchThreadID, ui
if (cloudProperties.density > CLOUD_DENSITY_TRESHOLD)
{
// Apply the extinction
const float3 currentStepExtinction = exp(- _ScatteringTint.xyz * cloudProperties.density * cloudProperties.sigmaT * stepSize);
const float3 currentStepExtinction = exp(-_ScatteringTint.xyz * cloudProperties.density * cloudProperties.sigmaT * stepSize);
transmittance *= Luminance(currentStepExtinction);
}
}
}

_VolumetricCloudsShadowRW[currentCoords.xy] = lerp(1.0 - _ShadowIntensity, 1.0, transmittance);
}

// LDS used to pre-fetch the neighborhood data a 8x8 region with a one pixel border (10x10)
groupshared uint gs_cacheShadow[100];

TEXTURE2D(_VolumetricCloudsShadow);

void FillShadowLDSData(uint elementIndex, uint2 groupOrigin)
{
// Define which value we will be acessing with this worker thread
int acessCoordX = elementIndex % 10;
int acessCoordY = elementIndex / 10;

// The initial position of the access
int2 originXY = (int2)groupOrigin - int2(1, 1) + int2(acessCoordX, acessCoordY);

// Compute the sample position
int2 tapCoord = int2(clamp(originXY.x, 0, _ShadowCookieResolution - 1), clamp(originXY.y, 0, _ShadowCookieResolution - 1));

// Read the value from the texture
float3 shadowValue = LOAD_TEXTURE2D(_VolumetricCloudsShadow, tapCoord.xy).xyz;

// Pack it and store it into the LDS
gs_cacheShadow[elementIndex] = PackToR11G11B10f(shadowValue);
}

uint ShadowOffsetToLDSAdress(uint2 groupThreadId, int2 offset)
{
// Compute the tap coordinate in the 10x10 grid
uint2 tapAddress = (uint2)((int2)(groupThreadId + 1) + offset);
return clamp((uint)(tapAddress.x) % 10 + tapAddress.y * 10, 0, 99);
}

[numthreads(8, 8, 1)]
void FilterVolumetricCloudsShadow(uint3 currentCoords : SV_DispatchThreadID, int groupIndex : SV_GroupIndex, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID)
{
UNITY_XR_ASSIGN_VIEW_INDEX(currentCoords.z);

// Fill the LDS with the shadow data
if (groupIndex < 50)
{
FillShadowLDSData(groupIndex * 2, groupId * 8);
FillShadowLDSData(groupIndex * 2 + 1, groupId * 8);
}
GroupMemoryBarrierWithGroupSync();

// Grab the center pixel
float3 centerShadow = UnpackFromR11G11B10f(gs_cacheShadow[ShadowOffsetToLDSAdress(groupThreadId, int2(0, 0))]);

// Average the 3x3 rgion
float3 filteredShadow = UnpackFromR11G11B10f(gs_cacheShadow[ShadowOffsetToLDSAdress(groupThreadId, int2(-1, -1))]);
filteredShadow += UnpackFromR11G11B10f(gs_cacheShadow[ShadowOffsetToLDSAdress(groupThreadId, int2(0, -1))]);
filteredShadow += UnpackFromR11G11B10f(gs_cacheShadow[ShadowOffsetToLDSAdress(groupThreadId, int2(1, -1))]);
filteredShadow += UnpackFromR11G11B10f(gs_cacheShadow[ShadowOffsetToLDSAdress(groupThreadId, int2(-1, 0))]);
filteredShadow += centerShadow;
filteredShadow += UnpackFromR11G11B10f(gs_cacheShadow[ShadowOffsetToLDSAdress(groupThreadId, int2(1, 0))]);
filteredShadow += UnpackFromR11G11B10f(gs_cacheShadow[ShadowOffsetToLDSAdress(groupThreadId, int2(-1, 1))]);
filteredShadow += UnpackFromR11G11B10f(gs_cacheShadow[ShadowOffsetToLDSAdress(groupThreadId, int2(0, 1))]);
filteredShadow += UnpackFromR11G11B10f(gs_cacheShadow[ShadowOffsetToLDSAdress(groupThreadId, int2(1, 1))]);

// We have a different behavior if this is a border pixel
float borderPixel = currentCoords.x == 0 || currentCoords.y == 0 || ((int)currentCoords.x) == (_ShadowCookieResolution - 1) || ((int)currentCoords.y) == (_ShadowCookieResolution - 1) ? 1.0 : 0.0;

// Normalize and return the result
_VolumetricCloudsShadowRW[currentCoords.xy] = lerp(filteredShadow * 0.1111111, centerShadow, borderPixel);
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,12 @@ public enum CloudShadowResolution
Medium256 = 256,
/// <summary>The volumetric clouds shadow will be 512x512.</summary>
High512 = 512,
/// <summary>The volumetric clouds shadow will be 1024x1024.</summary>
Ultra1024 = 1024,
}

/// <summary> </summary>
public const int CloudShadowResolutionCount = 4;
public const int CloudShadowResolutionCount = 5;

/// <summary>
/// A <see cref="VolumeParameter"/> that holds a <see cref="CloudControl"/> value.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@ static class HDShaderIDs
public static readonly int _CloudsAdditionalTextureRW = Shader.PropertyToID("_CloudsAdditionalTextureRW");
public static readonly int _VolumetricCloudsTexture = Shader.PropertyToID("_VolumetricCloudsTexture");
public static readonly int _VolumetricCloudsTextureRW = Shader.PropertyToID("_VolumetricCloudsTextureRW");
public static readonly int _VolumetricCloudsShadow = Shader.PropertyToID("_VolumetricCloudsShadow");
public static readonly int _VolumetricCloudsShadowRW = Shader.PropertyToID("_VolumetricCloudsShadowRW");
public static readonly int _VolumetricCloudsUpscaleTextureRW = Shader.PropertyToID("_VolumetricCloudsUpscaleTextureRW");
public static readonly int _HistoryVolumetricClouds0Texture = Shader.PropertyToID("_HistoryVolumetricClouds0Texture");
Expand Down