Unravel Engine C++ Reference
Loading...
Searching...
No Matches
volume_resolver.cpp
Go to the documentation of this file.
1#include "volume_resolver.h"
12#include <algorithm>
13#include <cmath>
14#include <limits>
15#include <vector>
16
17namespace unravel
18{
19
20namespace
21{
22
23struct volume_contribution
24{
25 entt::entity entity;
31 float size;
32};
33
40struct enabled_resolver
41{
42 bool seen = false;
43 bool enabled = false;
44
45 void accumulate(bool component_enabled, float contribution)
46 {
47 if(!seen)
48 {
49 enabled = component_enabled;
50 seen = true;
51 return;
52 }
53 if(contribution >= 0.5f)
54 {
55 enabled = component_enabled;
56 }
57 }
58
59 auto resolve() const -> bool
60 {
61 return seen && enabled;
62 }
63};
64
65auto compute_blend_factor(const math::bbox& world_bounds,
66 const math::vec3& camera_pos,
67 float blend_distance) -> float
68{
69 if(world_bounds.contains_point(camera_pos))
70 {
71 return 1.0f;
72 }
73 const math::vec3 closest = world_bounds.closest_point(camera_pos);
74 const float dist_to_boundary = glm::length(camera_pos - closest);
75 if(blend_distance <= 0.0f)
76 {
77 return dist_to_boundary <= 0.0f ? 1.0f : 0.0f;
78 }
79 if(dist_to_boundary >= blend_distance)
80 {
81 return 0.0f;
82 }
83 return 1.0f - (dist_to_boundary / blend_distance);
84}
85
86} // namespace
87
89 const math::vec3& camera_pos,
90 entt::handle camera_ent) -> resolved_post_process_settings
91{
93
94 std::vector<volume_contribution> contributions;
95
96 scn.registry->view<transform_component, volume_component, active_component>().each(
97 [&](entt::entity e, const transform_component& transform_comp, const volume_component& volume_comp, const active_component& active_comp)
98 {
99 float contribution = 0.0f;
100 float size = std::numeric_limits<float>::max();
101 if(volume_comp.mode == volume_mode::global)
102 {
103 contribution = volume_comp.weight;
104 }
105 else
106 {
107 const math::bbox local_bounds = volume_comp.get_local_bounds();
108 const math::transform& world_transform = transform_comp.get_transform_global();
109 const math::bbox world_bounds = math::bbox::mul(local_bounds, world_transform);
110 const float blend_factor = compute_blend_factor(world_bounds, camera_pos, volume_comp.blend_distance);
111 contribution = volume_comp.weight * blend_factor;
112 const math::vec3 dims = world_bounds.get_dimensions();
113 size = dims.x * dims.y * dims.z;
114 }
115 if(contribution > 0.0f)
116 {
117 contributions.push_back({e, contribution, volume_comp.priority, volume_comp.mode == volume_mode::global, size});
118 }
119 });
120
121 // Order volumes so the most authoritative one is applied last: the merge
122 // model seeds the result with the first volume and lets later volumes
123 // override it (see *_component::merge_into and enabled_resolver). Sorting
124 // ascending by priority makes a higher-priority volume win; the
125 // global-before-local tiebreak lets a local volume override a global at
126 // equal priority; for the same priority and type the larger contribution is
127 // applied last; and when contributions tie (e.g. the camera is fully inside
128 // two overlapping locals) the smaller, more specific volume is applied last
129 // so it wins.
130 std::sort(contributions.begin(),
131 contributions.end(),
132 [](const volume_contribution& a, const volume_contribution& b)
133 {
134 if(a.priority != b.priority)
135 {
136 return a.priority < b.priority;
137 }
138 if(a.is_global != b.is_global)
139 {
140 return a.is_global && !b.is_global;
141 }
142 if(a.contribution != b.contribution)
143 {
144 return a.contribution < b.contribution;
145 }
146 return a.size > b.size;
147 });
148
149 bool first_auto_exposure = true;
150 bool first_bloom = true;
151 bool first_tonemapping = true;
152 bool first_assao = true;
153 bool first_ssr = true;
154 bool first_ssil = true;
155 bool first_taa = true;
156 enabled_resolver auto_exposure_enabled;
157 enabled_resolver bloom_enabled;
158 enabled_resolver tonemapping_enabled;
159 enabled_resolver fxaa_enabled;
160 enabled_resolver ssr_enabled;
161 enabled_resolver assao_enabled;
162 enabled_resolver ssil_enabled;
163 enabled_resolver taa_enabled;
164
165 for(const auto& c : contributions)
166 {
167 auto handle = scn.create_handle(c.entity);
168 const float contrib = c.contribution;
169
170 if(auto* ae = handle.try_get<auto_exposure_component>(); ae && contrib > 0.0f)
171 {
172 auto_exposure_enabled.accumulate(ae->enabled, contrib);
173 if(ae->enabled)
174 {
175 auto_exposure_component::merge_into(result.auto_exposure, ae->settings, contrib, first_auto_exposure);
176 first_auto_exposure = false;
177 }
178 }
179
180 if(auto* bloom = handle.try_get<bloom_component>(); bloom && contrib > 0.0f)
181 {
182 bloom_enabled.accumulate(bloom->enabled, contrib);
183 if(bloom->enabled)
184 {
185 bloom_component::merge_into(result.bloom, bloom->settings, contrib, first_bloom);
186 first_bloom = false;
187 }
188 }
189
190 if(auto* tonemapping = handle.try_get<tonemapping_component>(); tonemapping && contrib > 0.0f)
191 {
192 tonemapping_enabled.accumulate(tonemapping->enabled, contrib);
193 if(tonemapping->enabled)
194 {
195 tonemapping_component::merge_into(result.tonemapping, tonemapping->settings, contrib, first_tonemapping);
196 first_tonemapping = false;
197 }
198 }
199
200 if(auto* fxaa = handle.try_get<fxaa_component>(); fxaa && contrib > 0.0f)
201 {
202 fxaa_enabled.accumulate(fxaa->enabled, contrib);
203 }
204
205 if(auto* taa = handle.try_get<taa_component>(); taa && contrib > 0.0f)
206 {
207 taa_enabled.accumulate(taa->enabled, contrib);
208 if(taa->enabled)
209 {
210 taa_component::merge_into(result.taa, taa->settings, contrib, first_taa);
211 first_taa = false;
212 }
213 }
214
215 if(auto* ssr = handle.try_get<ssr_component>(); ssr && contrib > 0.0f)
216 {
217 ssr_enabled.accumulate(ssr->enabled, contrib);
218 if(ssr->enabled)
219 {
220 ssr_component::merge_into(result.ssr, ssr->settings, contrib, first_ssr);
221 first_ssr = false;
222 }
223 }
224
225 if(auto* assao = handle.try_get<assao_component>(); assao && contrib > 0.0f)
226 {
227 assao_enabled.accumulate(assao->enabled, contrib);
228 if(assao->enabled)
229 {
230 assao_component::merge_into(result.assao, assao->settings, contrib, first_assao);
231 first_assao = false;
232 }
233 }
234
235 if(auto* ssil = handle.try_get<ssil_component>(); ssil && contrib > 0.0f)
236 {
237 ssil_enabled.accumulate(ssil->enabled, contrib);
238 if(ssil->enabled)
239 {
240 ssil_component::merge_into(result.ssil, ssil->settings, contrib, first_ssil);
241 first_ssil = false;
242 }
243 }
244 }
245
246 result.has_auto_exposure = auto_exposure_enabled.resolve();
247 result.has_bloom = bloom_enabled.resolve();
248 result.has_tonemapping = tonemapping_enabled.resolve();
249 result.has_fxaa = fxaa_enabled.resolve();
250 result.has_taa = taa_enabled.resolve();
251 result.has_ssr = ssr_enabled.resolve();
252 result.has_assao = assao_enabled.resolve();
253 result.has_ssil = ssil_enabled.resolve();
254
255 return result;
256}
257
258} // namespace unravel
entt::handle b
entt::handle a
General purpose transformation class designed to maintain each component of the transformation separa...
Definition transform.hpp:27
static void merge_into(assao_pass::settings &result, const assao_pass::settings &from, float contribution, bool is_first)
Merges this component's settings into result. For first contribution, copies; otherwise lerps.
static void merge_into(auto_exposure_pass::settings &result, const auto_exposure_pass::settings &from, float contribution, bool is_first)
Merges this component's settings into result. For first contribution, copies; otherwise lerps.
static void merge_into(bloom_pass::settings &result, const bloom_pass::settings &from, float contribution, bool is_first)
Merges this component's settings into result. For first contribution, copies; otherwise lerps.
static void merge_into(ssil_pass::ssil_settings &result, const ssil_pass::ssil_settings &from, float contribution, bool is_first)
static void merge_into(ssr_pass::ssr_settings &result, const ssr_pass::ssr_settings &from, float contribution, bool is_first)
Merges this component's settings into result. For first contribution, copies; otherwise lerps.
static void merge_into(taa_pass::settings &result, const taa_pass::settings &from, float contribution, bool is_first)
static void merge_into(tonemapping_pass::settings &result, const tonemapping_pass::settings &from, float contribution, bool is_first)
Merges this component's settings into result. For first contribution, copies; otherwise lerps.
Component that handles transformations (position, rotation, scale, etc.) in the ACE framework.
auto get_transform_global() const noexcept -> const math::transform &
Gets the global transform.
Spatial volume that applies post-processing effects when the camera is inside. Effect settings come f...
auto get_local_bounds() const -> math::bbox
Gets local bounding box (before transform).
int priority
Higher priority wins when multiple volumes overlap.
float blend_distance
Distance outside the volume over which blending ramps from 0 to 1 (local volumes only)....
volume_mode mode
Volume mode: local uses bounds, global affects camera everywhere.
float weight
Influence multiplier in range [0, 1].
auto resolve_post_process_volumes(scene &scn, const math::vec3 &camera_pos, entt::handle camera_ent) -> resolved_post_process_settings
Resolves post-process volumes for a camera position.
entt::handle entity
Storage for box vector values and wraps up common functionality.
Definition bbox.h:21
bbox & mul(const transform &t)
Transforms an axis aligned bounding box by the specified matrix.
Definition bbox.cpp:876
vec3 get_dimensions() const
Returns a vector containing the dimensions of the bounding box.
Definition bbox.cpp:941
Merged post-processing settings from all contributing volumes.
Represents a scene in the ACE framework, managing entities and their relationships.
Definition scene.h:70
gfx::uniform_handle handle
Definition uniform.cpp:9
bool seen
float contribution
bool is_global
bool enabled
int priority