105 enabled_ = inst_.world.has_volume() || !current_objects_.is_empty();
107 const Scene *scene_eval = inst_.scene;
110 const float camera_clip_start = inst_.camera.data_get().clip_near;
111 const float camera_clip_end = inst_.camera.data_get().clip_far;
115 if (!inst_.camera.is_camera_object() && inst_.camera.is_orthographic()) {
116 integration_start = -integration_end;
119 std::optional<Bounds<float>> volume_bounds = inst_.pipelines.volume.object_integration_range();
120 if (volume_bounds && !inst_.world.has_volume()) {
122 integration_start =
math::max(integration_start, -volume_bounds.value().max);
123 integration_end =
math::min(integration_end, -volume_bounds.value().min);
127 float near = -
math::max(integration_start, camera_clip_start - 1e-4f);
128 float far = -
math::min(integration_end, camera_clip_end + 1e-4f);
134 valid_history_ =
false;
137 if (valid_history_) {
139 if (current_objects_ != previous_objects_) {
140 valid_history_ =
false;
144 if (inst_.camera.is_perspective()) {
146 sample_distribution = 4.0f *
math::max(1.0f - sample_distribution, 1e-2f);
148 data_.depth_near = (far - near * exp2(1.0f / sample_distribution)) / (far - near);
149 data_.depth_far = (1.0f - data_.depth_near) / near;
150 data_.depth_distribution = sample_distribution;
153 data_.depth_near = near;
154 data_.depth_far = far;
155 data_.depth_distribution = 0.0f;
159 occupancy_tx_.free();
160 prop_scattering_tx_.free();
161 prop_extinction_tx_.free();
162 prop_emission_tx_.free();
163 prop_phase_tx_.free();
164 prop_phase_weight_tx_.free();
165 scatter_tx_.current().free();
166 scatter_tx_.previous().free();
167 extinction_tx_.current().free();
168 extinction_tx_.previous().free();
169 integrated_scatter_tx_.free();
170 integrated_transmit_tx_.free();
173 result.scattering_tx_ = dummy_scatter_tx_;
174 result.transmittance_tx_ = dummy_transmit_tx_;
187 valid_history_ =
false;
191 bool has_scatter = inst_.world.has_volume_scatter() || inst_.pipelines.volume.has_scatter();
192 bool has_absorption = inst_.world.has_volume_absorption() ||
193 inst_.pipelines.volume.has_absorption();
194 use_lights_ = has_scatter;
205 prop_phase_tx_.ensure_3d(
GPU_R16F, data_.tex_size, usage);
206 prop_phase_weight_tx_.ensure_3d(
GPU_R16F, data_.tex_size, usage);
211 occupancy_tx_.ensure_3d(
GPU_R32UI,
int3(data_.tex_size.xy(), occupancy_layers), occupancy_usage);
219 int hit_list_layer = 1;
220 if (inst_.pipelines.volume.use_hit_list()) {
221 hit_list_layer =
clamp_i(inst_.scene->eevee.volumetric_ray_depth, 1, 16);
222 hit_list_size = data_.tex_size.
xy();
224 hit_depth_tx_.ensure_3d(
GPU_R32F,
int3(hit_list_size, hit_list_layer), hit_depth_usage);
225 if (hit_count_tx_.ensure_2d(
GPU_R32UI, hit_list_size, hit_count_usage)) {
226 hit_count_tx_.clear(
uint4(0u));
235 bool created =
false;
236 created |= scatter_tx_.current().ensure_3d(
GPU_R11F_G11F_B10F, data_.tex_size, usage);
237 created |= extinction_tx_.current().ensure_3d(
GPU_R11F_G11F_B10F, data_.tex_size, usage);
238 created |= scatter_tx_.previous().ensure_3d(
GPU_R11F_G11F_B10F, data_.tex_size, usage);
239 created |= extinction_tx_.previous().ensure_3d(
GPU_R11F_G11F_B10F, data_.tex_size, usage);
242 valid_history_ =
false;
249 result.scattering_tx_ = integrated_scatter_tx_;
250 result.transmittance_tx_ = integrated_transmit_tx_;
251 properties.scattering_tx_ = prop_scattering_tx_;
252 properties.extinction_tx_ = prop_extinction_tx_;
255 properties.phase_weight_tx_ = prop_phase_weight_tx_;
268 scatter_ps_.shader_set(
270 scatter_ps_.bind_resources(inst_.lights);
271 scatter_ps_.bind_resources(inst_.sphere_probes);
272 scatter_ps_.bind_resources(inst_.volume_probes);
273 scatter_ps_.bind_resources(inst_.shadows);
274 scatter_ps_.bind_resources(inst_.uniform_data);
275 scatter_ps_.bind_resources(inst_.sampling);
276 scatter_ps_.bind_image(
"in_scattering_img", &prop_scattering_tx_);
277 scatter_ps_.bind_image(
"in_extinction_img", &prop_extinction_tx_);
278 scatter_ps_.bind_texture(
"extinction_tx", &prop_extinction_tx_);
279 scatter_ps_.bind_image(
"in_emission_img", &prop_emission_tx_);
280 scatter_ps_.bind_image(
"in_phase_img", &prop_phase_tx_);
281 scatter_ps_.bind_image(
"in_phase_weight_img", &prop_phase_weight_tx_);
282 scatter_ps_.bind_texture(
"scattering_history_tx", &scatter_tx_.previous(), history_sampler);
283 scatter_ps_.bind_texture(
"extinction_history_tx", &extinction_tx_.previous(), history_sampler);
284 scatter_ps_.bind_image(
"out_scattering_img", &scatter_tx_.current());
285 scatter_ps_.bind_image(
"out_extinction_img", &extinction_tx_.current());
291 integration_ps_.init();
293 integration_ps_.bind_resources(inst_.uniform_data);
294 integration_ps_.bind_resources(inst_.sampling);
295 integration_ps_.bind_texture(
"in_scattering_tx", &scatter_tx_.current());
296 integration_ps_.bind_texture(
"in_extinction_tx", &extinction_tx_.current());
297 integration_ps_.bind_image(
"out_scattering_img", &integrated_scatter_tx_);
298 integration_ps_.bind_image(
"out_transmittance_img", &integrated_transmit_tx_);
301 integration_ps_.dispatch(
306 resolve_ps_.shader_set(inst_.shaders.static_shader_get(
VOLUME_RESOLVE));
307 resolve_ps_.bind_resources(inst_.uniform_data);
308 resolve_ps_.bind_resources(this->
result);
309 resolve_ps_.bind_resources(inst_.hiz_buffer.front);
310 resolve_ps_.bind_image(
RBUFS_COLOR_SLOT, &inst_.render_buffers.rp_color_tx);
311 resolve_ps_.bind_image(
RBUFS_VALUE_SLOT, &inst_.render_buffers.rp_value_tx);
324 int exponential_frame_count = 16;
325 if (inst_.is_image_render()) {
327 exponential_frame_count = 0;
329 else if (!use_reprojection_) {
331 exponential_frame_count = 0;
333 else if (inst_.is_playback()) {
338 exponential_frame_count = 3;
340 else if (inst_.is_transforming()) {
344 exponential_frame_count = 3;
346 else if (inst_.is_navigating()) {
349 exponential_frame_count = 8;
351 else if (inst_.sampling.is_reset()) {
354 exponential_frame_count = 0;
357 if (!valid_history_) {
358 history_frame_count_ = 0;
364 history_frame_count_ =
math::min(history_frame_count_, exponential_frame_count);
368 float history_opacity = history_frame_count_ / (history_frame_count_ + 1.0f);
372 data_.history_opacity = (valid_history_) ? history_opacity : 0.0f;
374 float left, right, bottom,
top, near, far;
380 float2 volume_size = render_size *
float2(data_.tex_size.xy() * data_.tile_size) /
381 float2(inst_.film.render_extent_get());
383 right =
left + volume_size.x;
384 top = bottom + volume_size.y;
386 float4x4 winmat_infinite, winmat_finite;
389 winmat_infinite = main_view.
is_persp() ?
393 winmat_finite = main_view.
is_persp() ?
397 data_.winmat_stable = winmat_finite;
405 jitter *= data_.inv_tex_size.
xy();
410 data_.winmat_finite = winmat_finite;
414 data_.curr_view_to_past_view = history_viewmat_ * main_view.
viewinv();
416 inst_.uniform_data.push_update();
419 occupancy_fb_.bind();
420 inst_.pipelines.world_volume.render(main_view);
422 volume_view.sync(main_view.
viewmat(), winmat_infinite);
425 volume_view.visibility_test(
false);
427 if (!current_objects_.is_empty()) {
428 inst_.pipelines.volume.render(volume_view, occupancy_tx_);