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.
510 lines
22 KiB
510 lines
22 KiB
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
|
|
|
|
// Depth related kernels
|
|
#pragma kernel DownscaleDepth
|
|
|
|
// 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"
|
|
|
|
// Input textures
|
|
TEXTURE2D_X(_CameraColorTexture);
|
|
TEXTURE2D_X(_DepthTexture);
|
|
|
|
// History buffers
|
|
TEXTURE2D_X(_HistoryVolumetricClouds0Texture);
|
|
TEXTURE2D_X(_HistoryVolumetricClouds1Texture);
|
|
|
|
// Output texture
|
|
RW_TEXTURE2D_X(float, _HalfResDepthBufferRW);
|
|
RW_TEXTURE2D_X(float4, _CloudsLightingTextureRW);
|
|
RW_TEXTURE2D_X(float3, _CloudsAdditionalTextureRW);
|
|
|
|
[numthreads(8, 8, 1)]
|
|
void DownscaleDepth(uint3 intermediateCoord : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID)
|
|
{
|
|
UNITY_XR_ASSIGN_VIEW_INDEX(intermediateCoord.z);
|
|
|
|
// If this is bigger than the trace size, we are done
|
|
if (any(intermediateCoord.xy >= uint2(_IntermediateScreenSize.xy)))
|
|
return;
|
|
|
|
// TODO USE LDS for this
|
|
float depth0 = LOAD_TEXTURE2D_X(_DepthTexture, intermediateCoord.xy * 2.0).x;
|
|
float depth1 = LOAD_TEXTURE2D_X(_DepthTexture, intermediateCoord.xy * 2.0 + int2(0, 1)).x;
|
|
float depth2 = LOAD_TEXTURE2D_X(_DepthTexture, intermediateCoord.xy * 2.0 + int2(1, 1)).x;
|
|
float depth3 = LOAD_TEXTURE2D_X(_DepthTexture, intermediateCoord.xy * 2.0 + int2(1, 0)).x;
|
|
|
|
// Combine it with the current shift to define which half res depth should be used
|
|
_HalfResDepthBufferRW[COORD_TEXTURE2D_X(intermediateCoord.xy)] = min(min(depth0, depth1), min(depth2, depth3));
|
|
}
|
|
|
|
[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;
|
|
|
|
#ifndef WITHOUT_LDS
|
|
// 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
|
|
|
|
#ifdef WITHOUT_LDS
|
|
// Average the depth of the cloud
|
|
float currentCloudDepth = LOAD_TEXTURE2D_X(_CloudsDepthTexture, traceCoord).x;
|
|
#else
|
|
// Average the depth of the cloud
|
|
float currentCloudDepth = GetCloudDepth_LDS(groupThreadId, int2(0, 0));
|
|
#endif
|
|
|
|
// Compute the motionVector of the clouds
|
|
float2 motionVector = EvaluateCloudMotionVectors(fullResCoord, currentCloudDepth, 1.0);
|
|
|
|
// Compute the history pixel coordinate to tap from
|
|
float2 historyCoord = (intermediateCoord.xy + 0.5) - motionVector * _IntermediateScreenSize.xy;
|
|
float2 clampedHistoryUV = clamp(historyCoord, 0.0, _IntermediateScreenSize.xy - 0.5f) / _IntermediateScreenSize.xy;
|
|
|
|
// Read the volumetric cloud value from the previous frame
|
|
float2 ratioScale = _HistoryViewportSize / _HistoryBufferSize;
|
|
float2 historySampleCoords = clampedHistoryUV * ratioScale;
|
|
|
|
// Grab the history values
|
|
float4 previousResult = SAMPLE_TEXTURE2D_X_LOD(_HistoryVolumetricClouds0Texture, s_linear_clamp_sampler, historySampleCoords, 0);
|
|
float3 previousResult1 = SAMPLE_TEXTURE2D_X_LOD(_HistoryVolumetricClouds1Texture, s_linear_clamp_sampler, historySampleCoords, 0).xyz;
|
|
|
|
// Inverse the exposure of the previous frame and apply the current one (need to be done in linear space)
|
|
previousResult.xyz *= GetInversePreviousExposureMultiplier() * GetCurrentExposureMultiplier();
|
|
|
|
// Unpack the second buffer
|
|
float previousSampleCount = previousResult1.x;
|
|
float previousDepth = previousResult1.y;
|
|
float previousCloudDepth = previousResult1.z;
|
|
|
|
// Reproject previous cloud depth in case near plane has changed
|
|
previousCloudDepth = saturate(previousCloudDepth * _NearPlaneReprojection);
|
|
|
|
// This tracks if the history is considered valid
|
|
bool validHistory = previousSampleCount >= 0.5f;
|
|
|
|
// The history is invalid if we are requesting a value outside the frame
|
|
if(historyCoord.x < 0.0 || historyCoord.x >= _IntermediateScreenSize.x || historyCoord.y < 0.0 || historyCoord.y >= _IntermediateScreenSize.y)
|
|
validHistory = false;
|
|
|
|
// Read the resolution of the current pixel
|
|
float currentDepth = LOAD_TEXTURE2D_X(_HalfResDepthBuffer, intermediateCoord).x;
|
|
|
|
// Compare the depth of the current pixel to the one of its history, if they are too different, we cannot consider this history valid
|
|
float linearPrevDepth = Linear01Depth(previousDepth, _ZBufferParams);
|
|
float linearCurrentDepth = Linear01Depth(currentDepth, _ZBufferParams);
|
|
|
|
// We only need to check if the pixel depth coherence if the clouds can be behind and in front of the pixel
|
|
if (abs(linearPrevDepth - linearCurrentDepth) > linearCurrentDepth * 0.2)
|
|
validHistory = false;
|
|
|
|
float validityFactor = 1.0;
|
|
#ifdef WITH_REJECTION
|
|
// We need to validate that within the 3x3 trace region, at least one of the pixels is not a background pixel (including the clouds)
|
|
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)
|
|
{
|
|
#ifdef WITHOUT_LDS
|
|
float4 cloudLigting = LOAD_TEXTURE2D_X(_CloudsLightingTexture, traceCoord + int2(x, y));
|
|
#else
|
|
float4 cloudLigting = GetCloudLighting_LDS(groupThreadId, int2(x, y));
|
|
#endif
|
|
lightingMin = min(lightingMin, cloudLigting);
|
|
lightingMax = max(lightingMax, cloudLigting);
|
|
}
|
|
}
|
|
|
|
if (currentDepth == UNITY_RAW_FAR_CLIP_VALUE)
|
|
previousResult = ClipCloudsToRegion(previousResult, lightingMin, lightingMax, validityFactor);
|
|
#endif
|
|
|
|
// Compute the local index that tells us the index of this pixel, the strategy for reprojection is a bit different in both cases
|
|
int localIndex = (intermediateCoord.x & 1) + (intermediateCoord.y & 1) * 2;
|
|
int currentIndex = ComputeCheckerBoardIndex(traceCoord, _SubPixelIndex);
|
|
if (localIndex == currentIndex)
|
|
{
|
|
// We need to validate that within the 3x3 trace region, at least one of the pixels is not a background pixel (incluing the clouds)
|
|
float cloudNeighborhood = 0.0f;
|
|
for (int y = -1; y <= 1; ++y)
|
|
{
|
|
for (int x = -1; x <= 1; ++x)
|
|
{
|
|
#ifdef WITHOUT_LDS
|
|
if (LOAD_TEXTURE2D_X(_CloudsDepthTexture, traceCoord + int2(x, y)).x != 0.0f)
|
|
cloudNeighborhood += 1.0f;
|
|
#else
|
|
if (GetCloudDepth_LDS(groupThreadId, int2(x, y)) != 0.0f)
|
|
cloudNeighborhood += 1.0f;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// If the target coordinate is out of the screen, we cannot use the history
|
|
float accumulationFactor = 0.0;
|
|
float sampleCount = 1.0;
|
|
if (validHistory && cloudNeighborhood != 0.0f)
|
|
{
|
|
// Define our accumation value
|
|
accumulationFactor = previousSampleCount >= 16.0 ? 0.94117647058 : (previousSampleCount / (previousSampleCount + 1.0));
|
|
accumulationFactor *= _TemporalAccumulationFactor * validityFactor * _CloudHistoryInvalidation;
|
|
sampleCount = min(previousSampleCount + 1.0, 16.0);
|
|
}
|
|
|
|
// Accumulate the result with the previous frame
|
|
#ifdef WITHOUT_LDS
|
|
previousResult = accumulationFactor * previousResult + (1.0 - accumulationFactor) * LOAD_TEXTURE2D_X(_CloudsLightingTexture, traceCoord);
|
|
#else
|
|
previousResult = accumulationFactor * previousResult + (1.0 - accumulationFactor) * GetCloudLighting_LDS(groupThreadId, int2(0, 0));
|
|
#endif
|
|
previousSampleCount = sampleCount;
|
|
previousDepth = currentDepth;
|
|
|
|
// If there are no clouds in the new pixel, we force the depth to zero. Otherwise, we are likely on a pixel
|
|
// which state is not stable and we take the maximum of both frames as we cannot interpolate between the depths.
|
|
previousCloudDepth = previousResult.w == 1.0 ? UNITY_RAW_FAR_CLIP_VALUE : currentCloudDepth;
|
|
}
|
|
else
|
|
{
|
|
// Reduce the history validity a bit
|
|
previousSampleCount *= validityFactor * _CloudHistoryInvalidation;
|
|
|
|
// If the target coordinate is out of the screen or the depth that was used to generate it
|
|
// is too different from the one of the current pixel, we cannot use the history
|
|
if (!validHistory)
|
|
{
|
|
// Structure that will hold everything
|
|
NeighborhoodUpsampleData3x3 upsampleData;
|
|
#ifdef WITHOUT_LDS
|
|
FillCloudReprojectionNeighborhoodData_NOLDS(traceCoord, localIndex, upsampleData);
|
|
#else
|
|
FillCloudReprojectionNeighborhoodData(groupThreadId, localIndex, upsampleData);
|
|
#endif
|
|
// Make sure that at least one of the pixels in the neighborhood can be used
|
|
bool rejectNeighborhood;
|
|
int closestNeighbor = 4;
|
|
OverrideMaskValues(currentDepth, upsampleData, rejectNeighborhood, closestNeighbor);
|
|
|
|
if (rejectNeighborhood)
|
|
{
|
|
// We don't have any valid history and there is no neighbor that is usable, we consider that we have no clouds.
|
|
previousResult = float4(0.0, 0.0, 0.0, 1.0);
|
|
previousSampleCount = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
// We don't have any history for this pixel, but there is at least one neighbor that can be used in the current frame tracing
|
|
previousSampleCount = 1.0f;
|
|
previousResult = BilUpColor3x3(currentDepth, upsampleData);
|
|
|
|
// Due to numerical precision issues, upscaling a bunch of 1.0 can lead to a slightly lower number, this fixes it.
|
|
if (EvaluateRegionEmptiness(upsampleData) == 1.0)
|
|
previousResult = float4(0, 0, 0, 1);
|
|
}
|
|
#ifdef WITHOUT_LDS
|
|
previousCloudDepth = LOAD_TEXTURE2D_X(_CloudsDepthTexture, traceCoord + IndexToLocalOffsetCoords[closestNeighbor]).x;
|
|
#else
|
|
previousCloudDepth = GetCloudDepth_LDS(groupThreadId, IndexToLocalOffsetCoords[closestNeighbor]);
|
|
#endif
|
|
}
|
|
previousDepth = currentDepth;
|
|
}
|
|
|
|
// Make sure this doesn't go outside of the [0, 1] interval
|
|
previousResult.w = saturate(previousResult.w);
|
|
|
|
// Accumulate the result with the previous frame
|
|
_CloudsLightingTextureRW[COORD_TEXTURE2D_X(intermediateCoord)] = previousResult;
|
|
_CloudsAdditionalTextureRW[COORD_TEXTURE2D_X(intermediateCoord)] = float3(previousSampleCount, previousDepth, previousCloudDepth);
|
|
}
|
|
|
|
[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;
|
|
|
|
#ifndef WITHOUT_LDS
|
|
// 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
|
|
|
|
#ifdef WITHOUT_LDS
|
|
// Average the depth of the cloud
|
|
float currentCloudDepth = LOAD_TEXTURE2D_X(_CloudsDepthTexture, traceCoord).x;
|
|
#else
|
|
// Average the depth of the cloud
|
|
float currentCloudDepth = GetCloudDepth_LDS(groupThreadId, int2(0, 0));
|
|
#endif
|
|
|
|
float cloudCloudDepth = 0;
|
|
float currentDepth = LOAD_TEXTURE2D_X(_HalfResDepthBuffer, intermediateCoord).x;
|
|
float4 cloudLighting = 0;
|
|
|
|
// Compute the local index that tells us the index of this pixel, the strategy for reprojection is a bit different in both cases
|
|
int localIndex = (intermediateCoord.x & 1) + (intermediateCoord.y & 1) * 2;
|
|
int currentIndex = _EnableIntegration ? ComputeCheckerBoardIndex(intermediateCoord / 2, _SubPixelIndex) : 0;
|
|
if (localIndex == currentIndex)
|
|
{
|
|
// Accumulate the result with the previous frame
|
|
#ifdef WITHOUT_LDS
|
|
cloudLighting = LOAD_TEXTURE2D_X(_CloudsLightingTexture, traceCoord);
|
|
#else
|
|
cloudLighting = GetCloudLighting_LDS(groupThreadId, int2(0, 0));
|
|
#endif
|
|
cloudCloudDepth = currentCloudDepth;
|
|
}
|
|
else
|
|
{
|
|
// Structure that will hold everything
|
|
NeighborhoodUpsampleData3x3 upsampleData;
|
|
#ifdef WITHOUT_LDS
|
|
FillCloudReprojectionNeighborhoodData_NOLDS(traceCoord, localIndex, upsampleData);
|
|
#else
|
|
FillCloudReprojectionNeighborhoodData(groupThreadId, localIndex, upsampleData);
|
|
#endif
|
|
// Make sure that at least one of the pixels in the neighborhood can be used
|
|
float rejectNeighborhood;
|
|
int closestNeighbor;
|
|
OverrideMaskValues(currentDepth, upsampleData, rejectNeighborhood, closestNeighbor);
|
|
|
|
// 1.0 if we were able to produce a value 0.0 if we failed to
|
|
if (rejectNeighborhood)
|
|
{
|
|
// We don't have any valid history and there is no neighbor that is usable
|
|
cloudLighting = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
// We don't have any history for this pixel, but there is at least one neighbor that can be used in the current frame tracing
|
|
cloudLighting = BilUpColor3x3(currentDepth, upsampleData);
|
|
}
|
|
#ifdef WITHOUT_LDS
|
|
cloudCloudDepth = LOAD_TEXTURE2D_X(_CloudsDepthTexture, traceCoord + IndexToLocalOffsetCoords[closestNeighbor]).x;
|
|
#else
|
|
cloudCloudDepth = GetCloudDepth_LDS(groupThreadId, IndexToLocalOffsetCoords[closestNeighbor]);
|
|
#endif
|
|
|
|
// Due to numerical precision issues, upscaling a bunch of 1.0 can lead to a slightly lower number, this fixes it.
|
|
if (EvaluateRegionEmptiness(upsampleData) == 1.0)
|
|
cloudLighting = float4(0, 0, 0, 1);
|
|
}
|
|
|
|
// Make sure this doesn't go outside of the [0, 1] interval
|
|
cloudLighting.w = saturate(cloudLighting.w);
|
|
|
|
// Accumulate the result with the previous frame
|
|
_CloudsLightingTextureRW[COORD_TEXTURE2D_X(intermediateCoord)] = cloudLighting;
|
|
_CloudsAdditionalTextureRW[COORD_TEXTURE2D_X(intermediateCoord)] = float3(1, currentDepth, cloudCloudDepth);
|
|
}
|
|
|
|
// Constant buffer where all variables should land
|
|
CBUFFER_START(VolumetricCloudsUpscaleConstantBuffer)
|
|
float2 _UpperScreenSize;
|
|
CBUFFER_END
|
|
|
|
RW_TEXTURE2D_X(float4, _VolumetricCloudsLightingTextureRW);
|
|
RW_TEXTURE2D_X(float, _VolumetricCloudsDepthTextureRW);
|
|
|
|
void FillLDSUpscale(uint groupIndex, uint2 groupOrigin)
|
|
{
|
|
// Define which value we will be acessing with this worker thread
|
|
int acessCoordX = groupIndex % 6;
|
|
int acessCoordY = groupIndex / 6;
|
|
|
|
// Everything we are accessing is in intermediate res (half rez).
|
|
uint2 traceGroupOrigin = groupOrigin / 2;
|
|
|
|
// The initial position of the access
|
|
int2 originXY = traceGroupOrigin - int2(1, 1);
|
|
|
|
// Compute the sample position
|
|
int2 sampleCoord = int2(clamp(originXY.x + acessCoordX, 0, _IntermediateScreenSize.x - 1), clamp(originXY.y + acessCoordY, 0, _IntermediateScreenSize.y - 1));
|
|
|
|
// Read the sample value
|
|
float4 sampleVal = LOAD_TEXTURE2D_X(_VolumetricCloudsTexture, sampleCoord);
|
|
float3 depthStatusValue = LOAD_TEXTURE2D_X(_DepthStatusTexture, sampleCoord).xyz;
|
|
|
|
// Store into the LDS
|
|
gs_cacheR[groupIndex] = sampleVal.r;
|
|
gs_cacheG[groupIndex] = sampleVal.g;
|
|
gs_cacheB[groupIndex] = sampleVal.b;
|
|
gs_cacheA[groupIndex] = sampleVal.a;
|
|
gs_cacheDP[groupIndex] = depthStatusValue.y;
|
|
gs_cachePS[groupIndex] = saturate(depthStatusValue.x);
|
|
gs_cacheDC[groupIndex] = depthStatusValue.z;
|
|
}
|
|
|
|
[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;
|
|
|
|
#ifndef WITHOUT_LDS
|
|
// 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 highDepth = LOAD_TEXTURE2D_X(_DepthTexture, finalCoord.xy).x;
|
|
|
|
// Compute the index of the pixel in the 2x2 region (L->R, T->B)
|
|
uint subRegionIndex = (finalCoord.x & 1) + (finalCoord.y & 1) * 2;
|
|
|
|
// Structure that will hold everything
|
|
NeighborhoodUpsampleData3x3 upsampleData;
|
|
|
|
#ifndef WITHOUT_LDS
|
|
// Fill the sample data
|
|
FillCloudUpscaleNeighborhoodData(groupThreadId.xy, subRegionIndex, upsampleData);
|
|
#else
|
|
// Fill the sample data
|
|
FillCloudUpscaleNeighborhoodData_NOLDS(halfResCoord, subRegionIndex, upsampleData);
|
|
#endif
|
|
|
|
// This flags allows us to track if at least one of the contributing pixels has some clouds
|
|
int closestNeighbor;
|
|
bool rejectedNeighborhood;
|
|
OverrideMaskValues(highDepth, upsampleData, rejectedNeighborhood, closestNeighbor);
|
|
|
|
// Do the bilateral upscale
|
|
float4 currentClouds = BilUpColor3x3(highDepth, upsampleData);
|
|
|
|
// Read the fallback value and use it if we defined that it was impossible for us to do something about it
|
|
if (rejectedNeighborhood)
|
|
currentClouds = float4(0.0, 0.0, 0.0, 1.0);
|
|
|
|
// De-tonemap the inscattering value
|
|
currentClouds.w = saturate(currentClouds.w);
|
|
|
|
// Due to numerical precision issues, upscaling a bunch of 1.0 can lead to a slightly lower number, this fixes it.
|
|
if (EvaluateRegionEmptiness(upsampleData) == 1.0)
|
|
currentClouds = float4(0, 0, 0, 1);
|
|
|
|
// We cannot simply pick the low res depth that ressembles the most the full resolution pixel
|
|
// Two cases are possible:
|
|
// - The final pixel doesn't have any clouds. In this case, we don't care about the depth.
|
|
// - The final pixel has some amount of clouds (which doesn't neccesarly map to any specific pixel in the neighborhood as it has been interpolated).
|
|
// In the second this case we need to take the average depth (in linear space) of the contributing pixels (the one that have some clouds in them).
|
|
#ifdef WITHOUT_LDS
|
|
float cloudDepth = currentClouds.w != 1.0 ? EvaluateUpscaledCloudDepth_NOLDS(halfResCoord, upsampleData) : UNITY_RAW_FAR_CLIP_VALUE;
|
|
#else
|
|
//float cloudDepth = GetCloudDepth_LDS(groupThreadId, IndexToLocalOffsetCoords[closestNeighbor]);
|
|
float cloudDepth = currentClouds.w != 1.0 ? EvaluateUpscaledCloudDepth(groupThreadId, upsampleData) : UNITY_RAW_FAR_CLIP_VALUE;
|
|
#endif
|
|
|
|
#if defined(PERCEPTUAL_TRANSMITTANCE)
|
|
// Estimate the transmittance that shall be used
|
|
float4 currentColor = _CameraColorTexture[COORD_TEXTURE2D_X(finalCoord.xy)];
|
|
float finalTransmittance = EvaluateFinalTransmittance(currentColor.rgb, currentClouds.w);
|
|
#else
|
|
float finalTransmittance = _CubicTransmittance ? currentClouds.a * currentClouds.a : currentClouds.a;
|
|
#endif
|
|
|
|
// Store the upscaled result only, composite in later pass.
|
|
_VolumetricCloudsLightingTextureRW[COORD_TEXTURE2D_X(finalCoord.xy)] = float4(currentClouds.xyz, finalTransmittance);
|
|
_VolumetricCloudsDepthTextureRW[COORD_TEXTURE2D_X(finalCoord.xy)] = cloudDepth;
|
|
}
|
|
|
|
[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;
|
|
|
|
// Grab the depth value of the pixel
|
|
float highDepth = LOAD_TEXTURE2D_X(_DepthTexture, finalCoord.xy).x;
|
|
float4 sampleVal = LOAD_TEXTURE2D_X(_VolumetricCloudsTexture, finalCoord.xy);
|
|
|
|
// Do the bilateral upscale
|
|
float4 currentClouds = sampleVal;
|
|
|
|
// De-tonemap the inscattering value
|
|
currentClouds.w = saturate(currentClouds.w);
|
|
|
|
float cloudsDepth = LOAD_TEXTURE2D_X(_DepthStatusTexture, finalCoord.xy).z;
|
|
|
|
#if defined(PERCEPTUAL_TRANSMITTANCE)
|
|
// Estimate the transmittance that shall be used
|
|
float4 currentColor = _CameraColorTexture[COORD_TEXTURE2D_X(finalCoord.xy)];
|
|
float finalTransmittance = EvaluateFinalTransmittance(currentColor.rgb, currentClouds.w);
|
|
#else
|
|
float finalTransmittance = _CubicTransmittance ? currentClouds.a * currentClouds.a : currentClouds.a;
|
|
#endif
|
|
|
|
// Store the upscaled result only, composite in later pass.
|
|
_VolumetricCloudsLightingTextureRW[COORD_TEXTURE2D_X(finalCoord.xy)] = float4(currentClouds.xyz, finalTransmittance);
|
|
_VolumetricCloudsDepthTextureRW[COORD_TEXTURE2D_X(finalCoord.xy)] = cloudsDepth;
|
|
}
|