324 lines
14 KiB
Plaintext
324 lines
14 KiB
Plaintext
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
|
|
|
|
// Trace to intermediate
|
|
#pragma kernel ReprojectClouds REPROJECT_CLOUDS=ReprojectClouds
|
|
#pragma kernel ReprojectCloudsRejection REPROJECT_CLOUDS=ReprojectCloudsRejection WITH_REJECTION
|
|
#pragma kernel PreUpscaleClouds
|
|
|
|
// Intermediate to Full resolution
|
|
#pragma kernel UpscaleClouds UPSCALE_CLOUDS=UpscaleClouds
|
|
#pragma kernel UpscaleCloudsPerceptual UPSCALE_CLOUDS=UpscaleCloudsPerceptual PERCEPTUAL_TRANSMITTANCE
|
|
|
|
// Full resolution combination
|
|
#pragma kernel CombineClouds COMBINE_CLOUDS=CombineClouds
|
|
#pragma kernel CombineCloudsPerceptual COMBINE_CLOUDS=CombineCloudsPerceptual PERCEPTUAL_TRANSMITTANCE
|
|
|
|
// #define WITHOUT_LDS
|
|
// #pragma enable_d3d11_debug_symbols
|
|
|
|
// HDRP generic includes
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/BilateralUpsample.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RayTracingCommon.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricClouds/VolumetricCloudsUtilities.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricClouds/VolumetricCloudsDenoising.hlsl"
|
|
|
|
// Buffer that holds the offset for every level of the depth pyramid
|
|
StructuredBuffer<int2> _DepthPyramidMipLevelOffsets;
|
|
|
|
// History buffers
|
|
TEXTURE2D_X(_HistoryVolumetricClouds0Texture);
|
|
TEXTURE2D_X(_HistoryVolumetricClouds1Texture);
|
|
|
|
// Output texture
|
|
RW_TEXTURE2D_X(float3, _CloudsLightingTextureRW);
|
|
RW_TEXTURE2D_X(float4, _CloudsAdditionalTextureRW);
|
|
|
|
[numthreads(8, 8, 1)]
|
|
void REPROJECT_CLOUDS(uint3 dispatchThreadId : SV_DispatchThreadID,
|
|
int groupIndex : SV_GroupIndex,
|
|
uint2 groupThreadId : SV_GroupThreadID,
|
|
uint2 groupId : SV_GroupID)
|
|
{
|
|
UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z);
|
|
|
|
// Compute the set of coordinates we need
|
|
uint2 intermediateCoord = dispatchThreadId.xy;
|
|
uint2 fullResCoord = intermediateCoord * _IntermediateResolutionScale;
|
|
uint2 traceCoord = intermediateCoord / 2;
|
|
uint2 localOffset = uint2(intermediateCoord.x & 1, intermediateCoord.y & 1);
|
|
|
|
#ifdef WITHOUT_LDS
|
|
uint2 threadCoord = traceCoord;
|
|
#else
|
|
uint2 threadCoord = groupThreadId;
|
|
|
|
// Only 36 workers of the 64 do the pre-fetching
|
|
if (groupIndex < 36)
|
|
{
|
|
// Load 1 value per thread
|
|
FillCloudReprojectionLDS(groupIndex, groupId * 8);
|
|
}
|
|
// Make sure all values are loaded in LDS by now.
|
|
GroupMemoryBarrierWithGroupSync();
|
|
#endif
|
|
|
|
// 1. Init various stuff
|
|
float currentSceneDepth = LOAD_TEXTURE2D_X(_CameraDepthTexture, _ReprojDepthMipOffset + intermediateCoord).x;
|
|
float currentCloudDepth = GetCloudDepth(threadCoord, int2(0, 0));
|
|
|
|
bool validTracing = all(localOffset == ComputeCheckerBoardOffset(traceCoord, _SubPixelIndex));
|
|
|
|
float4 finalColor = GetCloudLighting(threadCoord, int2(0, 0));
|
|
float finalCloudDepth = currentCloudDepth;
|
|
float finalSampleCount = 1.0;
|
|
|
|
// 2. Check history validity
|
|
float2 motionVector = EvaluateCloudMotionVectors(fullResCoord, currentCloudDepth, 1.0);
|
|
float2 historyUV = (intermediateCoord.xy + 0.5) / _IntermediateScreenSize.xy - motionVector;
|
|
|
|
float4 history = SAMPLE_TEXTURE2D_X_LOD(_HistoryVolumetricClouds1Texture, s_linear_clamp_sampler, historyUV * _HistoryViewportScale, 0);
|
|
float previousSampleCount = history.x;
|
|
|
|
// History is invalid if sample is out of screen or scene depth was too different
|
|
if (all(historyUV == saturate(historyUV)) && previousSampleCount >= 0.5f && EvaluateDepthDifference(history.y, currentSceneDepth))
|
|
{
|
|
float4 previousColor = SAMPLE_TEXTURE2D_X_LOD(_HistoryVolumetricClouds0Texture, s_linear_clamp_sampler, historyUV * _HistoryViewportScale, 0);
|
|
previousColor.xyz *= GetInversePreviousExposureMultiplier() * GetCurrentExposureMultiplier();
|
|
previousColor.a = history.a;
|
|
|
|
float previousCloudDepth = history.z;
|
|
previousCloudDepth = saturate(previousCloudDepth * _NearPlaneReprojection);
|
|
|
|
// Color clamp the history with neighborhood
|
|
float validityFactor = 1.0;
|
|
|
|
#ifdef WITH_REJECTION
|
|
float4 lightingMin = float4(FLT_MAX, FLT_MAX, FLT_MAX, 1.0);
|
|
float4 lightingMax = float4(0, 0, 0, 0.0);
|
|
for (int y = -1; y <= 1; ++y)
|
|
{
|
|
for (int x = -1; x <= 1; ++x)
|
|
{
|
|
CloudReprojectionData data = GetCloudReprojectionDataSample(threadCoord, int2(x, y));
|
|
if ((data.pixelDepth == UNITY_RAW_FAR_CLIP_VALUE) == (currentSceneDepth == UNITY_RAW_FAR_CLIP_VALUE))
|
|
{
|
|
lightingMin = min(lightingMin, data.cloudLighting);
|
|
lightingMax = max(lightingMax, data.cloudLighting);
|
|
}
|
|
}
|
|
}
|
|
|
|
previousColor = ClipCloudsToRegion(previousColor, lightingMin, lightingMax, validityFactor);
|
|
#endif
|
|
|
|
if (validTracing)
|
|
{
|
|
// Define our accumation value
|
|
float accumulationFactor = validityFactor * previousSampleCount / (previousSampleCount + 1.0);
|
|
accumulationFactor *= _TemporalAccumulationFactor * _CloudHistoryInvalidation;
|
|
|
|
finalColor = lerp(finalColor, previousColor, accumulationFactor);
|
|
finalSampleCount = min(previousSampleCount + 1.0, 16.0);
|
|
}
|
|
else
|
|
{
|
|
finalColor = previousColor;
|
|
finalCloudDepth = previousCloudDepth;
|
|
finalSampleCount = max(1, validityFactor * previousSampleCount * _CloudHistoryInvalidation);
|
|
}
|
|
}
|
|
else if (!validTracing)
|
|
{
|
|
// Bilateral upscale in case we have no data
|
|
NeighborhoodUpsampleData3x3 upsampleData;
|
|
uint localIndex = (intermediateCoord.x & 1) + ((intermediateCoord.y & 1) << 1);
|
|
FillCloudReprojectionNeighborhoodData(threadCoord, localIndex, upsampleData);
|
|
|
|
bool isSky = currentSceneDepth == UNITY_RAW_FAR_CLIP_VALUE;
|
|
upsampleData.lowWeightA *= ((upsampleData.lowDepthA == UNITY_RAW_FAR_CLIP_VALUE) == isSky);
|
|
upsampleData.lowWeightB *= ((upsampleData.lowDepthB == UNITY_RAW_FAR_CLIP_VALUE) == isSky);
|
|
upsampleData.lowWeightC *= ((upsampleData.lowDepthC == UNITY_RAW_FAR_CLIP_VALUE) == isSky);
|
|
|
|
// Depth are not converted to linear 01 space on purpose here
|
|
// But it would be slower without noticeable quality improvement
|
|
BilUpColor3x3(currentSceneDepth, upsampleData, finalColor, finalCloudDepth);
|
|
}
|
|
|
|
// 3. Export
|
|
finalColor.a = saturate(finalColor.a);
|
|
finalCloudDepth = finalColor.a == 1.0 ? UNITY_RAW_FAR_CLIP_VALUE : finalCloudDepth;
|
|
|
|
_CloudsLightingTextureRW[COORD_TEXTURE2D_X(intermediateCoord)] = finalColor.xyz;
|
|
_CloudsAdditionalTextureRW[COORD_TEXTURE2D_X(intermediateCoord)] = float4(finalSampleCount, currentSceneDepth, finalCloudDepth, finalColor.a);
|
|
}
|
|
|
|
[numthreads(8, 8, 1)]
|
|
void PreUpscaleClouds(uint3 dispatchThreadId : SV_DispatchThreadID,
|
|
int groupIndex : SV_GroupIndex,
|
|
uint2 groupThreadId : SV_GroupThreadID,
|
|
uint2 groupId : SV_GroupID)
|
|
{
|
|
UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z);
|
|
|
|
// Compute the set of coordinates we need
|
|
uint2 intermediateCoord = dispatchThreadId.xy;
|
|
uint2 traceCoord = intermediateCoord / 2;
|
|
uint2 localOffset = uint2(intermediateCoord.x & 1, intermediateCoord.y & 1);
|
|
|
|
#ifdef WITHOUT_LDS
|
|
uint2 threadCoord = traceCoord;
|
|
#else
|
|
uint2 threadCoord = groupThreadId;
|
|
|
|
// Only 36 workers of the 64 do the pre-fetching
|
|
if (groupIndex < 36)
|
|
{
|
|
// Load 1 value per thread
|
|
FillCloudReprojectionLDS(groupIndex, groupId * 8);
|
|
}
|
|
// Make sure all values are loaded in LDS by now.
|
|
GroupMemoryBarrierWithGroupSync();
|
|
#endif
|
|
|
|
// Read the resolution of the current pixel
|
|
float currentSceneDepth = LOAD_TEXTURE2D_X(_CameraDepthTexture, _ReprojDepthMipOffset + intermediateCoord).x;
|
|
float currentCloudDepth = GetCloudDepth(threadCoord, int2(0, 0));
|
|
|
|
bool validTracing = all(localOffset == ComputeCheckerBoardOffset(traceCoord, _SubPixelIndex));
|
|
|
|
float finalCloudDepth = 0;
|
|
float4 finalColor = 0;
|
|
|
|
// Compute the local index that tells us the index of this pixel, the strategy for reprojection is a bit different in both cases
|
|
if (validTracing)
|
|
{
|
|
// Accumulate the result with the previous frame
|
|
finalColor = GetCloudLighting(threadCoord, int2(0, 0));
|
|
finalCloudDepth = currentCloudDepth;
|
|
}
|
|
else
|
|
{
|
|
// Structure that will hold everything
|
|
NeighborhoodUpsampleData3x3 upsampleData;
|
|
uint localIndex = (intermediateCoord.x & 1) + ((intermediateCoord.y & 1) << 1);
|
|
FillCloudReprojectionNeighborhoodData(threadCoord, localIndex, upsampleData);
|
|
|
|
BilUpColor3x3(currentSceneDepth, upsampleData, finalColor, finalCloudDepth);
|
|
}
|
|
|
|
// Make sure this doesn't go outside of the [0, 1] interval
|
|
finalColor.w = saturate(finalColor.w);
|
|
|
|
// Accumulate the result with the previous frame
|
|
_CloudsLightingTextureRW[COORD_TEXTURE2D_X(intermediateCoord)] = finalColor.xyz;
|
|
_CloudsAdditionalTextureRW[COORD_TEXTURE2D_X(intermediateCoord)] = float4(1, currentSceneDepth, finalCloudDepth, finalColor.a);
|
|
}
|
|
|
|
RW_TEXTURE2D_X(float3, _VolumetricCloudsLightingTextureRW);
|
|
RW_TEXTURE2D_X(float2, _VolumetricCloudsDepthTextureRW);
|
|
|
|
[numthreads(8, 8, 1)]
|
|
void UPSCALE_CLOUDS(uint3 finalCoord : SV_DispatchThreadID,
|
|
int groupIndex : SV_GroupIndex,
|
|
uint2 groupThreadId : SV_GroupThreadID,
|
|
uint2 groupId : SV_GroupID)
|
|
{
|
|
UNITY_XR_ASSIGN_VIEW_INDEX(finalCoord.z);
|
|
int2 halfResCoord = finalCoord.xy / 2;
|
|
|
|
#ifdef WITHOUT_LDS
|
|
int2 threadCoord = halfResCoord;
|
|
#else
|
|
int2 threadCoord = groupThreadId;
|
|
|
|
// Only 36 workers of the 64 do the pre-fetching
|
|
if (groupIndex < 36)
|
|
{
|
|
// Load 1 value per thread
|
|
FillLDSUpscale(groupIndex, groupId * 8);
|
|
}
|
|
|
|
// Make sure all values are loaded in LDS by now.
|
|
GroupMemoryBarrierWithGroupSync();
|
|
#endif
|
|
|
|
// If out of bounds, leave right away
|
|
if (any(finalCoord.xy >= uint2(_FinalScreenSize.xy)))
|
|
return;
|
|
|
|
// Grab the depth value of the pixel
|
|
float sceneDepth = LOAD_TEXTURE2D_X(_CameraDepthTexture, finalCoord.xy).x;
|
|
|
|
// Structure that will hold everything
|
|
NeighborhoodUpsampleData3x3 upsampleData;
|
|
uint localIndex = (finalCoord.x & 1) + (finalCoord.y & 1) * 2;
|
|
FillCloudUpscaleNeighborhoodData(threadCoord, localIndex, upsampleData);
|
|
|
|
// Solves edge filtering in most cases
|
|
bool isSky = sceneDepth == UNITY_RAW_FAR_CLIP_VALUE;
|
|
upsampleData.lowWeightA *= ((upsampleData.lowDepthA == UNITY_RAW_FAR_CLIP_VALUE) == isSky);
|
|
upsampleData.lowWeightB *= ((upsampleData.lowDepthB == UNITY_RAW_FAR_CLIP_VALUE) == isSky);
|
|
upsampleData.lowWeightC *= ((upsampleData.lowDepthC == UNITY_RAW_FAR_CLIP_VALUE) == isSky);
|
|
|
|
// Convert the depths to linear, helps when scene depth has checkerboard pattern
|
|
float linearSceneDepth = Linear01Depth(sceneDepth, _ZBufferParams);
|
|
upsampleData.lowDepthA = Linear01Depth(upsampleData.lowDepthA, _ZBufferParams);
|
|
upsampleData.lowDepthB = Linear01Depth(upsampleData.lowDepthB, _ZBufferParams);
|
|
upsampleData.lowDepthC = Linear01Depth(upsampleData.lowDepthC, _ZBufferParams);
|
|
|
|
// Do the bilateral upscale
|
|
float4 finalColor;
|
|
float finalCloudDepth;
|
|
BilUpColor3x3(linearSceneDepth, upsampleData, finalColor, finalCloudDepth);
|
|
|
|
finalColor.a = EvaluateFinalTransmittance(finalCoord.xy, finalColor.a);
|
|
|
|
// Optimized conversion of scene depth to infinite depth
|
|
//sceneDepth = EncodeInfiniteDepth(LinearEyeDepth(sceneDepth, _ZBufferParams), _CloudNearPlane);
|
|
float finalSceneDepth = (_ZBufferParams.z * sceneDepth + _ZBufferParams.w) * _CloudNearPlane;
|
|
|
|
// Manual ztest as upscaling can produce clouds behind geometry
|
|
if (sceneDepth != UNITY_RAW_FAR_CLIP_VALUE && finalCloudDepth <= finalSceneDepth)
|
|
{
|
|
finalColor.a = 1.0f;
|
|
finalCloudDepth = UNITY_NEAR_CLIP_VALUE;
|
|
}
|
|
|
|
// Store the upscaled result only, composite in later pass.
|
|
_VolumetricCloudsLightingTextureRW[COORD_TEXTURE2D_X(finalCoord.xy)] = finalColor.rgb;
|
|
_VolumetricCloudsDepthTextureRW[COORD_TEXTURE2D_X(finalCoord.xy)] = float2(finalCloudDepth, finalColor.a);
|
|
}
|
|
|
|
[numthreads(8, 8, 1)]
|
|
void COMBINE_CLOUDS(uint3 finalCoord : SV_DispatchThreadID,
|
|
int groupIndex : SV_GroupIndex,
|
|
uint2 groupThreadId : SV_GroupThreadID,
|
|
uint2 groupId : SV_GroupID)
|
|
{
|
|
UNITY_XR_ASSIGN_VIEW_INDEX(finalCoord.z);
|
|
|
|
// If out of bounds, leave right away
|
|
if (any(finalCoord.xy >= uint2(_FinalScreenSize.xy)))
|
|
return;
|
|
|
|
float3 color = LOAD_TEXTURE2D_X(_VolumetricCloudsTexture, finalCoord.xy).xyz;
|
|
float3 data = LOAD_TEXTURE2D_X(_DepthStatusTexture, finalCoord.xy).yzw;
|
|
|
|
float cloudDepth = data.y;
|
|
float transmittance = EvaluateFinalTransmittance(finalCoord.xy, data.z);
|
|
|
|
// Manual ztest as upscaling can produce clouds behind geometry
|
|
float sceneDepth = (_ZBufferParams.z * data.x + _ZBufferParams.w) * _CloudNearPlane;
|
|
if (data.x != UNITY_RAW_FAR_CLIP_VALUE && cloudDepth <= sceneDepth)
|
|
{
|
|
transmittance = 1.0f;
|
|
cloudDepth = UNITY_NEAR_CLIP_VALUE;
|
|
}
|
|
|
|
// Store the upscaled result only, composite in later pass.
|
|
_VolumetricCloudsLightingTextureRW[COORD_TEXTURE2D_X(finalCoord.xy)] = color;
|
|
_VolumetricCloudsDepthTextureRW[COORD_TEXTURE2D_X(finalCoord.xy)] = float2(cloudDepth, transmittance);
|
|
}
|