112 const Scene *scene_eval = inst_.scene;
115 const float camera_clip_start = inst_.camera.data_get().clip_near;
116 const float camera_clip_end = inst_.camera.data_get().clip_far;
120 if (!inst_.camera.is_camera_object() && inst_.camera.is_orthographic()) {
121 integration_start = -integration_end;
124 std::optional<Bounds<float>> volume_bounds = inst_.pipelines.volume.object_integration_range();
125 if (volume_bounds && !inst_.world.has_volume()) {
127 integration_start =
math::max(integration_start, -volume_bounds.value().max);
128 integration_end =
math::min(integration_end, -volume_bounds.value().min);
132 float near = -
math::max(integration_start, camera_clip_start - 1e-4f);
133 float far = -
math::min(integration_end, camera_clip_end + 1e-4f);
139 valid_history_ =
false;
142 if (valid_history_) {
144 if (current_objects_ != previous_objects_) {
145 valid_history_ =
false;
149 if (inst_.camera.is_perspective()) {
151 sample_distribution = 4.0f *
math::max(1.0f - sample_distribution, 1e-2f);
153 data_.depth_near = (far - near *
exp2(1.0f / sample_distribution)) / (far - near);
154 data_.depth_far = (1.0f - data_.depth_near) / near;
155 data_.depth_distribution = sample_distribution;
158 data_.depth_near = near;
159 data_.depth_far = far;
160 data_.depth_distribution = 0.0f;
164 occupancy_tx_.free();
165 prop_scattering_tx_.free();
166 prop_extinction_tx_.free();
167 prop_emission_tx_.free();
168 prop_phase_tx_.free();
169 prop_phase_weight_tx_.free();
170 scatter_tx_.current().free();
171 scatter_tx_.previous().free();
172 extinction_tx_.current().free();
173 extinction_tx_.previous().free();
174 integrated_scatter_tx_.free();
175 integrated_transmit_tx_.free();
178 result.scattering_tx_ = dummy_scatter_tx_;
179 result.transmittance_tx_ = dummy_transmit_tx_;
192 valid_history_ =
false;
196 bool has_scatter = inst_.world.has_volume_scatter() || inst_.pipelines.volume.has_scatter();
197 bool has_absorption = inst_.world.has_volume_absorption() ||
198 inst_.pipelines.volume.has_absorption();
199 use_lights_ = has_scatter;
210 prop_phase_tx_.ensure_3d(
GPU_R16F, data_.tex_size, usage);
211 prop_phase_weight_tx_.ensure_3d(
GPU_R16F, data_.tex_size, usage);
216 occupancy_tx_.ensure_3d(
GPU_R32UI,
int3(data_.tex_size.xy(), occupancy_layers), occupancy_usage);
224 int hit_list_layer = 1;
225 if (inst_.pipelines.volume.use_hit_list()) {
226 hit_list_layer =
clamp_i(inst_.scene->eevee.volumetric_ray_depth, 1, 16);
227 hit_list_size = data_.tex_size.
xy();
229 hit_depth_tx_.ensure_3d(
GPU_R32F,
int3(hit_list_size, hit_list_layer), hit_depth_usage);
230 if (hit_count_tx_.ensure_2d(
GPU_R32UI, hit_list_size, hit_count_usage)) {
231 hit_count_tx_.clear(
uint4(0u));
240 bool created =
false;
241 created |= scatter_tx_.current().ensure_3d(
GPU_R11F_G11F_B10F, data_.tex_size, usage);
242 created |= extinction_tx_.current().ensure_3d(
GPU_R11F_G11F_B10F, data_.tex_size, usage);
243 created |= scatter_tx_.previous().ensure_3d(
GPU_R11F_G11F_B10F, data_.tex_size, usage);
244 created |= extinction_tx_.previous().ensure_3d(
GPU_R11F_G11F_B10F, data_.tex_size, usage);
247 valid_history_ =
false;
254 result.scattering_tx_ = integrated_scatter_tx_;
255 result.transmittance_tx_ = integrated_transmit_tx_;
256 properties.scattering_tx_ = prop_scattering_tx_;
257 properties.extinction_tx_ = prop_extinction_tx_;
260 properties.phase_weight_tx_ = prop_phase_weight_tx_;
273 scatter_ps_.shader_set(
275 scatter_ps_.bind_resources(inst_.lights);
276 scatter_ps_.bind_resources(inst_.sphere_probes);
277 scatter_ps_.bind_resources(inst_.volume_probes);
278 scatter_ps_.bind_resources(inst_.shadows);
279 scatter_ps_.bind_resources(inst_.uniform_data);
280 scatter_ps_.bind_resources(inst_.sampling);
281 scatter_ps_.bind_image(
"in_scattering_img", &prop_scattering_tx_);
282 scatter_ps_.bind_image(
"in_extinction_img", &prop_extinction_tx_);
283 scatter_ps_.bind_texture(
"extinction_tx", &prop_extinction_tx_);
284 scatter_ps_.bind_image(
"in_emission_img", &prop_emission_tx_);
285 scatter_ps_.bind_image(
"in_phase_img", &prop_phase_tx_);
286 scatter_ps_.bind_image(
"in_phase_weight_img", &prop_phase_weight_tx_);
287 scatter_ps_.bind_texture(
"scattering_history_tx", &scatter_tx_.previous(), history_sampler);
288 scatter_ps_.bind_texture(
"extinction_history_tx", &extinction_tx_.previous(), history_sampler);
289 scatter_ps_.bind_image(
"out_scattering_img", &scatter_tx_.current());
290 scatter_ps_.bind_image(
"out_extinction_img", &extinction_tx_.current());
296 integration_ps_.init();
298 integration_ps_.bind_resources(inst_.uniform_data);
299 integration_ps_.bind_resources(inst_.sampling);
300 integration_ps_.bind_texture(
"in_scattering_tx", &scatter_tx_.current());
301 integration_ps_.bind_texture(
"in_extinction_tx", &extinction_tx_.current());
302 integration_ps_.bind_image(
"out_scattering_img", &integrated_scatter_tx_);
303 integration_ps_.bind_image(
"out_transmittance_img", &integrated_transmit_tx_);
306 integration_ps_.dispatch(
311 resolve_ps_.shader_set(inst_.shaders.static_shader_get(
VOLUME_RESOLVE));
312 resolve_ps_.bind_resources(inst_.uniform_data);
313 resolve_ps_.bind_resources(this->
result);
314 resolve_ps_.bind_resources(inst_.hiz_buffer.front);
315 resolve_ps_.bind_image(
RBUFS_COLOR_SLOT, &inst_.render_buffers.rp_color_tx);
316 resolve_ps_.bind_image(
RBUFS_VALUE_SLOT, &inst_.render_buffers.rp_value_tx);
329 int exponential_frame_count = 16;
330 if (inst_.is_image_render) {
332 exponential_frame_count = 0;
334 else if (!use_reprojection_) {
336 exponential_frame_count = 0;
338 else if (inst_.is_playback) {
343 exponential_frame_count = 3;
345 else if (inst_.is_transforming) {
349 exponential_frame_count = 3;
351 else if (inst_.is_navigating) {
354 exponential_frame_count = 8;
356 else if (inst_.is_viewport() && inst_.sampling.is_reset()) {
359 exponential_frame_count = 0;
362 if (!valid_history_) {
363 history_frame_count_ = 0;
369 history_frame_count_ =
math::min(history_frame_count_, exponential_frame_count);
373 float history_opacity = history_frame_count_ / (history_frame_count_ + 1.0f);
377 data_.history_opacity = (valid_history_) ? history_opacity : 0.0f;
379 float left, right, bottom,
top, near, far;
385 float2 volume_size = render_size *
float2(data_.tex_size.xy() * data_.tile_size) /
386 float2(inst_.film.render_extent_get());
388 right =
left + volume_size.x;
389 top = bottom + volume_size.y;
391 float4x4 winmat_infinite, winmat_finite;
394 winmat_infinite = main_view.
is_persp() ?
398 winmat_finite = main_view.
is_persp() ?
402 data_.winmat_stable = winmat_finite;
410 jitter *= data_.inv_tex_size.
xy();
415 data_.winmat_finite = winmat_finite;
419 data_.curr_view_to_past_view = history_viewmat_ * main_view.
viewinv();
421 inst_.uniform_data.push_update();
424 occupancy_fb_.bind();
425 inst_.pipelines.world_volume.render(main_view);
427 volume_view.sync(main_view.
viewmat(), winmat_infinite);
430 volume_view.visibility_test(
false);
432 if (!current_objects_.is_empty()) {
433 inst_.pipelines.volume.render(volume_view, occupancy_tx_);