3#include "IVSmokeRenderer.h"
5#include "IVSmokePostProcessPass.h"
6#include "IVSmokeSettings.h"
7#include "IVSmokeShaders.h"
8#include "IVSmokeSmokePreset.h"
9#include "IVSmokeVoxelVolume.h"
10#include "IVSmokeCSMRenderer.h"
11#include "IVSmokeVSMProcessor.h"
12#include "IVSmokeRayMarchPipeline.h"
13#include "Engine/TextureRenderTargetVolume.h"
14#include "PostProcess/PostProcessMaterialInputs.h"
15#include "SceneRenderTargetParameters.h"
16#include "IVSmokeHoleGeneratorComponent.h"
17#include "RenderGraphUtils.h"
18#include "Engine/DirectionalLight.h"
19#include "Components/DirectionalLightComponent.h"
20#include "EngineUtils.h"
21#include "Kismet/GameplayStatics.h"
22#include "Components/SceneComponent.h"
24#include "Engine/TextureRenderTarget2D.h"
25#include "Materials/MaterialRenderProxy.h"
26#include "MaterialShader.h"
27#include "MaterialShaderType.h"
28#include "IVSmokeVisualMaterialPreset.h"
29#include "PixelShaderUtils.h"
30#include "FXRenderingUtils.h"
39FIVSmokeRenderer::FIVSmokeRenderer() =
default;
41FIVSmokeRenderer::~FIVSmokeRenderer()
52 if (IsRunningCommandlet())
64 UE_LOG(LogIVSmoke, Log, TEXT(
"[FIVSmokeRenderer::Initialize] Renderer initialized. Global settings loaded from UIVSmokeSettings."));
70 FlushRenderingCommands();
72 if (IsValid(NoiseVolume))
74 NoiseVolume->RemoveFromRoot();
75 NoiseVolume =
nullptr;
83 FScopeLock Lock(&WorldDataMutex);
85 for (
auto& Pair : WorldDataMap)
87 if (Pair.Value.IsValid())
89 Pair.Value->CleanupCSM();
95 WorldEndPlayHandles.Empty();
102FPerWorldData::FPerWorldData() =
default;
104FPerWorldData::~FPerWorldData()
132 FScopeLock Lock(&WorldDataMutex);
134 TObjectKey<UWorld> WorldKey(World);
137 if (TSharedPtr<FPerWorldData>* Found = WorldDataMap.Find(WorldKey))
143 TSharedPtr<FPerWorldData> NewData = MakeShared<FPerWorldData>();
144 WorldDataMap.Add(WorldKey, NewData);
148 FDelegateHandle Handle = FWorldDelegates::OnWorldCleanup.AddLambda(
149 [
this, WorldKey](UWorld* CleaningWorld,
bool bSessionEnded,
bool bCleanupResources)
151 if (TObjectKey<UWorld>(CleaningWorld) == WorldKey)
157 WorldEndPlayHandles.Add(WorldKey, Handle);
159 UE_LOG(LogIVSmoke, Log, TEXT(
"[FIVSmokeRenderer::GetOrCreateWorldData] New world registered: %s"), *World->GetName());
171 FScopeLock Lock(&WorldDataMutex);
173 TObjectKey<UWorld> WorldKey(World);
174 TSharedPtr<FPerWorldData>* Found = WorldDataMap.Find(WorldKey);
176 return Found ? *Found :
nullptr;
186 UE_LOG(LogIVSmoke, Log, TEXT(
"[FIVSmokeRenderer::CleanupWorldData] Cleaning up world: %s"), *World->GetName());
190 FlushRenderingCommands();
192 FScopeLock Lock(&WorldDataMutex);
194 TObjectKey<UWorld> WorldKey(World);
197 if (FDelegateHandle* Handle = WorldEndPlayHandles.Find(WorldKey))
199 FWorldDelegates::OnWorldCleanup.Remove(*Handle);
200 WorldEndPlayHandles.Remove(WorldKey);
204 if (TSharedPtr<FPerWorldData>* Found = WorldDataMap.Find(WorldKey))
206 if (Found->IsValid())
208 (*Found)->CleanupCSM();
211 WorldDataMap.Remove(WorldKey);
216 TSharedPtr<FPerWorldData> WorldData =
GetWorldData(World);
217 return WorldData.IsValid() ? WorldData->bServerTimeSynced :
false;
223 if (WorldData.IsValid())
225 WorldData->bServerTimeSynced =
true;
226 WorldData->ServerTimeOffset = InServerTimeOffset;
237 FScopeLock Lock(&WorldDataMutex);
239 TObjectKey<UWorld> WorldKey(World);
240 TSharedPtr<FPerWorldData>* Found = WorldDataMap.Find(WorldKey);
242 if (Found && Found->IsValid())
244 (*Found)->CachedRenderData = MoveTemp(InRenderData);
247FIntVector FIVSmokeRenderer::GetAtlasTexCount(
const FIntVector& TexSize,
const int32 TexCount,
const int32 TexturePackInterval,
const int32 TexturePackMaxSize)
const
249 int QuotientX = TexturePackMaxSize / (TexSize.X + TexturePackInterval);
250 int QuotientY = TexturePackMaxSize / (TexSize.Y + TexturePackInterval);
251 int QuotientZ = TexturePackMaxSize / (TexSize.Z + TexturePackInterval);
253 FIntVector AtlasTexCount = FIntVector(1, 1, 1);
254 if (QuotientX < TexCount)
256 AtlasTexCount.X = QuotientX;
260 AtlasTexCount.X = TexCount;
263 int CurTexCount = TexCount / QuotientX + (TexCount % QuotientX == 0 ? 0 : 1);
264 if (QuotientY < CurTexCount)
266 AtlasTexCount.Y = QuotientY;
270 AtlasTexCount.Y = CurTexCount;
273 CurTexCount = CurTexCount / QuotientY + (CurTexCount % QuotientY == 0 ? 0 : 1);
274 if (QuotientZ < CurTexCount)
277 AtlasTexCount.Z = QuotientZ;
281 AtlasTexCount.Z = CurTexCount;
283 return AtlasTexCount;
286void FIVSmokeRenderer::InitializeCSM(TSharedPtr<FPerWorldData> WorldData, UWorld* World)
288 if (!World || !WorldData.IsValid())
300 if (!WorldData->CSMRenderer)
302 WorldData->CSMRenderer = MakeUnique<FIVSmokeCSMRenderer>();
306 if (!WorldData->CSMRenderer->IsInitialized())
308 WorldData->CSMRenderer->Initialize(
317 if (Settings->
bEnableVSM && !WorldData->VSMProcessor)
319 WorldData->VSMProcessor = MakeUnique<FIVSmokeVSMProcessor>();
323bool FIVSmokeRenderer::GetMainDirectionalLight(UWorld* World, FVector& OutDirection, FLinearColor& OutColor,
float& OutIntensity)
330 UDirectionalLightComponent* BestLight =
nullptr;
331 int32 BestIndex = INT_MAX;
334 for (TActorIterator<ADirectionalLight> It(World); It; ++It)
336 UDirectionalLightComponent* LightComp = Cast<UDirectionalLightComponent>(It->GetLightComponent());
337 if (LightComp && LightComp->IsUsedAsAtmosphereSunLight())
339 int32 Index = LightComp->GetAtmosphereSunLightIndex();
340 if (Index < BestIndex)
343 BestLight = LightComp;
351 for (TActorIterator<ADirectionalLight> It(World); It; ++It)
353 BestLight = Cast<UDirectionalLightComponent>(It->GetLightComponent());
364 OutDirection = -BestLight->GetComponentRotation().Vector();
365 OutColor = BestLight->GetLightColor();
366 OutIntensity = BestLight->Intensity;
373void FIVSmokeRenderer::CreateNoiseVolume()
375 constexpr int32 TexSize = FIVSmokeNoiseConfig::TexSize;
378 NoiseVolume = NewObject<UTextureRenderTargetVolume>();
379 NoiseVolume->AddToRoot();
380 NoiseVolume->Init(TexSize, TexSize, TexSize, EPixelFormat::PF_R16F);
381 NoiseVolume->bCanCreateUAV =
true;
382 NoiseVolume->ClearColor = FLinearColor::Black;
383 NoiseVolume->SRGB =
false;
384 NoiseVolume->UpdateResourceImmediate(
true);
387 CachedNoiseVolumeSize = CalculateImageBytes(TexSize, TexSize, TexSize, PF_R16F);
390 FTextureRenderTargetResource* RenderTargetResource = NoiseVolume->GameThread_GetRenderTargetResource();
391 if (!RenderTargetResource)
393 UE_LOG(LogIVSmoke, Error, TEXT(
"[FIVSmokeRenderer::CreateNoiseVolume] Failed to get render target resource"));
397 ENQUEUE_RENDER_COMMAND(IVSmokeGenerateNoise)(
398 [RenderTargetResource](FRHICommandListImmediate& RHICmdList)
400 FRDGBuilder GraphBuilder(RHICmdList);
401 FRDGTextureRef NoiseTexture = GraphBuilder.RegisterExternalTexture(
402 CreateRenderTarget(RenderTargetResource->TextureRHI, TEXT(
"IVSmokeNoiseVolume"))
405 FRDGTextureUAVRef OutputUAV = GraphBuilder.CreateUAV(NoiseTexture);
407 auto* Parameters = GraphBuilder.AllocParameters<FIVSmokeNoiseGeneratorGlobalCS::FParameters>();
408 Parameters->RWNoiseTex = OutputUAV;
409 Parameters->TexSize = FUintVector3(FIVSmokeNoiseConfig::TexSize, FIVSmokeNoiseConfig::TexSize, FIVSmokeNoiseConfig::TexSize);
410 Parameters->Octaves = FIVSmokeNoiseConfig::Octaves;
411 Parameters->Wrap = FIVSmokeNoiseConfig::Wrap;
412 Parameters->AxisCellCount = FIVSmokeNoiseConfig::AxisCellCount;
413 Parameters->Amplitude = FIVSmokeNoiseConfig::Amplitude;
414 Parameters->CellSize = FIVSmokeNoiseConfig::CellSize;
415 Parameters->Seed = FIVSmokeNoiseConfig::Seed;
417 TShaderMapRef<FIVSmokeNoiseGeneratorGlobalCS> ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel));
419 FIntVector GroupCount(
420 FMath::DivideAndRoundUp(FIVSmokeNoiseConfig::TexSize, 8),
421 FMath::DivideAndRoundUp(FIVSmokeNoiseConfig::TexSize, 8),
422 FMath::DivideAndRoundUp(FIVSmokeNoiseConfig::TexSize, 8)
425 GraphBuilder.AddPass(
426 RDG_EVENT_NAME(
"IVSmokeNoiseGeneration"),
428 ERDGPassFlags::Compute,
429 [Parameters, ComputeShader, GroupCount](FRHIComputeCommandList& RHICmdList)
431 FComputeShaderUtils::Dispatch(RHICmdList, ComputeShader, *Parameters, GroupCount);
434 GraphBuilder.Execute();
452 return GetDefault<UIVSmokeSmokePreset>();
461 check(IsInGameThread());
465 if (!World || InVolumes.Num() == 0)
478 if (!WorldData.IsValid())
485 const uint32 CurrentFrameNumber = GFrameNumber;
486 if (WorldData->LastPreparedFrameNumber == CurrentFrameNumber)
490 return WorldData->GameThreadCachedRenderData;
492 WorldData->LastPreparedFrameNumber = CurrentFrameNumber;
495 TArray<AIVSmokeVoxelVolume*> FilteredVolumes;
498 UE_LOG(LogIVSmoke, Warning,
499 TEXT(
"[FIVSmokeRenderer::PrepareRenderData] Volume count (%d) exceeds maximum (%d). "
500 "Farthest volumes from camera will be excluded."),
505 FilteredVolumes = InVolumes;
508 const float DistA = FVector::DistSquared(CameraPosition, A.GetActorLocation());
509 const float DistB = FVector::DistSquared(CameraPosition, B.GetActorLocation());
510 return DistA < DistB;
517 const TArray<AIVSmokeVoxelVolume*>& VolumesToProcess = (FilteredVolumes.Num() > 0) ? FilteredVolumes : InVolumes;
522 int32 ValidVolumeCount = 0;
527 if (ValidVolumeCount == 0)
535 Result.VolumeCount = ValidVolumeCount;
538 if (Result.VolumeCount == 0)
545 Result.HoleTextureSizes.Reserve(Result.VolumeCount);
554 if (FTextureRHIRef HoleTex = HoleComp->GetHoleTextureRHI())
556 Result.HoleResolution = HoleTex->GetSizeXYZ();
564 if (Result.HoleResolution == FIntVector::ZeroValue)
566 Result.HoleResolution = FIntVector(64, 64, 64);
570 const int32 TexturePackInterval = 4;
571 TArray<float> VoxelIntervalData;
574 FIntVector VoxelAtlasResolution = FIntVector(
577 Result.
VoxelResolution.Z * Result.VolumeCount + TexturePackInterval * (Result.VolumeCount - 1)
579 int32 TotalVoxelSize = VoxelAtlasResolution.X * VoxelAtlasResolution.Y * VoxelAtlasResolution.Z;
587 int32 ValidVolumeIndex = 0;
588 for (int32 i = 0; i < VolumesToProcess.Num(); ++i)
591 if (!IsValid(Volume))
603 if (!ensure(VoxelBirthTimes.Num() == ExpectedVoxelCount && VoxelDeathTimes.Num() == ExpectedVoxelCount))
605 UE_LOG(LogIVSmoke, Error, TEXT(
"[PrepareRenderData] %s: Buffer size mismatch - this should never happen if ShouldRender() is correct"), *Volume->GetName());
613 if (ValidVolumeIndex < Result.VolumeCount - 1)
622 if (IsValid(HoleComp))
628 Result.HoleTextureSizes.Add(HoleTex->GetSizeXYZ());
632 Result.HoleTextureSizes.Add(FIntVector::ZeroValue);
638 Result.HoleTextureSizes.Add(FIntVector::ZeroValue);
646 const FTransform VolumeTransform = Volume->GetActorTransform();
649 FVector HalfExtent = FVector(CenterOff) * VoxelSz;
650 FVector LocalMin = -HalfExtent;
651 FVector LocalMax = FVector(GridRes - CenterOff - FIntVector(1, 1, 1)) * VoxelSz;
652 FBox LocalBox(LocalMin, LocalMax);
653 FBox WorldBox = LocalBox.TransformBy(VolumeTransform);
660 FMemory::Memzero(&GPUData,
sizeof(GPUData));
662 GPUData.VoxelSize = VoxelSz;
666 GPUData.
GridResolution = FIntVector3(GridRes.X, GridRes.Y, GridRes.Z);
668 GPUData.
CenterOffset = FVector3f(CenterOff.X, CenterOff.Y, CenterOff.Z);
676 const bool bVoxelAABBValid = (VoxelAABBMin.X < VoxelAABBMax.X) &&
677 (VoxelAABBMin.Y < VoxelAABBMax.Y) &&
678 (VoxelAABBMin.Z < VoxelAABBMax.Z);
681 GPUData.VoxelWorldAABBMin = FVector3f(VoxelAABBMin);
682 GPUData.VoxelWorldAABBMax = FVector3f(VoxelAABBMax);
701 GPUData.
SmokeColor = FVector3f(0.8f, 0.8f, 0.8f);
711 check(ValidVolumeIndex == Result.VolumeCount);
723 Result.GlobalAbsorption = 0.1f;
738 if (VisualMaterialPreset)
743 Result.BlurStrength = VisualMaterialPreset->
BlurStrength;
753 Result.LightIntensity = 1.0f;
757 FVector AutoLightDir;
758 FLinearColor AutoLightColor;
759 float AutoLightIntensity;
761 if (GetMainDirectionalLight(World, AutoLightDir, AutoLightColor, AutoLightIntensity))
763 Result.LightDirection = AutoLightDir;
764 Result.LightIntensity = AutoLightIntensity;
769 Result.LightColor = AutoLightColor;
775 Result.LightDirection = FVector(0.0f, 0.0f, -1.0f);
776 Result.LightIntensity = 0.0f;
777 Result.LightColor = FLinearColor::Black;
809 const bool bAlreadyUpdatedThisFrame = (WorldData->LastCSMUpdateFrameNumber == CurrentFrameNumber);
811 if (!bAlreadyUpdatedThisFrame)
813 WorldData->LastCSMUpdateFrameNumber = CurrentFrameNumber;
816 InitializeCSM(WorldData, World);
818 if (WorldData->CSMRenderer && WorldData->CSMRenderer->IsInitialized())
821 bIsCapturingShadow =
true;
824 FVector CSMCameraPosition = FVector::ZeroVector;
825 FVector CSMCameraForward = FVector(1.0f, 0.0f, 0.0f);
828 if (APlayerController* PC = World->GetFirstPlayerController())
830 if (APlayerCameraManager* CameraManager = PC->PlayerCameraManager)
832 CSMCameraPosition = CameraManager->GetCameraLocation();
833 CSMCameraForward = CameraManager->GetCameraRotation().Vector();
838 WorldData->CSMRenderer->Update(
841 Result.LightDirection,
845 bIsCapturingShadow =
false;
851 if (WorldData->CSMRenderer && WorldData->CSMRenderer->IsInitialized() && WorldData->CSMRenderer->HasValidShadowData())
853 Result.
NumCascades = WorldData->CSMRenderer->GetNumCascades();
856 Result.CSMSplitDistances = WorldData->CSMRenderer->GetSplitDistances();
861 Result.CSMViewProjectionMatrices.SetNum(Result.
NumCascades);
862 Result.CSMLightCameraPositions.SetNum(Result.
NumCascades);
863 Result.CSMLightCameraForwards.SetNum(Result.
NumCascades);
871 Result.CSMVSMTextures[i] = WorldData->CSMRenderer->GetVSMTexture(i);
884 if (VolumesToProcess.Num() > 0 && IsValid(VolumesToProcess[0]))
886 Result.
GameTime = VolumesToProcess[0]->GetSyncWorldTimeSeconds();
894 WorldData->GameThreadCachedRenderData = Result;
903 FRDGBuilder& GraphBuilder,
904 const FSceneView& View,
905 const FPostProcessMaterialInputs& Inputs)
908 FScreenPassTextureSlice SceneColorSlice = Inputs.GetInput(EPostProcessMaterialInput::SceneColor);
909 if (!SceneColorSlice.IsValid())
911 return FScreenPassTexture();
914 FScreenPassTexture SceneColor(SceneColorSlice);
930 UWorld* World =
nullptr;
931 if (View.Family && View.Family->Scene)
933 World = View.Family->Scene->GetWorld();
942 TSharedPtr<FPerWorldData> WorldData =
GetWorldData(World);
943 if (!WorldData.IsValid())
952 FScopeLock Lock(&WorldDataMutex);
953 RenderData = WorldData->CachedRenderData;
962 FScreenPassRenderTarget Output = Inputs.OverrideOutput;
964 if (!Output.IsValid())
966 Output = FScreenPassRenderTarget(
969 ERenderTargetLoadAction::ELoad
974 const FIntPoint ViewportSize = SceneColor.ViewRect.Size();
975 const FIntPoint ViewRectMin = SceneColor.ViewRect.Min;
978 UpdateStatsIfNeeded(RenderData, ViewportSize);
988 UE_LOG(LogIVSmoke, Verbose, TEXT(
"[FIVSmokeRenderer::Render] View.State is null, skipping smoke rendering"));
993 FRDGTextureRef SmokeTex;
994 FRDGTextureRef SmokeLocalPosAlphaFull;
995 FRDGTextureRef SmokeWorldPosDepthFull;
996 FIntPoint EffectiveViewportSize;
998 FScopeLock Lock(&ViewDataMutex);
999 FPerViewData* ViewData = ViewDataMap.Find(View.State);
1000 if (!ViewData || !ViewData->bIsValid)
1004 UE_LOG(LogIVSmoke, Warning, TEXT(
"[FIVSmokeRenderer::Render] ViewData miss: ViewState=%p, ViewFamily=%p, FamilyFrame=%u, ViewDataMapSize=%d"),
1005 View.State, View.Family, View.Family ? View.Family->FrameNumber : 0, ViewDataMap.Num());
1011 SmokeTex = ViewData->SmokeTex;
1012 SmokeLocalPosAlphaFull = ViewData->LocalPosAlphaTex;
1013 SmokeWorldPosDepthFull = ViewData->WorldPosDepthTex;
1014 EffectiveViewportSize = ViewData->ViewportSize;
1017 FIntVector SceneSize = SceneColor.Texture->Desc.GetSize();
1018 FInt32Point SceneViewRectSize = SceneColor.ViewRect.Size();
1019 RDG_EVENT_SCOPE(GraphBuilder,
"IVSmoke_PostProcess_VisualComposite");
1026 FRDGTextureRef SmokeVisualTex = AddSmokeVisualPass(GraphBuilder, RenderData, View, SmokeTex, SmokeLocalPosAlphaFull, SmokeWorldPosDepthFull, SceneColor.Texture, EffectiveViewportSize);
1027 return FScreenPassTexture(SmokeVisualTex);
1031 AddCompositePass(GraphBuilder, RenderData, View, SceneColor.Texture, SmokeTex, Output, EffectiveViewportSize);
1032 return FScreenPassTexture(Output);
1039void FIVSmokeRenderer::AddCompositePass(
1040 FRDGBuilder& GraphBuilder,
1042 const FSceneView& View,
1043 FRDGTextureRef SceneTex,
1044 FRDGTextureRef SmokeTex,
1045 const FScreenPassRenderTarget& Output,
1046 const FIntPoint& ViewportSize)
1048 FGlobalShaderMap* ShaderMap = GetGlobalShaderMap(View.FeatureLevel);
1049 TShaderMapRef<FIVSmokeCompositePS> PixelShader(ShaderMap);
1051 auto* Parameters = GraphBuilder.AllocParameters<FIVSmokeCompositePS::FParameters>();
1052 Parameters->SceneTex = SceneTex;
1053 Parameters->SmokeTex = SmokeTex;
1054 Parameters->LinearClamp_Sampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
1055 Parameters->ViewportSize = FVector2f(ViewportSize);
1056 Parameters->ViewRectMin = FVector2f(Output.ViewRect.Min);
1057 Parameters->RenderTargets[0] = Output.GetRenderTargetBinding();
1067FRDGTextureRef FIVSmokeRenderer::AddCopyPass(
1068 FRDGBuilder& GraphBuilder,
1069 const FSceneView& View,
1070 FRDGTextureRef SourceTex,
1071 const FIntPoint& DestSize,
1072 const TCHAR* TexName)
1081 TexCreate_RenderTargetable | TexCreate_ShaderResource
1085 AddCopyPass(GraphBuilder, View, SourceTex, DestTex);
1090void FIVSmokeRenderer::AddCopyPass(
1091 FRDGBuilder& GraphBuilder,
1092 const FSceneView& View,
1093 FRDGTextureRef SourceTex,
1094 FRDGTextureRef DestTex)
1096 FGlobalShaderMap* ShaderMap = GetGlobalShaderMap(View.FeatureLevel);
1097 TShaderMapRef<FIVSmokeCopyPS> CopyShader(ShaderMap);
1099 const FIntPoint DestSize = DestTex->Desc.Extent;
1101 auto* Parameters = GraphBuilder.AllocParameters<FIVSmokeCopyPS::FParameters>();
1102 Parameters->MainTex = SourceTex;
1103 Parameters->LinearRepeat_Sampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
1104 Parameters->ViewportSize = FVector2f(DestSize);
1105 Parameters->RenderTargets[0] = FRenderTargetBinding(DestTex, ERenderTargetLoadAction::ENoAction);
1107 FScreenPassRenderTarget Output(
1109 FIntRect(0, 0, DestSize.X, DestSize.Y),
1110 ERenderTargetLoadAction::ENoAction
1118FRDGTextureRef FIVSmokeRenderer::AddUpsampleFilterPass(
1119 FRDGBuilder& GraphBuilder,
1121 const FSceneView& View,
1122 FRDGTextureRef SceneTex,
1123 FRDGTextureRef SmokeAlbedo,
1124 FRDGTextureRef SmokeLocalPosAlpha,
1125 const FIntPoint& TexSize,
1126 const FIntPoint& ViewRectMin)
1131 TEXT(
"IVSmokeUpsampleFilterTex"),
1136 FGlobalShaderMap* ShaderMap = GetGlobalShaderMap(View.FeatureLevel);
1137 TShaderMapRef<FIVSmokeUpsampleFilterPS> PixelShader(ShaderMap);
1138 auto* Parameters = GraphBuilder.AllocParameters<FIVSmokeUpsampleFilterPS::FParameters>();
1139 Parameters->SceneTex = SceneTex;
1140 Parameters->SmokeAlbedoTex = SmokeAlbedo;
1141 Parameters->SmokeLocalPosAlphaTex = SmokeLocalPosAlpha;
1142 Parameters->LinearClamp_Sampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
1144 Parameters->SharpenStrength = RenderData.SharpenStrength;
1145 Parameters->BlurStrength = RenderData.BlurStrength;
1146 Parameters->ViewportSize = TexSize;
1147 Parameters->ViewRectMin = FVector2f(ViewRectMin);
1148 Parameters->RenderTargets[0] = FRenderTargetBinding(SmokeTex, ERenderTargetLoadAction::ENoAction);
1149 FScreenPassRenderTarget Output(
1151 FIntRect(0, 0, TexSize.X, TexSize.Y),
1152 ERenderTargetLoadAction::ENoAction
1161FRDGTextureRef FIVSmokeRenderer::AddSmokeVisualPass(FRDGBuilder& GraphBuilder,
const FIVSmokePackedRenderData& RenderData,
const FSceneView& View, FRDGTextureRef SmokeTex, FRDGTextureRef SmokeLocalPosAlphaTex, FRDGTextureRef SmokeWorldPosDepthTex, FRDGTextureRef SceneTex,
const FIntPoint& TexSize)
1165 if (SmokeVisualMat ==
nullptr)
1171 FPostProcessMaterialInputs PostProcessInputs;
1174 PostProcessInputs.SetInput(GraphBuilder, EPostProcessMaterialInput::SceneColor, FScreenPassTexture(SmokeTex));
1177 PostProcessInputs.SetInput(GraphBuilder, EPostProcessMaterialInput::SeparateTranslucency, FScreenPassTexture(SmokeLocalPosAlphaTex));
1180 PostProcessInputs.SetInput(GraphBuilder, EPostProcessMaterialInput::PostTonemapHDRColor, FScreenPassTexture(SceneTex));
1183 PostProcessInputs.SetInput(GraphBuilder, EPostProcessMaterialInput::Velocity, FScreenPassTexture(SmokeWorldPosDepthTex));
1185 PostProcessInputs.SceneTextures = GetSceneTextureShaderParameters(View);
1195 TEXT(
"IVSmokeVisualTex"),
1198 TexCreate_RenderTargetable | TexCreate_ShaderResource
1200 PostProcessInputs.OverrideOutput = FScreenPassRenderTarget(OutputTexture, ERenderTargetLoadAction::ENoAction);
1202 AddPostProcessMaterialPass(GraphBuilder, View, PostProcessInputs, SmokeVisualMat);
1204 return OutputTexture;
1211void FIVSmokeRenderer::AddMultiVolumeRayMarchPass(
1212 FRDGBuilder& GraphBuilder,
1213 const FSceneView& View,
1215 FRDGTextureRef SmokeAlbedoTex,
1216 FRDGTextureRef SmokeLocalPosAlphaTex,
1217 FRDGTextureRef SmokeWorldPosDepthTex,
1218 const FIntPoint& TexSize,
1219 const FIntPoint& ViewportSize,
1220 const FIntPoint& ViewRectMin,
1221 FRDGTextureRef SceneDepthForDependency)
1223 const int32 VolumeCount = RenderData.VolumeCount;
1225 if (VolumeCount == 0 || !NoiseVolume || !RenderData.
bIsValid)
1231 UWorld* World =
nullptr;
1232 if (View.Family && View.Family->Scene)
1234 World = View.Family->Scene->GetWorld();
1236 TSharedPtr<FPerWorldData> WorldData = World ?
GetWorldData(World) : nullptr;
1244 const int32 TexturePackInterval = 4;
1245 const int32 TexturePackMaxSize = 2048;
1247 const FIntVector HoleResolution = RenderData.HoleResolution;
1249 if (VoxelResolution.X <= 0 || VoxelResolution.Y <= 0 || VoxelResolution.Z <= 0)
1251 UE_LOG(LogIVSmoke, Error, TEXT(
"[AddMultiVolumeRayMarchPass] Invalid VoxelResolution, aborting"));
1255 const FIntVector VoxelAtlasCount = GetAtlasTexCount(VoxelResolution, VolumeCount, TexturePackInterval, TexturePackMaxSize);
1256 const FIntVector HoleAtlasCount = GetAtlasTexCount(HoleResolution, VolumeCount, TexturePackInterval, TexturePackMaxSize);
1259 if (VoxelAtlasCount.X <= 0 || VoxelAtlasCount.Y <= 0 || VoxelAtlasCount.Z <= 0)
1261 UE_LOG(LogIVSmoke, Error, TEXT(
"[AddMultiVolumeRayMarchPass] Invalid VoxelAtlasCount (%d,%d,%d), likely VolumeCount=0, aborting"),
1262 VoxelAtlasCount.X, VoxelAtlasCount.Y, VoxelAtlasCount.Z);
1267 const FIntVector VoxelAtlasResolution = FIntVector(
1268 VoxelResolution.X * VoxelAtlasCount.X + TexturePackInterval * (VoxelAtlasCount.X - 1),
1269 VoxelResolution.Y * VoxelAtlasCount.Y + TexturePackInterval * (VoxelAtlasCount.Y - 1),
1270 VoxelResolution.Z * VoxelAtlasCount.Z + TexturePackInterval * (VoxelAtlasCount.Z - 1)
1272 const FIntVector VoxelAtlasFXAAResolution = VoxelAtlasResolution * 1;
1275 const FIntVector HoleAtlasResolution = FIntVector(
1276 HoleResolution.X * HoleAtlasCount.X + TexturePackInterval * (HoleAtlasCount.X - 1),
1277 HoleResolution.Y * HoleAtlasCount.Y + TexturePackInterval * (HoleAtlasCount.Y - 1),
1278 HoleResolution.Z * HoleAtlasCount.Z + TexturePackInterval * (HoleAtlasCount.Z - 1)
1282 FRDGTextureDesc VoxelAtlasDesc = FRDGTextureDesc::Create3D(
1283 VoxelAtlasResolution,
1285 FClearValueBinding::None,
1286 TexCreate_ShaderResource | TexCreate_UAV
1288 FRDGTextureRef PackedVoxelAtlas = GraphBuilder.CreateTexture(VoxelAtlasDesc, TEXT(
"IVSmoke_PackedVoxelAtlas"));
1290 FRDGTextureDesc VoxelAtlasFXAAResDesc = FRDGTextureDesc::Create3D(
1291 VoxelAtlasFXAAResolution,
1293 FClearValueBinding::None,
1294 TexCreate_ShaderResource | TexCreate_UAV
1296 FRDGTextureRef PackedVoxelAtlasFXAA = GraphBuilder.CreateTexture(VoxelAtlasFXAAResDesc, TEXT(
"IVSmoke_PackedVoxelAtlasFXAA"));
1299 AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(PackedVoxelAtlas), 0.0f);
1300 AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(PackedVoxelAtlasFXAA), 0.0f);
1302 FRDGTextureDesc HoleAtlasDesc = FRDGTextureDesc::Create3D(
1303 HoleAtlasResolution,
1305 FClearValueBinding::None,
1306 TexCreate_ShaderResource | TexCreate_UAV
1308 FRDGTextureRef PackedHoleAtlas = GraphBuilder.CreateTexture(HoleAtlasDesc, TEXT(
"IVSmoke_PackedHoleAtlas"));
1311 AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(PackedHoleAtlas), FLinearColor(0.0f, 0.0f, 0.0f, 1.0f));
1314 FRHICopyTextureInfo HoleCpyInfo;
1315 HoleCpyInfo.Size = HoleResolution;
1316 HoleCpyInfo.SourcePosition = FIntVector::ZeroValue;
1318 for (
int z = 0; z < HoleAtlasCount.Z; ++z)
1320 for (
int y = 0; y < HoleAtlasCount.Y; ++y)
1322 for (
int x = 0; x < HoleAtlasCount.X; ++x)
1324 int i = x + HoleAtlasCount.X * y + z * HoleAtlasCount.X * HoleAtlasCount.Y;
1337 FRDGTextureRef SourceTexture = GraphBuilder.RegisterExternalTexture(
1338 CreateRenderTarget(SourceRHI, TEXT(
"IVSmoke_CopyHoleSource"))
1341 HoleCpyInfo.DestPosition.X = x * (HoleResolution.X + TexturePackInterval);
1342 HoleCpyInfo.DestPosition.Y = y * (HoleResolution.Y + TexturePackInterval);
1343 HoleCpyInfo.DestPosition.Z = z * (HoleResolution.Z + TexturePackInterval);
1344 AddCopyTexturePass(GraphBuilder, SourceTexture, PackedHoleAtlas, HoleCpyInfo);
1352 UE_LOG(LogIVSmoke, Warning, TEXT(
"[AddMultiVolumeRayMarchPass] Empty render data (BirthTimes=%d, VolumeCount=%d), skipping"),
1358 FGlobalShaderMap* ShaderMap = GetGlobalShaderMap(View.FeatureLevel);
1360 FRDGBufferDesc BirthBufferDesc = FRDGBufferDesc::CreateStructuredDesc(
sizeof(
float), RenderData.
PackedVoxelBirthTimes.Num());
1361 FRDGBufferRef BirthBuffer = GraphBuilder.CreateBuffer(BirthBufferDesc, TEXT(
"IVSmoke_PackedBirthBuffer"));
1364 FRDGBufferDesc DeathBufferDesc = FRDGBufferDesc::CreateStructuredDesc(
sizeof(
float), RenderData.
PackedVoxelDeathTimes.Num());
1365 FRDGBufferRef DeathBuffer = GraphBuilder.CreateBuffer(DeathBufferDesc, TEXT(
"IVSmoke_PackedDeathBuffer"));
1369 FRDGBufferRef VolumeBuffer = GraphBuilder.CreateBuffer(VolumeBufferDesc, TEXT(
"IVSmokeVolumeDataBuffer"));
1373 TShaderMapRef<FIVSmokeStructuredToTextureCS> StructuredCopyShader(ShaderMap);
1374 auto* StructuredCopyParams = GraphBuilder.AllocParameters<FIVSmokeStructuredToTextureCS::FParameters>();
1375 StructuredCopyParams->Desti = GraphBuilder.CreateUAV(PackedVoxelAtlas);
1376 StructuredCopyParams->BirthTimes = GraphBuilder.CreateSRV(BirthBuffer);
1377 StructuredCopyParams->DeathTimes = GraphBuilder.CreateSRV(DeathBuffer);
1378 StructuredCopyParams->VolumeDataBuffer = GraphBuilder.CreateSRV(VolumeBuffer);
1379 StructuredCopyParams->TexSize = VoxelAtlasResolution;
1381 StructuredCopyParams->PackedInterval = TexturePackInterval;
1382 StructuredCopyParams->VoxelAtlasCount = VoxelAtlasCount;
1383 StructuredCopyParams->GameTime = RenderData.
GameTime;
1384 StructuredCopyParams->VolumeCount = VolumeCount;
1389 StructuredCopyShader,
1390 StructuredCopyParams,
1391 VoxelAtlasResolution
1395 TShaderMapRef<FIVSmokeVoxelFXAACS> VoxelFXAAShader(ShaderMap);
1396 auto* VoxelFXAAParams = GraphBuilder.AllocParameters<FIVSmokeVoxelFXAACS::FParameters>();
1398 VoxelFXAAParams->Desti = GraphBuilder.CreateUAV(PackedVoxelAtlasFXAA);
1399 VoxelFXAAParams->Source = GraphBuilder.CreateSRV(PackedVoxelAtlas);
1400 VoxelFXAAParams->LinearBorder_Sampler = TStaticSamplerState<SF_Bilinear, AM_Border, AM_Border, AM_Border>::GetRHI();
1401 VoxelFXAAParams->TexSize = VoxelAtlasFXAAResolution;
1402 VoxelFXAAParams->FXAASpanMax = Settings->
FXAASpanMax;
1403 VoxelFXAAParams->FXAARange = Settings->
FXAARange;
1411 VoxelAtlasFXAAResolution
1417 const FIntPoint TileCount = IVSmokeOccupancy::ComputeTileCount(ViewportSize);
1418 const uint32 StepSliceCount = IVSmokeOccupancy::ComputeStepSliceCount(RenderData.
MaxSteps);
1427 FVector3f GlobalAABBMin(1e10f, 1e10f, 1e10f);
1428 FVector3f GlobalAABBMax(-1e10f, -1e10f, -1e10f);
1431 GlobalAABBMin = FVector3f::Min(GlobalAABBMin, VolData.VolumeWorldAABBMin);
1432 GlobalAABBMax = FVector3f::Max(GlobalAABBMax, VolData.VolumeWorldAABBMax);
1438 const FVector3f CameraPos(View.ViewLocation);
1439 float MaxRayDistance = 0.0f;
1440 for (int32 i = 0; i < 8; i++)
1443 (i & 1) ? GlobalAABBMax.X : GlobalAABBMin.X,
1444 (i & 2) ? GlobalAABBMax.Y : GlobalAABBMin.Y,
1445 (i & 4) ? GlobalAABBMax.Z : GlobalAABBMin.Z
1447 MaxRayDistance = FMath::Max(MaxRayDistance, FVector3f::Dist(CameraPos, Corner));
1449 MaxRayDistance = FMath::Clamp(MaxRayDistance, 10000.0f, 1000000.0f);
1455 if (TileCount.X <= 0 || TileCount.Y <= 0)
1457 UE_LOG(LogIVSmoke, Error, TEXT(
"[AddMultiVolumeRayMarchPass] Invalid TileCount: %dx%d, aborting"), TileCount.X, TileCount.Y);
1460 if (StepSliceCount == 0)
1462 UE_LOG(LogIVSmoke, Error, TEXT(
"[AddMultiVolumeRayMarchPass] StepSliceCount is 0, aborting"));
1465 if (!FMath::IsFinite(MaxRayDistance) || MaxRayDistance <= 0.0f)
1467 UE_LOG(LogIVSmoke, Error, TEXT(
"[AddMultiVolumeRayMarchPass] Invalid MaxRayDistance: %.1f, aborting"), MaxRayDistance);
1474 IVSmokeOccupancy::AddTileSetupPass(
1490 IVSmokeOccupancy::AddOccupancyBuildPass(
1500 FVector3f(RenderData.LightDirection),
1501 RenderData.LightMarchingDistance > 0.0f ? RenderData.LightMarchingDistance : MaxRayDistance,
1508 TShaderMapRef<FIVSmokeMultiVolumeRayMarchCS> ComputeShader(ShaderMap);
1509 auto* Parameters = GraphBuilder.AllocParameters<FIVSmokeMultiVolumeRayMarchCS::FParameters>();
1512 Parameters->SmokeAlbedoTex = GraphBuilder.CreateUAV(FRDGTextureUAVDesc(SmokeAlbedoTex));
1513 Parameters->SmokeLocalPosAlphaTex = GraphBuilder.CreateUAV(FRDGTextureUAVDesc(SmokeLocalPosAlphaTex));
1514 Parameters->SmokeWorldPosDepthTex = GraphBuilder.CreateUAV(FRDGTextureUAVDesc(SmokeWorldPosDepthTex));
1517 Parameters->TileDataBuffer = GraphBuilder.CreateSRV(OccResources.
TileDataBuffer);
1518 Parameters->ViewOccupancy = GraphBuilder.CreateSRV(OccResources.
ViewOccupancy);
1519 Parameters->LightOccupancy = GraphBuilder.CreateSRV(OccResources.
LightOccupancy);
1522 Parameters->TileCount = TileCount;
1523 Parameters->StepSliceCount = StepSliceCount;
1527 FTextureRHIRef TextureRHI = NoiseVolume->GetRenderTargetResource()->GetRenderTargetTexture();
1528 FRDGTextureRef NoiseVolumeRDG = GraphBuilder.RegisterExternalTexture(
1529 CreateRenderTarget(TextureRHI, TEXT(
"IVSmokeNoiseVolume"))
1531 Parameters->NoiseVolume = NoiseVolumeRDG;
1535 Parameters->LinearBorder_Sampler = TStaticSamplerState<SF_Trilinear, AM_Border, AM_Border, AM_Border>::GetRHI();
1536 Parameters->LinearRepeat_Sampler = TStaticSamplerState<SF_Trilinear, AM_Wrap, AM_Wrap, AM_Wrap>::GetRHI();
1541 const float WorldServerTimeOffset = WorldData.IsValid() ? WorldData->ServerTimeOffset : 0.f;
1542 Parameters->ElapsedTime = View.Family->Time.GetRealTimeSeconds() + WorldServerTimeOffset;
1545 Parameters->TexSize = FIntPoint(TexSize.X, TexSize.Y);
1546 Parameters->ViewportSize = FVector2f(ViewportSize);
1547 Parameters->ViewRectMin = FVector2f(ViewRectMin);
1550 const FViewMatrices& ViewMatrices = View.ViewMatrices;
1551 Parameters->CameraPosition = FVector3f(ViewMatrices.GetViewOrigin());
1552 Parameters->CameraForward = FVector3f(View.GetViewDirection());
1553 Parameters->CameraRight = FVector3f(View.GetViewRight());
1554 Parameters->CameraUp = FVector3f(View.GetViewUp());
1556 const FMatrix& ProjMatrix = ViewMatrices.GetProjectionMatrix();
1557 float ProjM11 = ProjMatrix.M[1][1];
1560 if (FMath::IsNearlyZero(ProjM11, 1e-6f) || !FMath::IsFinite(ProjM11))
1562 UE_LOG(LogIVSmoke, Error, TEXT(
"[RayMarch] Invalid ProjMatrix.M[1][1] = %f (likely orthographic viewport), skipping"), ProjM11);
1566 Parameters->TanHalfFOV = 1.0f / ProjM11;
1567 Parameters->AspectRatio = (float)ViewportSize.X / (
float)ViewportSize.Y;
1570 Parameters->MaxSteps = RenderData.
MaxSteps;
1571 Parameters->MinStepSize = MinStepSize;
1574 Parameters->VolumeDataBuffer = GraphBuilder.CreateSRV(VolumeBuffer);
1578 Parameters->PackedInterval = TexturePackInterval;
1579 Parameters->PackedVoxelAtlas = GraphBuilder.CreateSRV(PackedVoxelAtlasFXAA);
1580 Parameters->VoxelTexSize = VoxelResolution;
1581 Parameters->PackedVoxelTexSize = VoxelAtlasResolution;
1582 Parameters->VoxelAtlasCount = VoxelAtlasCount;
1583 Parameters->PackedHoleAtlas = GraphBuilder.CreateSRV(PackedHoleAtlas);
1584 Parameters->HoleTexSize = HoleResolution;
1585 Parameters->PackedHoleTexSize = HoleAtlasResolution;
1586 Parameters->HoleAtlasCount = HoleAtlasCount;
1589 Parameters->SceneTexturesStruct = GetSceneTextureShaderParameters(View).SceneTextures;
1590 Parameters->InvDeviceZToWorldZTransform = FVector4f(View.InvDeviceZToWorldZTransform);
1595 if (SceneDepthForDependency)
1597 Parameters->SceneDepthTexture_RDGDependency = SceneDepthForDependency;
1598 Parameters->bUseExplicitSceneDepth = 1;
1604 FRDGTextureDesc DummyDesc = FRDGTextureDesc::Create2D(
1607 FClearValueBinding::Black,
1608 TexCreate_ShaderResource
1610 Parameters->SceneDepthTexture_RDGDependency = GraphBuilder.CreateTexture(DummyDesc, TEXT(
"IVSmoke_DummyDepth"));
1611 Parameters->bUseExplicitSceneDepth = 0;
1615 Parameters->View = View.ViewUniformBuffer;
1618 Parameters->GlobalAbsorption = RenderData.GlobalAbsorption;
1619 Parameters->SmokeSize = RenderData.SmokeSize;
1620 Parameters->WindDirection = FVector3f(RenderData.WindDirection);
1621 Parameters->VolumeRangeOffset = RenderData.VolumeRangeOffset;
1622 Parameters->VolumeEdgeNoiseFadeOffset = RenderData.VolumeEdgeNoiseFadeOffset;
1623 Parameters->VolumeEdgeFadeSharpness = RenderData.VolumeEdgeFadeSharpness;
1626 Parameters->LightDirection = FVector3f(RenderData.LightDirection);
1627 Parameters->LightColor = FVector3f(RenderData.LightColor.R, RenderData.LightColor.G, RenderData.LightColor.B);
1628 Parameters->ScatterScale = RenderData.
bEnableScattering ? (RenderData.ScatterScale * RenderData.LightIntensity) : 0.0f;
1629 Parameters->ScatteringAnisotropy = RenderData.ScatteringAnisotropy;
1632 Parameters->LightMarchingSteps = RenderData.
bEnableSelfShadowing ? RenderData.LightMarchingSteps : 0;
1633 Parameters->LightMarchingDistance = RenderData.LightMarchingDistance;
1634 Parameters->LightMarchingExpFactor = RenderData.LightMarchingExpFactor;
1635 Parameters->ShadowAmbient = RenderData.ShadowAmbient;
1638 Parameters->GlobalAABBMin = GlobalAABBMin;
1639 Parameters->GlobalAABBMax = GlobalAABBMax;
1642 Parameters->ShadowDepthBias = RenderData.ShadowDepthBias;
1643 Parameters->ExternalShadowAmbient = RenderData.ExternalShadowAmbient;
1645 Parameters->CascadeBlendRange = RenderData.CascadeBlendRange;
1646 Parameters->CSMCameraPosition = FVector3f(ViewMatrices.GetViewOrigin());
1647 Parameters->bEnableVSM = RenderData.
bEnableVSM ? 1 : 0;
1648 Parameters->VSMMinVariance = RenderData.VSMMinVariance;
1649 Parameters->VSMLightBleedingReduction = RenderData.VSMLightBleedingReduction;
1652 for (int32 i = 0; i < 8; i++)
1654 if (i < RenderData.
NumCascades && i < RenderData.CSMViewProjectionMatrices.Num())
1656 Parameters->CSMViewProjectionMatrices[i] = FMatrix44f(RenderData.CSMViewProjectionMatrices[i]);
1657 Parameters->CSMLightCameraPositions[i] = FVector4f(
1658 FVector3f(RenderData.CSMLightCameraPositions[i]),
1661 Parameters->CSMLightCameraForwards[i] = FVector4f(
1662 FVector3f(RenderData.CSMLightCameraForwards[i]),
1668 Parameters->CSMViewProjectionMatrices[i] = FMatrix44f::Identity;
1669 Parameters->CSMLightCameraPositions[i] = FVector4f(0.0f, 0.0f, 0.0f, 0.0f);
1670 Parameters->CSMLightCameraForwards[i] = FVector4f(0.0f, 0.0f, -1.0f, 0.0f);
1676 float SplitDists[8];
1677 for (int32 i = 0; i < 8; i++)
1679 SplitDists[i] = (i < RenderData.CSMSplitDistances.Num()) ? RenderData.CSMSplitDistances[i] : 100000.0f;
1681 Parameters->CSMSplitDistances[0] = FVector4f(SplitDists[0], SplitDists[1], SplitDists[2], SplitDists[3]);
1682 Parameters->CSMSplitDistances[1] = FVector4f(SplitDists[4], SplitDists[5], SplitDists[6], SplitDists[7]);
1690 const int32 CascadeCount = RenderData.
NumCascades;
1693 : FIntPoint(512, 512);
1696 FRDGTextureDesc DepthArrayDesc = FRDGTextureDesc::Create2DArray(
1699 FClearValueBinding(FLinearColor(1.0f, 0.0f, 0.0f, 0.0f)),
1700 TexCreate_ShaderResource | TexCreate_UAV,
1703 FRDGTextureRef CSMDepthArray = GraphBuilder.CreateTexture(DepthArrayDesc, TEXT(
"IVSmokeCSMDepthArray"));
1705 FRDGTextureDesc VSMArrayDesc = FRDGTextureDesc::Create2DArray(
1708 FClearValueBinding(FLinearColor(1.0f, 1.0f, 0.0f, 0.0f)),
1709 TexCreate_ShaderResource | TexCreate_UAV,
1712 FRDGTextureRef CSMVSMArray = GraphBuilder.CreateTexture(VSMArrayDesc, TEXT(
"IVSmokeCSMVSMArray"));
1714 AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(CSMDepthArray), FVector4f(1.0f, 0.0f, 0.0f, 0.0f));
1715 AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(CSMVSMArray), FVector4f(1.0f, 1.0f, 0.0f, 0.0f));
1718 const uint32 CurrentRenderFrameNumber = View.Family->FrameNumber;
1719 const int32 VSMBlurRadius = Settings ? Settings->
VSMBlurRadius : 2;
1720 FIVSmokeVSMProcessor* VSMProcessorPtr = WorldData.IsValid() ? WorldData->VSMProcessor.Get() :
nullptr;
1721 const bool bNeedVSMProcessing = RenderData.
bEnableVSM && VSMProcessorPtr &&
1722 WorldData.IsValid() && WorldData->LastVSMProcessFrameNumber != CurrentRenderFrameNumber;
1724 for (int32 i = 0; i < CascadeCount; i++)
1729 FRDGTextureRef SourceDepth = GraphBuilder.RegisterExternalTexture(
1730 CreateRenderTarget(RenderData.
CSMDepthTextures[i], TEXT(
"IVSmokeCSMDepthSource"))
1733 FRHICopyTextureInfo DepthCopyInfo;
1734 DepthCopyInfo.Size = FIntVector(CascadeResolution.X, CascadeResolution.Y, 1);
1735 DepthCopyInfo.SourcePosition = FIntVector::ZeroValue;
1736 DepthCopyInfo.DestPosition = FIntVector::ZeroValue;
1737 DepthCopyInfo.DestSliceIndex = i;
1738 DepthCopyInfo.NumSlices = 1;
1739 AddCopyTexturePass(GraphBuilder, SourceDepth, CSMDepthArray, DepthCopyInfo);
1741 if (RenderData.
bEnableVSM && i < RenderData.CSMVSMTextures.Num() && RenderData.CSMVSMTextures[i].IsValid())
1743 FRDGTextureRef VSMTexture = GraphBuilder.RegisterExternalTexture(
1744 CreateRenderTarget(RenderData.CSMVSMTextures[i], TEXT(
"IVSmokeCSMVSMSource"))
1748 if (bNeedVSMProcessing && VSMProcessorPtr)
1750 VSMProcessorPtr->
Process(GraphBuilder, SourceDepth, VSMTexture, VSMBlurRadius);
1753 FRHICopyTextureInfo VSMCopyInfo;
1754 VSMCopyInfo.Size = FIntVector(CascadeResolution.X, CascadeResolution.Y, 1);
1755 VSMCopyInfo.SourcePosition = FIntVector::ZeroValue;
1756 VSMCopyInfo.DestPosition = FIntVector::ZeroValue;
1757 VSMCopyInfo.DestSliceIndex = i;
1758 VSMCopyInfo.NumSlices = 1;
1759 AddCopyTexturePass(GraphBuilder, VSMTexture, CSMVSMArray, VSMCopyInfo);
1765 if (bNeedVSMProcessing && WorldData.IsValid())
1767 WorldData->LastVSMProcessFrameNumber = CurrentRenderFrameNumber;
1770 Parameters->CSMDepthTextureArray = CSMDepthArray;
1771 Parameters->CSMVSMTextureArray = CSMVSMArray;
1775 FRDGTextureDesc DummyDepthArrayDesc = FRDGTextureDesc::Create2DArray(
1778 FClearValueBinding(FLinearColor(1.0f, 0.0f, 0.0f, 0.0f)),
1779 TexCreate_ShaderResource | TexCreate_UAV,
1782 FRDGTextureRef DummyDepthArray = GraphBuilder.CreateTexture(DummyDepthArrayDesc, TEXT(
"IVSmokeCSMDepthArrayDummy"));
1783 AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(DummyDepthArray), FVector4f(1.0f, 0.0f, 0.0f, 0.0f));
1785 FRDGTextureDesc DummyVSMArrayDesc = FRDGTextureDesc::Create2DArray(
1788 FClearValueBinding(FLinearColor(1.0f, 1.0f, 0.0f, 0.0f)),
1789 TexCreate_ShaderResource | TexCreate_UAV,
1792 FRDGTextureRef DummyVSMArray = GraphBuilder.CreateTexture(DummyVSMArrayDesc, TEXT(
"IVSmokeCSMVSMArrayDummy"));
1793 AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(DummyVSMArray), FVector4f(1.0f, 1.0f, 0.0f, 0.0f));
1795 Parameters->CSMDepthTextureArray = DummyDepthArray;
1796 Parameters->CSMVSMTextureArray = DummyVSMArray;
1798 Parameters->CSMSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
1801 Parameters->FrameNumber = View.Family->FrameNumber;
1802 Parameters->JitterIntensity = 1.0f;
1810 FIntVector(TexSize.X, TexSize.Y, 1)
1817void FIVSmokeRenderer::UpdateStatsIfNeeded(
const FIVSmokePackedRenderData& RenderData,
const FIntPoint& ViewportSize)
1819 const double CurrentTime = FPlatformTime::Seconds();
1820 if (CurrentTime - LastStatUpdateTime < 1.0)
1824 LastStatUpdateTime = CurrentTime;
1827 CachedPerFrameSize = CalculatePerFrameTextureSize(
1829 RenderData.VolumeCount,
1831 RenderData.HoleResolution
1837 FScopeLock Lock(&WorldDataMutex);
1838 for (
const auto& Pair : WorldDataMap)
1840 if (Pair.Value.IsValid() && Pair.Value->CSMRenderer && Pair.Value->CSMRenderer->IsInitialized())
1842 const TArray<FIVSmokeCascadeData>& Cascades = Pair.Value->CSMRenderer->GetCascades();
1845 if (Cascade.DepthRT)
1847 CachedCSMSize += Cascade.DepthRT->CalcTextureMemorySizeEnum(TMC_ResidentMips);
1851 CachedCSMSize += Cascade.VSMRT->CalcTextureMemorySizeEnum(TMC_ResidentMips);
1862int64 FIVSmokeRenderer::CalculatePerFrameTextureSize(
1863 const FIntPoint& ViewportSize,
1865 const FIntVector& VoxelResolution,
1866 const FIntVector& HoleResolution
1869 if (VolumeCount == 0)
1874 int64 TotalSize = 0;
1877 const FIntPoint HalfSize(FMath::Max(1, ViewportSize.X / 2), FMath::Max(1, ViewportSize.Y / 2));
1878 TotalSize += CalculateImageBytes(HalfSize.X, HalfSize.Y, 1, PF_FloatRGBA) * 2;
1881 const int32 TexturePackInterval = 4;
1882 const int32 TexturePackMaxSize = 2048;
1884 FIntVector VoxelAtlasCount = GetAtlasTexCount(VoxelResolution, VolumeCount, TexturePackInterval, TexturePackMaxSize);
1885 FIntVector VoxelAtlasResolution(
1886 VoxelResolution.X * VoxelAtlasCount.X + TexturePackInterval * (VoxelAtlasCount.X - 1),
1887 VoxelResolution.Y * VoxelAtlasCount.Y + TexturePackInterval * (VoxelAtlasCount.Y - 1),
1888 VoxelResolution.Z * VoxelAtlasCount.Z + TexturePackInterval * (VoxelAtlasCount.Z - 1)
1891 TotalSize += CalculateImageBytes(VoxelAtlasResolution.X, VoxelAtlasResolution.Y, VoxelAtlasResolution.Z, PF_R32_FLOAT) * 2;
1894 FIntVector HoleAtlasCount = GetAtlasTexCount(HoleResolution, VolumeCount, TexturePackInterval, TexturePackMaxSize);
1895 FIntVector HoleAtlasResolution(
1896 HoleResolution.X * HoleAtlasCount.X + TexturePackInterval * (HoleAtlasCount.X - 1),
1897 HoleResolution.Y * HoleAtlasCount.Y + TexturePackInterval * (HoleAtlasCount.Y - 1),
1898 HoleResolution.Z * HoleAtlasCount.Z + TexturePackInterval * (HoleAtlasCount.Z - 1)
1900 TotalSize += CalculateImageBytes(HoleAtlasResolution.X, HoleAtlasResolution.Y, HoleAtlasResolution.Z, PF_FloatRGBA);
1906 const FIntPoint TileCount(
1908 (ViewportSize.Y + FIVSmokeOccupancyConfig::TileSizeY - 1) / FIVSmokeOccupancyConfig::TileSizeY
1912 TotalSize += CalculateImageBytes(TileCount.X, TileCount.Y, StepSliceCount, PF_R32G32B32A32_UINT) * 2;
1918void FIVSmokeRenderer::UpdateAllStats()
1921 SET_MEMORY_STAT(STAT_IVSmoke_NoiseVolume, CachedNoiseVolumeSize);
1922 SET_MEMORY_STAT(STAT_IVSmoke_CSMShadowMaps, CachedCSMSize);
1923 SET_MEMORY_STAT(STAT_IVSmoke_PerFrameTextures, CachedPerFrameSize);
1924 SET_MEMORY_STAT(STAT_IVSmoke_TotalVRAM, CachedNoiseVolumeSize + CachedCSMSize + CachedPerFrameSize);
1930bool FIVSmokeRenderer::IsPrimaryGameView(
const FSceneView& View)
1934 if (View.bIsSceneCapture || View.bIsPlanarReflection || View.bIsReflectionCapture)
1942 FRDGBuilder& GraphBuilder,
1943 const FSceneView& View,
1944 const FRenderTargetBindingSlots& RenderTargets,
1945 TRDGUniformBufferRef<FSceneTextureUniformParameters> SceneTextures)
1956 if (!IsPrimaryGameView(View))
1964 UE_LOG(LogIVSmoke, Verbose, TEXT(
"[FIVSmokeRenderer::RunPrePassPipeline] View.State is null, skipping Pre-pass"));
1969 UWorld* World =
nullptr;
1970 if (View.Family && View.Family->Scene)
1972 World = View.Family->Scene->GetWorld();
1981 TSharedPtr<FPerWorldData> WorldData =
GetWorldData(World);
1982 if (!WorldData.IsValid())
1990 FScopeLock Lock(&WorldDataMutex);
1991 RenderData = WorldData->CachedRenderData;
1995 if (!RenderData.
bIsValid || RenderData.VolumeCount == 0)
2008 const FIntRect ScaledViewRect = UE::FXRenderingUtils::GetRawViewRectUnsafe(View);
2010 RDG_EVENT_SCOPE(GraphBuilder,
"IVSmoke_PrePassPipeline");
2013 const FIntRect PrePassViewRect = ScaledViewRect;
2014 const FIntPoint ViewportSize = PrePassViewRect.Size();
2015 const FIntPoint ViewRectMin = PrePassViewRect.Min;
2018 if (ViewportSize.X <= 0 || ViewportSize.Y <= 0)
2020 UE_LOG(LogIVSmoke, Error, TEXT(
"[RunPrePassPipeline] Invalid ViewportSize: %dx%d, skipping"), ViewportSize.X, ViewportSize.Y);
2027 FPerViewData* ViewDataPtr =
nullptr;
2029 FScopeLock Lock(&ViewDataMutex);
2030 ViewDataPtr = &ViewDataMap.FindOrAdd(View.State);
2032 FPerViewData& ViewData = *ViewDataPtr;
2036 const FIntPoint HalfSize = FIntPoint(
2037 FMath::Max(1, ViewportSize.X / 2),
2038 FMath::Max(1, ViewportSize.Y / 2)
2043 FRDGTextureDesc FullResDesc = FRDGTextureDesc::Create2D(
2044 ViewportSize, PF_FloatRGBA, FClearValueBinding::Black,
2045 TexCreate_RenderTargetable | TexCreate_ShaderResource | TexCreate_UAV
2048 ViewData.SmokeTex = GraphBuilder.CreateTexture(FullResDesc, TEXT(
"IVSmoke_SmokeTex"));
2049 ViewData.LocalPosAlphaTex = GraphBuilder.CreateTexture(FullResDesc, TEXT(
"IVSmoke_LocalPosAlphaTex"));
2050 ViewData.WorldPosDepthTex = GraphBuilder.CreateTexture(FullResDesc, TEXT(
"IVSmoke_WorldPosDepthTex"));
2054 FRDGTextureDesc HalfResDesc = FRDGTextureDesc::Create2D(
2055 HalfSize, PF_FloatRGBA, FClearValueBinding::Black,
2056 TexCreate_RenderTargetable | TexCreate_ShaderResource | TexCreate_UAV
2059 FRDGTextureRef SmokeAlbedoHalf = GraphBuilder.CreateTexture(HalfResDesc, TEXT(
"IVSmokeAlbedoTex_Half_PrePass"));
2060 FRDGTextureRef SmokeLocalPosAlphaHalf = GraphBuilder.CreateTexture(HalfResDesc, TEXT(
"IVSmokeLocalPosAlphaTex_Half_PrePass"));
2061 FRDGTextureRef SmokeWorldPosDepthHalf = GraphBuilder.CreateTexture(HalfResDesc, TEXT(
"IVSmokeWorldPosDepthTex_Half_PrePass"));
2066 FRDGTextureRef SceneDepthTexture = RenderTargets.DepthStencil.GetTexture();
2067 AddMultiVolumeRayMarchPass(
2068 GraphBuilder, View, RenderData,
2069 SmokeAlbedoHalf, SmokeLocalPosAlphaHalf, SmokeWorldPosDepthHalf,
2070 HalfSize, ViewportSize, ViewRectMin,
2076 FRDGTextureRef SmokeAlbedoFull = AddCopyPass(
2077 GraphBuilder, View, SmokeAlbedoHalf, ViewportSize, TEXT(
"IVSmokeAlbedoTex_Full_PrePass")
2079 AddCopyPass(GraphBuilder, View, SmokeLocalPosAlphaHalf, ViewData.LocalPosAlphaTex);
2080 AddCopyPass(GraphBuilder, View, SmokeWorldPosDepthHalf, ViewData.WorldPosDepthTex);
2084 FRDGTextureRef FilteredSmokeTex = AddUpsampleFilterPass(
2085 GraphBuilder, RenderData, View,
2087 SmokeAlbedoFull, ViewData.LocalPosAlphaTex,
2088 ViewportSize, ViewRectMin
2092 AddCopyPass(GraphBuilder, View, FilteredSmokeTex, ViewData.SmokeTex);
2099 GraphBuilder, View, RenderTargets,
2100 ViewData.WorldPosDepthTex, ViewData.LocalPosAlphaTex,
2101 ViewportSize, ViewRectMin
2107 ViewData.ViewportSize = ViewportSize;
2108 ViewData.ViewRectMin = ViewRectMin;
2109 ViewData.bIsValid =
true;
2112void FIVSmokeRenderer::ExecuteDepthWrite(
2113 FRDGBuilder& GraphBuilder,
2114 const FSceneView& View,
2115 const FRenderTargetBindingSlots& RenderTargets,
2116 FRDGTextureRef SmokeWorldPosDepthTex,
2117 FRDGTextureRef SmokeLocalPosAlphaTex,
2118 const FIntPoint& ViewportSize,
2119 const FIntPoint& ViewRectMin)
2121 RDG_EVENT_SCOPE(GraphBuilder,
"IVSmoke_DepthWrite");
2124 FRDGTextureRef DepthTexture = RenderTargets.DepthStencil.GetTexture();
2133 FGlobalShaderMap* ShaderMap = GetGlobalShaderMap(View.FeatureLevel);
2134 TShaderMapRef<FIVSmokeDepthWritePS> PixelShader(ShaderMap);
2137 FIVSmokeDepthWritePS::FParameters* Parameters = GraphBuilder.AllocParameters<FIVSmokeDepthWritePS::FParameters>();
2139 Parameters->SmokeWorldPosDepthTex = SmokeWorldPosDepthTex;
2140 Parameters->SmokeLocalPosAlphaTex = SmokeLocalPosAlphaTex;
2141 Parameters->LinearClampSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
2144 Parameters->CameraForward = FVector3f(View.GetViewDirection());
2145 Parameters->CameraOrigin = FVector3f(View.ViewMatrices.GetViewOrigin());
2148 Parameters->ViewportSize = FVector2f(ViewportSize);
2149 Parameters->ViewRectMin = FVector2f(ViewRectMin);
2152 Parameters->DepthBias = Settings ? Settings->
DepthWriteBias : 0.0f;
2159 const FMatrix& ViewToClip = View.ViewMatrices.GetProjectionMatrix();
2160 Parameters->ViewToClip_22 = ViewToClip.M[2][2];
2161 Parameters->ViewToClip_32 = ViewToClip.M[3][2];
2164 Parameters->RenderTargets.DepthStencil = FDepthStencilBinding(
2166 ERenderTargetLoadAction::ELoad,
2167 ERenderTargetLoadAction::ELoad,
2168 FExclusiveDepthStencil::DepthWrite_StencilNop
2172 FIntRect ViewRect = View.UnscaledViewRect;
2177 FPixelShaderUtils::AddFullscreenPass(
2180 RDG_EVENT_NAME(
"IVSmoke_DepthWritePS"),
2186 TStaticDepthStencilState<true, CF_Always>::GetRHI()
FORCEINLINE const UIVSmokeSmokePreset * GetSmokePresetOverride() const
FORCEINLINE FVector GetVoxelWorldAABBMax() const
FORCEINLINE float GetVoxelSize() const
TObjectPtr< UIVSmokeHoleGeneratorComponent > GetHoleGeneratorComponent()
FORCEINLINE const TArray< float > & GetVoxelBirthTimes() const
FORCEINLINE FVector GetVoxelWorldAABBMin() const
FORCEINLINE FIntVector GetGridResolution() const
FORCEINLINE FIntVector GetCenterOffset() const
FORCEINLINE const TArray< float > & GetVoxelDeathTimes() const
static void AddComputeShaderPass(FRDGBuilder &GraphBuilder, FGlobalShaderMap *ShaderMap, TShaderMapRef< TShaderClass > ComputeShader, typename TShaderClass::FParameters *Parameters, const FIntVector &TotalThreadSize)
static FRDGTextureRef CreateOutputTexture(FRDGBuilder &GraphBuilder, FRDGTextureRef SourceTexture, const TCHAR *DebugName=, EPixelFormat OverrideFormat=PF_Unknown, FIntPoint OverrideExtent=FIntPoint::ZeroValue, ETextureCreateFlags Flags=ETextureCreateFlags::UAV)
void SetServerTimeOffset(UWorld *World, float InServerTimeOffset)
TSharedPtr< FPerWorldData > GetWorldData(UWorld *World)
static constexpr int32 MaxSupportedVolumes
FScreenPassTexture Render(FRDGBuilder &GraphBuilder, const FSceneView &View, const FPostProcessMaterialInputs &Inputs)
TSharedPtr< FPerWorldData > GetOrCreateWorldData(UWorld *World)
void RunPrePassPipeline(FRDGBuilder &GraphBuilder, const FSceneView &View, const struct FRenderTargetBindingSlots &RenderTargets, TRDGUniformBufferRef< FSceneTextureUniformParameters > SceneTextures)
void SetCachedRenderData(UWorld *World, FIVSmokePackedRenderData &&InRenderData)
bool IsInitialized() const
FIVSmokePackedRenderData PrepareRenderData(UWorld *World, const TArray< AIVSmokeVoxelVolume * > &InVolumes, const FVector &CameraPosition)
bool bIsServerTimeSynced(UWorld *World)
void CleanupWorldData(UWorld *World)
void Process(FRDGBuilder &GraphBuilder, FRDGTextureRef DepthTexture, FRDGTextureRef VSMTexture, int32 BlurRadius)
Component that generates hole texture for volumetric smoke. Provides public API for penetration and e...
FTextureRHIRef GetHoleTextureRHI() const
float LightMarchingExpFactor
bool bOverrideLightDirection
float VSMLightBleedingReduction
int32 GetEffectiveNumCascades() const
int32 GetEffectiveCascadeResolution() const
static const UIVSmokeSettings * Get()
bool bEnableSmokeRendering
bool IsSelfShadowingEnabled() const
float GetEffectiveMinStepSize() const
float DepthWriteAlphaThreshold
float SmokeDensityFalloff
float ScatteringAnisotropy
int32 GetEffectiveMaxSteps() const
float VolumeEdgeFadeSharpness
FLinearColor LightColorOverride
float GetEffectiveShadowMaxDistance() const
bool IsExternalShadowingEnabled() const
FVector LightDirectionOverride
float ExternalShadowAmbient
float LightMarchingDistance
int32 GetEffectiveLightMarchingSteps() const
float VolumeEdgeNoiseFadeOffset
TObjectPtr< UMaterialInterface > SmokeVisualMaterial
EIVSmokeUpSampleFilterType UpSampleFilterType
FVector LightCameraPosition
FMatrix ViewProjectionMatrix
FVector LightCameraForward
static constexpr float NoiseUVMul
static constexpr uint32 TileSizeX
static constexpr uint32 StepDivisor
FRDGTextureRef LightOccupancy
FRDGBufferRef TileDataBuffer
FRDGTextureRef ViewOccupancy
TArray< float > PackedVoxelBirthTimes
bool bEnableSelfShadowing
TArray< float > PackedVoxelDeathTimes
TArray< FIVSmokeVolumeGPUData > VolumeDataArray
TArray< FTextureRHIRef > HoleTextures
TArray< FTextureRHIRef > CSMDepthTextures
FVector CSMMainCameraPosition
FIntVector VoxelResolution
UMaterialInterface * SmokeVisualMaterial
FVector3f VolumeWorldAABBMin
FIntVector3 GridResolution
FVector3f VolumeWorldAABBMax
uint32 LastCSMUpdateFrameNumber
TUniquePtr< FIVSmokeVSMProcessor > VSMProcessor
TUniquePtr< FIVSmokeCSMRenderer > CSMRenderer
uint32 LastVSMProcessFrameNumber