Unravel Engine C++ Reference
Loading...
Searching...
No Matches
ssil_component.cpp
Go to the documentation of this file.
1#include "ssil_component.hpp"
3
6
7namespace unravel
8{
9
11{
12 using spatial_denoise_settings = ssil_pass::spatial_denoise_settings;
13
14 entt::meta_factory<spatial_denoise_settings>{}
15 .type("ssil_pass::spatial_denoise_settings"_hs)
17 entt::attribute{"name", "ssil_pass::spatial_denoise_settings"},
18 entt::attribute{"pretty_name", "Spatial Denoise Settings"},
19 })
20 .data<&spatial_denoise_settings::depth_sigma>("depth_sigma"_hs)
22 entt::attribute{"name", "depth_sigma"},
23 entt::attribute{"pretty_name", "Depth Sigma"},
24 entt::attribute{"min", 0.005f},
25 entt::attribute{"max", 0.05f},
26 entt::attribute{"tooltip", "Depth edge-stopping threshold for the joint-bilateral a-trous filter.\nLower = stricter edges / sharper, higher = smoother."},
27 })
28 .data<&spatial_denoise_settings::normal_power>("normal_power"_hs)
30 entt::attribute{"name", "normal_power"},
31 entt::attribute{"pretty_name", "Normal Power"},
32 entt::attribute{"min", 16.0f},
33 entt::attribute{"max", 128.0f},
34 entt::attribute{"tooltip", "Normal edge-stopping exponent. Higher = stricter edges"},
35 })
36 .data<&spatial_denoise_settings::luma_sigma>("luma_sigma"_hs)
38 entt::attribute{"name", "luma_sigma"},
39 entt::attribute{"pretty_name", "Luma Sigma"},
40 entt::attribute{"min", 0.3f},
41 entt::attribute{"max", 32.0f},
42 entt::attribute{"tooltip", "Variance-guided luminance edge-stop multiplier (phi). Scales the measured\nspatiotemporal luminance std-dev (temporal moments, spatial fallback when fresh):\nlower = sharper / more detail kept, higher = smoother."},
43 })
44 .data<&spatial_denoise_settings::passes>("passes"_hs)
46 entt::attribute{"name", "passes"},
47 entt::attribute{"pretty_name", "Passes"},
48 entt::attribute{"min", 1},
49 entt::attribute{"max", 5},
50 entt::attribute{"tooltip", "Number of a-trous filter passes. More passes = wider blur reach but higher cost"},
51 })
52 .data<&spatial_denoise_settings::full_res_passes>("full_res_passes"_hs)
54 entt::attribute{"name", "full_res_passes"},
55 entt::attribute{"pretty_name", "Full-Res Passes"},
56 entt::attribute{"min", 0},
57 entt::attribute{"max", 5},
58 entt::attribute{"tooltip", "Mixed-resolution split: how many a-trous passes run at the trace resolution. The\nREMAINING (wide) passes run at half res (cache-coherent, ~4x cheaper); a bilateral\nupsample then restores sharp silhouettes from the full-res G-buffer. 0 lets the pass\nchoose the cheapest split; when temporal moments exist it is promoted to one full-res\npass so stable variance is consumed before the half-res tier. >= Passes = all full res."},
59 })
60 .data<&spatial_denoise_settings::max_step>("max_step"_hs)
62 entt::attribute{"name", "max_step"},
63 entt::attribute{"pretty_name", "Max Step"},
64 entt::attribute{"min", 1},
65 entt::attribute{"max", 16},
66 entt::attribute{"tooltip", "Caps the a-trous dilation (trace texels). The step normally doubles each pass\n(1,2,4,8,16); the widely-dilated late passes scatter taps and thrash the texture\ncache, costing far more than early passes. Lower this (e.g. 8) to flatten that\ncost spike with minimal quality loss; 16 = uncapped doubling."},
67 });
68}
69
71{
72 using temporal_settings = ssil_pass::temporal_settings;
73
74 entt::meta_factory<temporal_settings>{}
75 .type("ssil_pass::temporal_settings"_hs)
77 entt::attribute{"name", "ssil_pass::temporal_settings"},
78 entt::attribute{"pretty_name", "Temporal Accumulation Settings"},
79 })
80 .data<&temporal_settings::history_strength>("history_strength"_hs)
82 entt::attribute{"name", "history_strength"},
83 entt::attribute{"pretty_name", "History Strength"},
84 entt::attribute{"min", 0.0f},
85 entt::attribute{"max", 1.0f},
86 entt::attribute{"tooltip", "Controls how long indirect lighting keeps history.\n0 = real-time only, 1 = maximum denoise"},
87 })
88 .data<&temporal_settings::depth_threshold>("depth_threshold"_hs)
90 entt::attribute{"name", "depth_threshold"},
91 entt::attribute{"pretty_name", "Edge Threshold"},
92 entt::attribute{"min", 0.000f},
93 entt::attribute{"max", 0.200f},
94 entt::attribute{"tooltip", "Relative depth tolerance for temporal disocclusion (fraction of linear\ndepth). Lower = more ghosting rejected but less accumulation; higher =\nsmoother but more ghosting."},
95 })
96 .data<&temporal_settings::normal_dot_threshold>("normal_dot_threshold"_hs)
98 entt::attribute{"name", "normal_dot_threshold"},
99 entt::attribute{"pretty_name", "Normal Threshold"},
100 entt::attribute{"min", 0.0f},
101 entt::attribute{"max", 1.0f},
102 entt::attribute{"tooltip", "Minimum dot(n_current, n_at_reprojected_uv) to accept history. Catches the common\ndisocclusion case where reprojection lands on a different surface (rotated geometry,\nanimated foliage) which the depth-only test misses. 0.85 ~ 32 deg tolerance; lower\nallows wider surface mismatch (more ghosting), higher rejects more aggressively."},
103 })
104 .data<&temporal_settings::max_accum_frames>("max_accum_frames"_hs)
106 entt::attribute{"name", "max_accum_frames"},
107 entt::attribute{"pretty_name", "Max Accum Frames"},
108 entt::attribute{"min", 1},
109 entt::attribute{"max", 16},
110 entt::attribute{"tooltip", "Maximum temporal accumulation frames"},
111 });
112}
113
115{
116 using ssil_settings = ssil_pass::ssil_settings;
117
118 auto multi_bounce_predicate_entt = entt::property_predicate<bool>([](const entt::meta_any& obj)
119 {
120 if(auto data = obj.try_cast<ssil_settings>())
121 {
122 return data->enable_multi_bounce;
123 }
124 return false;
125 });
126
127 auto temporal_predicate_entt = entt::property_predicate<bool>([](const entt::meta_any& obj)
128 {
129 if(auto data = obj.try_cast<ssil_settings>())
130 {
131 return data->enable_temporal_accumulation;
132 }
133 return false;
134 });
135
136 auto spatial_denoise_predicate_entt = entt::property_predicate<bool>([](const entt::meta_any& obj)
137 {
138 if(auto data = obj.try_cast<ssil_settings>())
139 {
140 return data->enable_spatial_denoise;
141 }
142 return false;
143 });
144
145 entt::meta_factory<ssil_settings>{}
146 .type("ssil_pass::ssil_settings"_hs)
148 entt::attribute{"name", "ssil_pass::ssil_settings"},
149 entt::attribute{"pretty_name", "SSIL Settings"},
150 })
151 .data<&ssil_settings::max_rays>("max_rays"_hs)
153 entt::attribute{"name", "max_rays"},
154 entt::attribute{"pretty_name", "Max Rays"},
155 entt::attribute{"min", 1},
156 entt::attribute{"max", 16},
157 entt::attribute{"tooltip", "Number of hemisphere rays per pixel. More = better quality, higher cost"},
158 })
159 .data<&ssil_settings::max_steps>("max_steps"_hs)
161 entt::attribute{"name", "max_steps"},
162 entt::attribute{"pretty_name", "Max Steps"},
163 entt::attribute{"min", 4},
164 entt::attribute{"max", 256},
165 entt::attribute{"tooltip", "Maximum Hi-Z ray marching steps per ray"},
166 })
167 .data<&ssil_settings::depth_tolerance>("depth_tolerance"_hs)
169 entt::attribute{"name", "depth_tolerance"},
170 entt::attribute{"pretty_name", "Depth Tolerance"},
171 entt::attribute{"min", 0.01f},
172 entt::attribute{"max", 1.0f},
173 entt::attribute{"tooltip", "Depth tolerance for hit validation"},
174 })
175 .data<&ssil_settings::thickness>("thickness"_hs)
177 entt::attribute{"name", "thickness"},
178 entt::attribute{"pretty_name", "Thickness"},
179 entt::attribute{"min", 0.0f},
180 entt::attribute{"max", 2.0f},
181 entt::attribute{"tooltip", "Extra view-space hit-acceptance band added on top of Depth Tolerance, scaled by hit\ndistance. Far hits resolve against coarser Hi-Z depth, so a fixed band over-rejects\nthem and leaks the environment fallback through occluders; raising thickness closes\nthat leak. Too high over-occludes (darkening). 0 = fixed band only."},
182 })
183 .data<&ssil_settings::brightness>("brightness"_hs)
185 entt::attribute{"name", "brightness"},
186 entt::attribute{"pretty_name", "Brightness"},
187 entt::attribute{"min", 0.0f},
188 entt::attribute{"max", 5.0f},
189 entt::attribute{"tooltip", "Gain on the on-screen indirect BOUNCE only (the environment-miss fallback stays at\nprobe intensity, so unoccluded ambient matches the SH probe). 1.0 = physically-matched\nsingle bounce (reads strong with saturated albedos); 0.5 is the tamer default. Raise\ntoward 1.0 for full physical colour bleed."},
190 })
191 .data<&ssil_settings::max_distance>("max_distance"_hs)
193 entt::attribute{"name", "max_distance"},
194 entt::attribute{"pretty_name", "Max Distance"},
195 entt::attribute{"min", 0.5f},
196 entt::attribute{"max", 500.0f},
197 entt::attribute{"tooltip", "Maximum ray distance in world units. SSIL captures local bounce; distant GI comes from probes"},
198 })
199 .data<&ssil_settings::resolution>("resolution"_hs)
201 entt::attribute{"name", "resolution"},
202 entt::attribute{"pretty_name", "Trace Resolution"},
203 entt::attribute{"tooltip", "Downscale divisor for SSIL trace buffers.\nFull = reference quality, Half = ~4x faster, Quarter = ~16x faster (viable for indirect lighting because it is inherently low-frequency).\nThe indirect pass samples the upscaled result through the same full-res G-buffer UV."},
204 })
205 .data<&ssil_settings::enable_multi_bounce>("enable_multi_bounce"_hs)
207 entt::attribute{"name", "enable_multi_bounce"},
208 entt::attribute{"pretty_name", "Enable Multi-Bounce"},
209 entt::attribute{"tooltip", "Feed previous frame's SSIL back into the trace for multi-bounce indirect lighting. Light propagates deeper into corridors and shadowed areas over several frames. Each bounce is attenuated by the hit surface's diffuse albedo for energy conservation."},
210 })
211 .data<&ssil_settings::multi_bounce_intensity>("multi_bounce_intensity"_hs)
213 entt::attribute{"name", "multi_bounce_intensity"},
214 entt::attribute{"pretty_name", "Multi-Bounce Intensity"},
215 entt::attribute{"predicate", multi_bounce_predicate_entt},
216 entt::attribute{"min", 0.0f},
217 entt::attribute{"max", 1.0f},
218 entt::attribute{"tooltip", "Controls how much indirect light is carried between bounces. Acts as an extra decay factor on top of surface albedo attenuation. 0 = single bounce only, 0.5 = balanced (default), 1.0 = full physical albedo-only attenuation."},
219 })
220 .data<&ssil_settings::enable_spatial_denoise>("enable_spatial_denoise"_hs)
222 entt::attribute{"name", "enable_spatial_denoise"},
223 entt::attribute{"pretty_name", "Enable Spatial Denoise"},
224 entt::attribute{"tooltip", "Enable edge-preserving spatial denoising (a-trous wavelet)"},
225 })
226 .data<&ssil_settings::spatial_denoise>("spatial_denoise"_hs)
228 entt::attribute{"name", "spatial_denoise"},
229 entt::attribute{"predicate", spatial_denoise_predicate_entt},
230 entt::attribute{"pretty_name", "Spatial Denoise"},
231 entt::attribute{"tooltip", "Spatial denoise settings"},
232 // entt::attribute{"flattable", true},
233 })
234 .data<&ssil_settings::enable_temporal_accumulation>("enable_temporal_accumulation"_hs)
236 entt::attribute{"name", "enable_temporal_accumulation"},
237 entt::attribute{"pretty_name", "Enable Temporal"},
238 entt::attribute{"tooltip", "Enable temporal accumulation to reduce noise over multiple frames"},
239 })
240 .data<&ssil_settings::temporal>("temporal"_hs)
242 entt::attribute{"name", "temporal"},
243 entt::attribute{"predicate", temporal_predicate_entt},
244 entt::attribute{"pretty_name", "Temporal Accumulation"},
245 entt::attribute{"tooltip", "Temporal accumulation settings"},
246 // entt::attribute{"flattable", true},
247 });
248}
249
250// --- Serialization: spatial_denoise_settings ---
251
253{
254 try_save(ar, ser20::make_nvp("depth_sigma", obj.depth_sigma));
255 try_save(ar, ser20::make_nvp("normal_power", obj.normal_power));
256 try_save(ar, ser20::make_nvp("luma_sigma", obj.luma_sigma));
257 try_save(ar, ser20::make_nvp("passes", obj.passes));
258 try_save(ar, ser20::make_nvp("full_res_passes", obj.full_res_passes));
259 try_save(ar, ser20::make_nvp("max_step", obj.max_step));
260}
263
265{
266 try_load(ar, ser20::make_nvp("depth_sigma", obj.depth_sigma));
267 try_load(ar, ser20::make_nvp("normal_power", obj.normal_power));
268 try_load(ar, ser20::make_nvp("luma_sigma", obj.luma_sigma));
269 try_load(ar, ser20::make_nvp("passes", obj.passes));
270 try_load(ar, ser20::make_nvp("full_res_passes", obj.full_res_passes));
271 try_load(ar, ser20::make_nvp("max_step", obj.max_step));
272}
275
276// --- Serialization: temporal_settings ---
277
279{
280 try_save(ar, ser20::make_nvp("history_strength", obj.history_strength));
281 try_save(ar, ser20::make_nvp("depth_threshold", obj.depth_threshold));
282 try_save(ar, ser20::make_nvp("normal_dot_threshold", obj.normal_dot_threshold));
283 try_save(ar, ser20::make_nvp("max_accum_frames", obj.max_accum_frames));
284}
287
289{
290 try_load(ar, ser20::make_nvp("history_strength", obj.history_strength));
291 try_load(ar, ser20::make_nvp("depth_threshold", obj.depth_threshold));
292 try_load(ar, ser20::make_nvp("normal_dot_threshold", obj.normal_dot_threshold));
293 try_load(ar, ser20::make_nvp("max_accum_frames", obj.max_accum_frames));
294}
297
298// --- Serialization: ssil_settings ---
299
301{
302 try_save(ar, ser20::make_nvp("max_rays", obj.max_rays));
303 try_save(ar, ser20::make_nvp("max_steps", obj.max_steps));
304 try_save(ar, ser20::make_nvp("depth_tolerance", obj.depth_tolerance));
305 try_save(ar, ser20::make_nvp("thickness", obj.thickness));
306 try_save(ar, ser20::make_nvp("brightness", obj.brightness));
307 try_save(ar, ser20::make_nvp("max_distance", obj.max_distance));
308 try_save(ar, ser20::make_nvp("resolution", obj.resolution));
309 try_save(ar, ser20::make_nvp("enable_multi_bounce", obj.enable_multi_bounce));
310 try_save(ar, ser20::make_nvp("multi_bounce_intensity", obj.multi_bounce_intensity));
311 try_save(ar, ser20::make_nvp("enable_spatial_denoise", obj.enable_spatial_denoise));
312 try_save(ar, ser20::make_nvp("spatial_denoise", obj.spatial_denoise));
313 try_save(ar, ser20::make_nvp("enable_temporal_accumulation", obj.enable_temporal_accumulation));
314 try_save(ar, ser20::make_nvp("temporal", obj.temporal));
315}
318
320{
321 try_load(ar, ser20::make_nvp("max_rays", obj.max_rays));
322 try_load(ar, ser20::make_nvp("max_steps", obj.max_steps));
323 try_load(ar, ser20::make_nvp("depth_tolerance", obj.depth_tolerance));
324 try_load(ar, ser20::make_nvp("thickness", obj.thickness));
325 try_load(ar, ser20::make_nvp("brightness", obj.brightness));
326 try_load(ar, ser20::make_nvp("max_distance", obj.max_distance));
327 // Backwards compat: legacy scenes store the old boolean under `enable_half_res`.
328 // Try the new enum field first; fall back to the bool when missing.
329 if(!try_load(ar, ser20::make_nvp("resolution", obj.resolution)))
330 {
331 bool legacy_half_res = false;
332 if(try_load(ar, ser20::make_nvp("enable_half_res", legacy_half_res)))
333 {
334 obj.resolution = legacy_half_res ? trace_resolution::half : trace_resolution::full;
335 }
336 }
337 try_load(ar, ser20::make_nvp("enable_multi_bounce", obj.enable_multi_bounce));
338 try_load(ar, ser20::make_nvp("multi_bounce_intensity", obj.multi_bounce_intensity));
339 try_load(ar, ser20::make_nvp("enable_spatial_denoise", obj.enable_spatial_denoise));
340 try_load(ar, ser20::make_nvp("spatial_denoise", obj.spatial_denoise));
341 try_load(ar, ser20::make_nvp("enable_temporal_accumulation", obj.enable_temporal_accumulation));
342 try_load(ar, ser20::make_nvp("temporal", obj.temporal));
343}
346
347// --- Reflection + Serialization: ssil_component ---
348
350{
351 entt::meta_factory<ssil_component>{}
352 .type("ssil_component"_hs)
354 entt::attribute{"name", "ssil_component"},
355 entt::attribute{"category", "RENDERING"},
356 entt::attribute{"pretty_name", "SSIL"},
357 })
358 .func<&component_meta<ssil_component>::exists>("component_exists"_hs)
359 .func<&component_meta<ssil_component>::add>("component_add"_hs)
360 .func<&component_meta<ssil_component>::remove>("component_remove"_hs)
361 .func<&component_meta<ssil_component>::save>("component_save"_hs)
362 .func<&component_meta<ssil_component>::load>("component_load"_hs)
363 .data<&ssil_component::enabled>("enabled"_hs)
364 .custom<entt::attributes>(entt::attributes{
365 entt::attribute{"name", "enabled"},
366 entt::attribute{"pretty_name", "Enabled"},
367 entt::attribute{"tooltip", "Enable/disable Screen Space Indirect Lighting"},
368 })
369 .data<&ssil_component::settings>("settings"_hs)
371 entt::attribute{"name", "settings"},
372 entt::attribute{"pretty_name", "Settings"},
373 entt::attribute{"flattable", true},
374 });
375}
376
378{
379 try_save(ar, ser20::make_nvp("enabled", obj.enabled));
380 try_save(ar, ser20::make_nvp("settings", obj.settings));
381}
384
386{
387 try_load(ar, ser20::make_nvp("enabled", obj.enabled));
388 try_load(ar, ser20::make_nvp("settings", obj.settings));
389}
392
393} // namespace unravel
auto property_predicate(property_predicate_t< T > predicate) -> property_predicate_t< T >
Definition reflection.h:89
attributes::value_type attribute
Definition reflection.h:19
std::map< std::string, meta_any > attributes
Definition reflection.h:18
BinaryInputArchive iarchive_binary_t
simd::JSONOutputArchive oarchive_associative_t
BinaryOutputArchive oarchive_binary_t
simd::JSONInputArchive iarchive_associative_t
#define REFLECT(cls)
Definition reflection.h:149
#define REFLECT_INLINE(cls)
Definition reflection.h:144
#define SAVE_INSTANTIATE(cls, Archive)
#define LOAD(cls)
auto try_save(Archive &ar, ser20::NameValuePair< T > &&t, const hpp::source_location &loc=hpp::source_location::current()) -> bool
#define LOAD_INSTANTIATE(cls, Archive)
#define SAVE(cls)
#define LOAD_INLINE(cls)
#define SAVE_INLINE(cls)
auto try_load(Archive &ar, ser20::NameValuePair< T > &&t, const hpp::source_location &loc=hpp::source_location::current()) -> bool
Spatial denoise parameters (a-trous wavelet filter)
Definition ssil_pass.h:18
Temporal accumulation parameters.
Definition ssil_pass.h:47