IVSmoke 1.0
Loading...
Searching...
No Matches
IVSmokeSettings.cpp
1// Copyright (c) 2026, Team SDB. All rights reserved.
2
3#include "IVSmokeSettings.h"
4#include "IVSmokeRenderer.h"
5#include "IVSmoke.h"
6#include "IVSmokeVisualMaterialPreset.h"
7#include "Materials/MaterialInterface.h"
8
9
10UIVSmokeSettings::UIVSmokeSettings()
11{
12
13}
14
16{
17 return GetDefault<UIVSmokeSettings>();
18}
19
20//~==============================================================================
21// Quality Preset Tables
22// Index order: Low=0, Medium=1, High=2
23
24namespace IVSmokeQualityPresets
25{
26 // Ray Marching: MaxSteps, MinStepSize
27 static constexpr int32 RayMarchMaxSteps[] = { 128, 256, 512 };
28 static constexpr float RayMarchMinStepSize[] = { 50.0f, 25.0f, 16.0f };
29
30 // Self Shadow: LightMarchingSteps (Off=0, Low=1, Medium=2, High=3)
31 static constexpr int32 SelfShadowSteps[] = { 0, 3, 6, 8 };
32
33 // External Shadow: NumCascades, Resolution, MaxDistance (Off=0, Low=1, Medium=2, High=3)
34 static constexpr int32 ExternalShadowCascades[] = { 0, 3, 4, 4 };
35 static constexpr int32 ExternalShadowResolution[] = { 0, 512, 512, 1024 };
36 static constexpr float ExternalShadowMaxDistance[] = { 0.0f, 20000.0f, 30000.0f, 50000.0f };
37
38 // Global → External Shadow mapping (Low→Off, Medium→Medium, High→High)
39 static constexpr uint8 GlobalToExternalShadow[] = { 0, 2, 3 }; // Low→Off(0), Medium→Medium(2), High→High(3)
40}
41
42//~==============================================================================
43// Ray Marching Quality Getters
44
46{
47 if (GlobalQuality == EIVSmokeGlobalQuality::Custom)
48 {
49 if (RayMarchQuality == EIVSmokeRayMarchQuality::Custom)
50 {
51 return CustomMaxSteps;
52 }
53 return IVSmokeQualityPresets::RayMarchMaxSteps[static_cast<uint8>(RayMarchQuality)];
54 }
55 return IVSmokeQualityPresets::RayMarchMaxSteps[static_cast<uint8>(GlobalQuality)];
56}
57
59{
60 if (GlobalQuality == EIVSmokeGlobalQuality::Custom)
61 {
62 if (RayMarchQuality == EIVSmokeRayMarchQuality::Custom)
63 {
64 return CustomMinStepSize;
65 }
66 return IVSmokeQualityPresets::RayMarchMinStepSize[static_cast<uint8>(RayMarchQuality)];
67 }
68 return IVSmokeQualityPresets::RayMarchMinStepSize[static_cast<uint8>(GlobalQuality)];
69}
70
71//~==============================================================================
72// Self Shadow Quality Getters
73
75{
76 if (GlobalQuality == EIVSmokeGlobalQuality::Custom)
77 {
78 return SelfShadowQuality != EIVSmokeSelfShadowQuality::Off;
79 }
80 // Global Low/Medium/High → Self Shadow Low/Medium/High (always enabled)
81 return true;
82}
83
85{
86 if (GlobalQuality == EIVSmokeGlobalQuality::Custom)
87 {
88 if (SelfShadowQuality == EIVSmokeSelfShadowQuality::Custom)
89 {
91 }
92 return IVSmokeQualityPresets::SelfShadowSteps[static_cast<uint8>(SelfShadowQuality)];
93 }
94 // Global Low=0, Medium=1, High=2 → Self Shadow Low=1, Medium=2, High=3
95 return IVSmokeQualityPresets::SelfShadowSteps[static_cast<uint8>(GlobalQuality) + 1];
96}
97
98//~==============================================================================
99// External Shadow Quality Getters
100
102{
103 if (GlobalQuality == EIVSmokeGlobalQuality::Custom)
104 {
105 return ExternalShadowQuality != EIVSmokeExternalShadowQuality::Off;
106 }
107 // Global Low → External Shadow Off
108 return GlobalQuality != EIVSmokeGlobalQuality::Low;
109}
110
112{
113 if (GlobalQuality == EIVSmokeGlobalQuality::Custom)
114 {
115 if (ExternalShadowQuality == EIVSmokeExternalShadowQuality::Custom)
116 {
117 return CustomNumCascades;
118 }
119 return IVSmokeQualityPresets::ExternalShadowCascades[static_cast<uint8>(ExternalShadowQuality)];
120 }
121 uint8 MappedIndex = IVSmokeQualityPresets::GlobalToExternalShadow[static_cast<uint8>(GlobalQuality)];
122 return IVSmokeQualityPresets::ExternalShadowCascades[MappedIndex];
123}
124
126{
127 if (GlobalQuality == EIVSmokeGlobalQuality::Custom)
128 {
129 if (ExternalShadowQuality == EIVSmokeExternalShadowQuality::Custom)
130 {
132 }
133 return IVSmokeQualityPresets::ExternalShadowResolution[static_cast<uint8>(ExternalShadowQuality)];
134 }
135 uint8 MappedIndex = IVSmokeQualityPresets::GlobalToExternalShadow[static_cast<uint8>(GlobalQuality)];
136 return IVSmokeQualityPresets::ExternalShadowResolution[MappedIndex];
137}
138
140{
141 if (GlobalQuality == EIVSmokeGlobalQuality::Custom)
142 {
143 if (ExternalShadowQuality == EIVSmokeExternalShadowQuality::Custom)
144 {
146 }
147 return IVSmokeQualityPresets::ExternalShadowMaxDistance[static_cast<uint8>(ExternalShadowQuality)];
148 }
149 uint8 MappedIndex = IVSmokeQualityPresets::GlobalToExternalShadow[static_cast<uint8>(GlobalQuality)];
150 return IVSmokeQualityPresets::ExternalShadowMaxDistance[MappedIndex];
151}
152UIVSmokeVisualMaterialPreset* UIVSmokeSettings::GetVisualMaterialPreset() const
153{
154 if (CachedVisualMaterialPreset != nullptr)
155 {
156 return CachedVisualMaterialPreset;
157 }
158 return nullptr;
159}
160void UIVSmokeSettings::SetVisualMaterialPreset(FSoftObjectPath VisualMaterialPresetPath)
161{
162 UIVSmokeSettings* Settings = GetMutableDefault<UIVSmokeSettings>();
163
164 Settings->SmokeVisualMaterialPreset = VisualMaterialPresetPath;
165 Settings->CachedVisualMaterialPreset = Cast<UIVSmokeVisualMaterialPreset>(Settings->SmokeVisualMaterialPreset.TryLoad());
166
167 // EnsureIsComplete() requires RHI - skip during commandlets (cooking/packaging)
168 if (!IsRunningCommandlet() && CachedVisualMaterialPreset)
169 {
170 if (UMaterialInterface* Mat = CachedVisualMaterialPreset->SmokeVisualMaterial.Get())
171 {
172 Mat->EnsureIsComplete();
173 }
174 }
175}
176
177void UIVSmokeSettings::PostInitProperties()
178{
179 Super::PostInitProperties();
180
181 // Load preset (safe during cooking)
182 CachedVisualMaterialPreset = Cast<UIVSmokeVisualMaterialPreset>(SmokeVisualMaterialPreset.TryLoad());
183
184 // EnsureIsComplete() requires RHI - skip during commandlets (cooking/packaging)
185 if (!IsRunningCommandlet() && CachedVisualMaterialPreset)
186 {
187 if (UMaterialInterface* Mat = CachedVisualMaterialPreset->SmokeVisualMaterial.Get())
188 {
189 Mat->EnsureIsComplete();
190 }
191 }
192}
193
194#if WITH_EDITOR
195void UIVSmokeSettings::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
196{
197 Super::PostEditChangeProperty(PropertyChangedEvent);
198
199 // Global settings are read directly from UIVSmokeSettings::Get() each frame,
200 // so no manual refresh is needed when properties change.
201
202 // Load preset and ensure shader compilation when preset changes
203 CachedVisualMaterialPreset = Cast<UIVSmokeVisualMaterialPreset>(SmokeVisualMaterialPreset.TryLoad());
204 if (CachedVisualMaterialPreset)
205 {
206 if (UMaterialInterface* Mat = CachedVisualMaterialPreset->SmokeVisualMaterial.Get())
207 {
208 Mat->EnsureIsComplete();
209 }
210 }
211}
212#endif
EIVSmokeSelfShadowQuality SelfShadowQuality
int32 GetEffectiveNumCascades() const
int32 GetEffectiveCascadeResolution() const
static const UIVSmokeSettings * Get()
bool IsSelfShadowingEnabled() const
float GetEffectiveMinStepSize() const
int32 GetEffectiveMaxSteps() const
float GetEffectiveShadowMaxDistance() const
EIVSmokeRayMarchQuality RayMarchQuality
EIVSmokeGlobalQuality GlobalQuality
bool IsExternalShadowingEnabled() const
FSoftObjectPath SmokeVisualMaterialPreset
int32 GetEffectiveLightMarchingSteps() const
void SetVisualMaterialPreset(FSoftObjectPath VisualMaterialPresetPath)
EIVSmokeExternalShadowQuality ExternalShadowQuality
TObjectPtr< UMaterialInterface > SmokeVisualMaterial