-
Notifications
You must be signed in to change notification settings - Fork 871
Expand file tree
/
Copy pathVolumetricClouds.compute
More file actions
343 lines (278 loc) · 14.4 KB
/
VolumetricClouds.compute
File metadata and controls
343 lines (278 loc) · 14.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch switch2
// 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.zw - 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
float2 historyUVMax = 1.0 - 0.5 * _IntermediateScreenSize.zw - 0.000001; // To avoid lerp with garbage pixels
if (all(0.0 <= float4(historyUV, historyUVMax - 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
bool currentIsSky = currentSceneDepth == UNITY_RAW_FAR_CLIP_VALUE;
float4 lightingMin = float4(FLT_MAX, FLT_MAX, FLT_MAX, 1.0);
float4 lightingMax = float4(0, 0, 0, 0.0);
int skySampleCount = 0;
if(currentIsSky)
{
for (int y = -1; y <= 1; ++y)
{
for (int x = -1; x <= 1; ++x)
{
CloudReprojectionData data = GetCloudReprojectionDataSample(threadCoord, int2(x, y));
bool sampleIsSky = data.pixelDepth == UNITY_RAW_FAR_CLIP_VALUE;
if (sampleIsSky)
{
lightingMin = min(lightingMin, data.cloudLighting);
lightingMax = max(lightingMax, data.cloudLighting);
skySampleCount++;
}
}
}
// Only apply clamping if we have enough sky samples (at least 5 out of 9)
if (skySampleCount >= 5)
{
// Modulate validity factor based on sky sample ratio, the more samples are sky, the more ghosting reduction
float skyRatio = skySampleCount / 9.0;
previousColor = ClipCloudsToRegion(previousColor, lightingMin, lightingMax, skyRatio);
validityFactor *= skyRatio;
}
}
#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);
}