IVSmoke 1.0
Loading...
Searching...
No Matches
IVSmokeRayMarchPipeline.h
1// Copyright (c) 2026, Team SDB. All rights reserved.
2
3#pragma once
4
5#include "CoreMinimal.h"
6#include "GlobalShader.h"
7#include "RenderGraphUtils.h"
8#include "SceneTexturesConfig.h"
9#include "SceneView.h"
10#include "Shader.h"
11#include "ShaderCompilerCore.h"
12#include "ShaderParameterStruct.h"
13
14// Forward declarations
16
17//~==============================================================================
18// Occupancy System Configuration
19
20/**
21 * Occupancy system configuration constants.
22 * Tile-based occupancy for efficient empty space skipping.
23 *
24 * Memory Layout (1080p):
25 * TileCount: 120 × 68 tiles (W/16 × H/16)
26 * StepSlices: 32 (128 steps / 4)
27 * Occupancy Texture: 120 × 68 × 32 = 261,120 texels
28 * Per-texel: uint4 (128 bits for 128 volumes)
29 * Total Memory: ~8.4 MB (View + Light)
30 */
32{
33 /** Tile size in pixels (16×16 = 256 pixels per tile). */
34 static constexpr uint32 TileSizeX = 16;
35 static constexpr uint32 TileSizeY = 16;
36
37 /** Step divisor for depth slicing (128 steps / 4 = 32 slices). */
38 static constexpr uint32 StepDivisor = 4;
39
40 /** Maximum supported volumes (128 = uint4 bitmask). */
41 static constexpr uint32 MaxVolumes = 128;
42
43 /** Thread group size for tile setup (64×1 threads for parallel Bitonic Sort). */
44 static constexpr uint32 TileSetupThreadsX = 64;
45 static constexpr uint32 TileSetupThreadsY = 1;
46
47 /** Thread group size for occupancy build (8×8×4). */
48 static constexpr uint32 OccupancyBuildThreadsX = 8;
49 static constexpr uint32 OccupancyBuildThreadsY = 8;
50 static constexpr uint32 OccupancyBuildThreadsZ = 4;
51};
52
53//~==============================================================================
54// GPU Data Structures
55
56/**
57 * Per-tile metadata computed in Pass 0.
58 * Contains depth range and 128-bit volume mask for sparse iteration.
59 *
60 * Memory: 48 bytes (16-byte aligned, cache-friendly)
61 */
63{
64 /** Minimum linear depth in tile (near plane). */
65 float Near;
66
67 /** Maximum linear depth in tile (far plane, clamped to max ray distance). */
68 float Far;
69
70 /** Step size for this tile: (Far - Near) / (StepSliceCount * StepDivisor). */
71 float StepSize;
72
73 /**
74 * Total ray-volume intersection length (for early rejection).
75 * Computed using interval merging to correctly handle overlapping volumes.
76 * If zero, no volumes intersect this tile's center ray.
77 */
79
80 /**
81 * 128-bit volume mask for sparse iteration.
82 * Each bit indicates whether the corresponding volume intersects this tile.
83 * Used by OccupancyBuild for efficient volume iteration.
84 */
85 uint32 VolumeMask128[4];
86
87 /**
88 * Maximum distance for light marching from this tile.
89 * Currently unused - light march uses GlobalAABB per-pixel instead.
90 */
92
93 /** Padding for 48-byte alignment. */
94 float Padding[3];
95};
96
97static_assert(sizeof(FIVSmokeTileData) == 48, "FIVSmokeTileData must be 48 bytes");
98
99//~==============================================================================
100// Pass 0: Tile Setup Compute Shader
101
102/**
103 * Tile Setup compute shader (Pass 0).
104 * Computes per-tile depth range and quick volume mask using wave reduction.
105 *
106 * Dispatch: (TileCountX, TileCountY, 1)
107 * Each thread group processes one tile (8×8 threads, 2×2 pixels each).
108 */
109class IVSMOKE_API FIVSmokeTileSetupCS : public FGlobalShader
110{
111public:
112 static constexpr uint32 ThreadGroupSizeX = FIVSmokeOccupancyConfig::TileSetupThreadsX;
113 static constexpr uint32 ThreadGroupSizeY = FIVSmokeOccupancyConfig::TileSetupThreadsY;
114 static constexpr uint32 ThreadGroupSizeZ = 1;
115 static constexpr const TCHAR* EventName = TEXT("IVSmokeTileSetupCS");
116
117 DECLARE_GLOBAL_SHADER(FIVSmokeTileSetupCS);
118 SHADER_USE_PARAMETER_STRUCT(FIVSmokeTileSetupCS, FGlobalShader);
119
120 BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
121 // Output: Per-tile data buffer
122 SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer<FIVSmokeTileData>, TileDataBufferRW)
123
124 // Input: Scene depth for depth range calculation
125 SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneTextureUniformParameters, SceneTexturesStruct)
126
127 // Volume data for AABB intersection
128 SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<FIVSmokeVolumeGPUData>, VolumeDataBuffer)
129 SHADER_PARAMETER(uint32, NumActiveVolumes)
130
131 // Tile configuration
132 SHADER_PARAMETER(FIntPoint, TileCount)
133 SHADER_PARAMETER(uint32, StepSliceCount)
134 SHADER_PARAMETER(float, MaxRayDistance)
135
136 // Viewport info
137 SHADER_PARAMETER(FIntPoint, ViewportSize)
138 SHADER_PARAMETER(FIntPoint, ViewRectMin)
139
140 // Camera parameters for world position reconstruction
141 SHADER_PARAMETER(FVector3f, CameraPosition)
142 SHADER_PARAMETER(FVector3f, CameraForward)
143 SHADER_PARAMETER(FVector3f, CameraRight)
144 SHADER_PARAMETER(FVector3f, CameraUp)
145 SHADER_PARAMETER(float, TanHalfFOV)
146 SHADER_PARAMETER(float, AspectRatio)
147
148 // Depth conversion
149 SHADER_PARAMETER(FVector4f, InvDeviceZToWorldZTransform)
150 END_SHADER_PARAMETER_STRUCT()
151
152 static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
153 {
154 return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
155 }
156
157 static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
158 {
159 FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
160 OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE_X"), ThreadGroupSizeX);
161 OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE_Y"), ThreadGroupSizeY);
162 OutEnvironment.SetDefine(TEXT("TILE_SIZE_X"), FIVSmokeOccupancyConfig::TileSizeX);
163 OutEnvironment.SetDefine(TEXT("TILE_SIZE_Y"), FIVSmokeOccupancyConfig::TileSizeY);
164 OutEnvironment.SetDefine(TEXT("MAX_VOLUMES"), FIVSmokeOccupancyConfig::MaxVolumes);
165 OutEnvironment.SetDefine(TEXT("STEP_DIVISOR"), FIVSmokeOccupancyConfig::StepDivisor);
166 // Enable wave intrinsics (supported on SM5 with DX11.3+)
167 OutEnvironment.CompilerFlags.Add(CFLAG_WaveOperations);
168 }
169};
170
171//~==============================================================================
172// Pass 1: Occupancy Build Compute Shader
173
174/**
175 * Occupancy Build compute shader (Pass 1).
176 * Builds View and Light occupancy 3D textures using tile data.
177 *
178 * Dispatch: (ceil(TileCountX/8), ceil(TileCountY/8), ceil(StepSliceCount/4))
179 * Each texel stores a uint4 bitmask (128 bits for 128 volumes).
180 */
181class IVSMOKE_API FIVSmokeOccupancyBuildCS : public FGlobalShader
182{
183public:
184 static constexpr uint32 ThreadGroupSizeX = FIVSmokeOccupancyConfig::OccupancyBuildThreadsX;
185 static constexpr uint32 ThreadGroupSizeY = FIVSmokeOccupancyConfig::OccupancyBuildThreadsY;
186 static constexpr uint32 ThreadGroupSizeZ = FIVSmokeOccupancyConfig::OccupancyBuildThreadsZ;
187 static constexpr const TCHAR* EventName = TEXT("IVSmokeOccupancyBuildCS");
188
189 DECLARE_GLOBAL_SHADER(FIVSmokeOccupancyBuildCS);
190 SHADER_USE_PARAMETER_STRUCT(FIVSmokeOccupancyBuildCS, FGlobalShader);
191
192 BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
193 // Input: Tile data from Pass 0
194 SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<FIVSmokeTileData>, TileDataBuffer)
195
196 // Output: Occupancy 3D textures (uint4 = 128-bit bitmask)
197 SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture3D<uint4>, ViewOccupancyRW)
198 SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture3D<uint4>, LightOccupancyRW)
199
200 // Volume data
201 SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<FIVSmokeVolumeGPUData>, VolumeDataBuffer)
202 SHADER_PARAMETER(uint32, NumActiveVolumes)
203
204 // Tile/Occupancy configuration
205 SHADER_PARAMETER(FIntPoint, TileCount)
206 SHADER_PARAMETER(uint32, StepSliceCount)
207 SHADER_PARAMETER(uint32, StepDivisor)
208
209 // Camera parameters for frustum cell calculation
210 SHADER_PARAMETER(FVector3f, CameraPosition)
211 SHADER_PARAMETER(FVector3f, CameraForward)
212 SHADER_PARAMETER(FVector3f, CameraRight)
213 SHADER_PARAMETER(FVector3f, CameraUp)
214 SHADER_PARAMETER(float, TanHalfFOV)
215 SHADER_PARAMETER(float, AspectRatio)
216
217 // Light parameters for light occupancy
218 SHADER_PARAMETER(FVector3f, LightDirection)
219 SHADER_PARAMETER(float, MaxLightMarchDistance)
220 END_SHADER_PARAMETER_STRUCT()
221
222 static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
223 {
224 return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
225 }
226
227 static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
228 {
229 FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
230 OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE_X"), ThreadGroupSizeX);
231 OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE_Y"), ThreadGroupSizeY);
232 OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE_Z"), ThreadGroupSizeZ);
233 OutEnvironment.SetDefine(TEXT("TILE_SIZE_X"), FIVSmokeOccupancyConfig::TileSizeX);
234 OutEnvironment.SetDefine(TEXT("TILE_SIZE_Y"), FIVSmokeOccupancyConfig::TileSizeY);
235 OutEnvironment.SetDefine(TEXT("MAX_VOLUMES"), FIVSmokeOccupancyConfig::MaxVolumes);
236 }
237};
238
239//~==============================================================================
240// Pass 2: Ray March with Occupancy Compute Shader
241
242/**
243 * Multi-Volume Ray March compute shader with Occupancy optimization.
244 * Uses precomputed occupancy textures for efficient empty space skipping.
245 *
246 * Key optimizations:
247 * - Slice-level early-out (skip 4 steps at once if empty)
248 * - Sparse volume iteration using firstbitlow + bit clear
249 * - Light occupancy for light march optimization
250 *
251 * This is the main multi-volume ray march shader class.
252 * Uses Occupancy-based optimization (3-pass pipeline).
253 */
254class IVSMOKE_API FIVSmokeMultiVolumeRayMarchCS : public FGlobalShader
255{
256public:
257 static constexpr uint32 ThreadGroupSizeX = 8;
258 static constexpr uint32 ThreadGroupSizeY = 8;
259 static constexpr uint32 ThreadGroupSizeZ = 1;
260 static constexpr const TCHAR* EventName = TEXT("IVSmokeMultiVolumeRayMarchCS");
261
262 DECLARE_GLOBAL_SHADER(FIVSmokeMultiVolumeRayMarchCS);
263 SHADER_USE_PARAMETER_STRUCT(FIVSmokeMultiVolumeRayMarchCS, FGlobalShader);
264
265 BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
266 // Output (Dual Render Target)
267 SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, SmokeAlbedoTex)
268 SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, SmokeLocalPosAlphaTex)
269 SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, SmokeWorldPosDepthTex)
270
271 // Occupancy inputs
272 SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<FIVSmokeTileData>, TileDataBuffer)
273 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture3D<uint4>, ViewOccupancy)
274 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture3D<uint4>, LightOccupancy)
275
276 // Tile configuration
277 SHADER_PARAMETER(FIntPoint, TileCount)
278 SHADER_PARAMETER(uint32, StepSliceCount)
279 SHADER_PARAMETER(uint32, StepDivisor)
280
281 // Input Textures (same as original ray march)
282 SHADER_PARAMETER_RDG_TEXTURE(Texture3D, NoiseVolume)
283 SHADER_PARAMETER(float, NoiseUVMul)
284
285 // Samplers
286 SHADER_PARAMETER_SAMPLER(SamplerState, LinearBorder_Sampler)
287 SHADER_PARAMETER_SAMPLER(SamplerState, LinearRepeat_Sampler)
288
289 // Time
290 SHADER_PARAMETER(float, ElapsedTime)
291
292 // Viewport
293 SHADER_PARAMETER(FIntPoint, TexSize)
294 SHADER_PARAMETER(FVector2f, ViewportSize)
295 SHADER_PARAMETER(FVector2f, ViewRectMin)
296
297 // Camera
298 SHADER_PARAMETER(FVector3f, CameraPosition)
299 SHADER_PARAMETER(FVector3f, CameraForward)
300 SHADER_PARAMETER(FVector3f, CameraRight)
301 SHADER_PARAMETER(FVector3f, CameraUp)
302 SHADER_PARAMETER(float, TanHalfFOV)
303 SHADER_PARAMETER(float, AspectRatio)
304
305 // Ray Marching Setup
306 SHADER_PARAMETER(int32, MaxSteps)
307 SHADER_PARAMETER(float, MinStepSize)
308
309 // Multi-Volume Data
310 SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<FIVSmokeVolumeGPUData>, VolumeDataBuffer)
311 SHADER_PARAMETER(uint32, NumActiveVolumes)
312
313 // Packed Voxel Data
314 SHADER_PARAMETER(int, PackedInterval)
315 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture3D, PackedVoxelAtlas)
316 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture3D, PackedHoleAtlas)
317 SHADER_PARAMETER(FIntVector, VoxelTexSize)
318 SHADER_PARAMETER(FIntVector, PackedVoxelTexSize)
319 SHADER_PARAMETER(FIntVector, VoxelAtlasCount)
320 SHADER_PARAMETER(FIntVector, HoleTexSize)
321 SHADER_PARAMETER(FIntVector, PackedHoleTexSize)
322 SHADER_PARAMETER(FIntVector, HoleAtlasCount)
323
324 // Scene Textures
325 SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneTextureUniformParameters, SceneTexturesStruct)
326 SHADER_PARAMETER(FVector4f, InvDeviceZToWorldZTransform)
327
328 // Explicit SceneDepth dependency for RDG ordering (Pre-pass mode only)
329 // When bUseExplicitSceneDepth=1, shader uses this texture instead of SceneTexturesStruct.SceneDepthTexture
330 // This ensures RDG sees the dependency and orders Ray March BEFORE Depth Write
331 SHADER_PARAMETER_RDG_TEXTURE(Texture2D, SceneDepthTexture_RDGDependency)
332 SHADER_PARAMETER(int32, bUseExplicitSceneDepth)
333
334 // View (for BlueNoise access)
335 SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
336
337 // Global Smoke Parameters
338 SHADER_PARAMETER(float, GlobalAbsorption)
339 SHADER_PARAMETER(float, SmokeSize)
340 SHADER_PARAMETER(FVector3f, WindDirection)
341 SHADER_PARAMETER(float, VolumeRangeOffset)
342 SHADER_PARAMETER(float, VolumeEdgeNoiseFadeOffset)
343 SHADER_PARAMETER(float, VolumeEdgeFadeSharpness)
344
345 // Rayleigh Scattering
346 SHADER_PARAMETER(FVector3f, LightDirection)
347 SHADER_PARAMETER(FVector3f, LightColor)
348 SHADER_PARAMETER(float, ScatterScale)
349 SHADER_PARAMETER(float, ScatteringAnisotropy)
350
351 // Self-Shadowing (Light Marching)
352 SHADER_PARAMETER(int32, LightMarchingSteps)
353 SHADER_PARAMETER(float, LightMarchingDistance)
354 SHADER_PARAMETER(float, LightMarchingExpFactor)
355 SHADER_PARAMETER(float, ShadowAmbient)
356
357 // Global AABB for light march distance calculation (per-pixel ray-box intersection)
358 SHADER_PARAMETER(FVector3f, GlobalAABBMin)
359 SHADER_PARAMETER(FVector3f, GlobalAABBMax)
360
361 // External Shadowing (CSM)
362 SHADER_PARAMETER(int32, NumCascades)
363 SHADER_PARAMETER_RDG_TEXTURE(Texture2DArray, CSMDepthTextureArray)
364 SHADER_PARAMETER_RDG_TEXTURE(Texture2DArray, CSMVSMTextureArray)
365 SHADER_PARAMETER_SAMPLER(SamplerState, CSMSampler)
366 SHADER_PARAMETER_ARRAY(FMatrix44f, CSMViewProjectionMatrices, [8])
367 SHADER_PARAMETER_SCALAR_ARRAY(float, CSMSplitDistances, [8])
368 SHADER_PARAMETER(FVector3f, CSMCameraPosition)
369 SHADER_PARAMETER(float, CascadeBlendRange)
370 SHADER_PARAMETER_ARRAY(FVector4f, CSMLightCameraPositions, [8])
371 SHADER_PARAMETER_ARRAY(FVector4f, CSMLightCameraForwards, [8])
372
373 // VSM parameters
374 SHADER_PARAMETER(int32, bEnableVSM)
375 SHADER_PARAMETER(float, VSMMinVariance)
376 SHADER_PARAMETER(float, VSMLightBleedingReduction)
377
378 // Shadow common parameters
379 SHADER_PARAMETER(float, ShadowDepthBias)
380 SHADER_PARAMETER(float, ExternalShadowAmbient)
381
382 // Temporal (for TAA integration)
383 SHADER_PARAMETER(uint32, FrameNumber)
384 SHADER_PARAMETER(float, JitterIntensity)
385 END_SHADER_PARAMETER_STRUCT()
386
387 static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
388 {
389 return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
390 }
391
392 static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
393 {
394 FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
395 OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE_X"), ThreadGroupSizeX);
396 OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE_Y"), ThreadGroupSizeY);
397 OutEnvironment.SetDefine(TEXT("TILE_SIZE_X"), FIVSmokeOccupancyConfig::TileSizeX);
398 OutEnvironment.SetDefine(TEXT("TILE_SIZE_Y"), FIVSmokeOccupancyConfig::TileSizeY);
399 OutEnvironment.SetDefine(TEXT("MAX_VOLUMES"), FIVSmokeOccupancyConfig::MaxVolumes);
400 OutEnvironment.SetDefine(TEXT("USE_OCCUPANCY"), 1);
401 }
402};
403
404//~==============================================================================
405// Occupancy Resources Container
406
407/**
408 * Container for occupancy resources created per frame.
409 * Holds tile data buffer and occupancy textures.
410 */
412{
413 /** Per-tile metadata buffer. */
414 FRDGBufferRef TileDataBuffer;
415
416 /** View occupancy 3D texture (which volumes are present at each cell). */
417 FRDGTextureRef ViewOccupancy;
418
419 /** Light occupancy 3D texture (which volumes affect light at each cell). */
420 FRDGTextureRef LightOccupancy;
421
422 /** Tile count (W/16, H/16). */
423 FIntPoint TileCount;
424
425 /** Step slice count (MaxSteps / 4). */
427
429 bool IsValid() const;
430};
431
432//~==============================================================================
433// Occupancy Renderer Namespace
434
435namespace IVSmokeOccupancy
436{
437 /**
438 * Compute tile count from viewport size.
439 */
440 FIntPoint ComputeTileCount(const FIntPoint& ViewportSize);
441
442 /**
443 * Compute step slice count from max steps.
444 */
445 uint32 ComputeStepSliceCount(int32 MaxSteps);
446
447 /**
448 * Create occupancy resources for a frame.
449 */
450 FIVSmokeOccupancyResources CreateOccupancyResources(
451 FRDGBuilder& GraphBuilder,
452 const FIntPoint& TileCount,
453 uint32 StepSliceCount);
454
455 /**
456 * Add Pass 0: Tile Setup.
457 * Computes per-tile depth range and quick volume mask.
458 */
459 void AddTileSetupPass(
460 FRDGBuilder& GraphBuilder,
461 const FSceneView& View,
462 FRDGBufferRef VolumeDataBuffer,
463 uint32 NumActiveVolumes,
464 FRDGBufferRef OutTileDataBuffer,
465 const FIntPoint& TileCount,
466 uint32 StepSliceCount,
467 float MaxRayDistance,
468 const FIntPoint& ViewportSize,
469 const FIntPoint& ViewRectMin);
470
471 /**
472 * Add Pass 1: Occupancy Build.
473 * Builds View and Light occupancy 3D textures.
474 */
475 void AddOccupancyBuildPass(
476 FRDGBuilder& GraphBuilder,
477 const FSceneView& View,
478 FRDGBufferRef TileDataBuffer,
479 FRDGBufferRef VolumeDataBuffer,
480 uint32 NumActiveVolumes,
481 FRDGTextureRef OutViewOccupancy,
482 FRDGTextureRef OutLightOccupancy,
483 const FIntPoint& TileCount,
484 uint32 StepSliceCount,
485 const FVector3f& LightDirection,
486 float MaxLightMarchDistance,
487 const FIntPoint& ViewportSize);
488
489} // namespace IVSmokeOccupancy
static constexpr uint32 TileSizeX
static constexpr uint32 OccupancyBuildThreadsX
static constexpr uint32 MaxVolumes
static constexpr uint32 StepDivisor
static constexpr uint32 TileSetupThreadsX