Files
test2/source/blender/draw/engines/eevee/eevee_lightprobe_planar.cc
Clément Foucault 0105b33a5f Refactor: DRW: Move some functions to DRWContext
This reduces the API and make it more clear where there
is the global access.

This also removes some of these global access by merging
the `DRW_context_get()` calls.
2025-03-17 17:19:13 +01:00

167 lines
5.6 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "eevee_lightprobe_planar.hh"
#include "eevee_instance.hh"
namespace blender::eevee {
using namespace blender::math;
/* -------------------------------------------------------------------- */
/** \name Planar Probe
* \{ */
void PlanarProbe::set_view(const draw::View &view, int layer_id)
{
this->viewmat = view.viewmat() * reflection_matrix_get();
this->winmat = view.winmat();
this->world_to_object_transposed = float3x4(transpose(world_to_plane));
this->normal = normalize(plane_to_world.z_axis());
float3 view_vec = view.is_persp() ? view.location() - plane_to_world.location() : view.forward();
bool view_is_below_plane = dot(view_vec, plane_to_world.z_axis()) < 0.0;
if (view_is_below_plane) {
this->normal = -this->normal;
}
this->layer_id = layer_id;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Planar Probe Module
* \{ */
void PlanarProbeModule::init()
{
/* This triggers the compilation of clipped shader only if we can detect light-probe planes. */
if (inst_.is_viewport()) {
/* This check needs to happen upfront before sync, so we use the previous sync result. */
update_probes_ = !inst_.light_probes.planar_map_.is_empty();
}
else {
/* TODO(jbakker): should we check on the subtype as well? Now it also populates even when
* there are other light probes in the scene. */
update_probes_ = DEG_id_type_any_exists(inst_.depsgraph, ID_LP);
}
do_display_draw_ = false;
}
void PlanarProbeModule::end_sync()
{
/* When first planar probes are enabled it can happen that the first sample is off. */
if (!update_probes_ && !inst_.light_probes.planar_map_.is_empty()) {
DRW_viewport_request_redraw();
}
}
void PlanarProbeModule::set_view(const draw::View &main_view, int2 main_view_extent)
{
GBuffer &gbuf = inst_.gbuffer;
const int64_t num_probes = inst_.light_probes.planar_map_.size();
/* TODO resolution percentage. */
int2 extent = main_view_extent;
int layer_count = num_probes;
if (num_probes == 0) {
/* Create valid dummy texture. */
extent = int2(1);
layer_count = 1;
}
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_SHADER_READ;
radiance_tx_.ensure_2d_array(GPU_R11F_G11F_B10F, extent, layer_count, usage);
depth_tx_.ensure_2d_array(GPU_DEPTH_COMPONENT32F, extent, layer_count, usage);
depth_tx_.ensure_layer_views();
do_display_draw_ = inst_.draw_overlays && num_probes > 0;
int resource_index = 0;
int display_index = 0;
for (PlanarProbe &probe : inst_.light_probes.planar_map_.values()) {
if (resource_index == PLANAR_PROBE_MAX) {
break;
}
PlanarResources &res = resources_[resource_index];
/* TODO Cull out of view planars. */
probe.set_view(main_view, resource_index);
probe_planar_buf_[resource_index] = probe;
res.view.sync(probe.viewmat, probe.winmat);
world_clip_buf_.plane = probe.reflection_clip_plane_get();
world_clip_buf_.push_update();
gbuf.acquire(extent,
inst_.pipelines.deferred.closure_layer_count(),
inst_.pipelines.deferred.normal_layer_count());
res.combined_fb.ensure(GPU_ATTACHMENT_TEXTURE_LAYER(depth_tx_, resource_index),
GPU_ATTACHMENT_TEXTURE_LAYER(radiance_tx_, resource_index));
res.gbuffer_fb.ensure(GPU_ATTACHMENT_TEXTURE_LAYER(depth_tx_, resource_index),
GPU_ATTACHMENT_TEXTURE_LAYER(radiance_tx_, resource_index),
GPU_ATTACHMENT_TEXTURE(gbuf.header_tx),
GPU_ATTACHMENT_TEXTURE_LAYER(gbuf.normal_tx.layer_view(0), 0),
GPU_ATTACHMENT_TEXTURE_LAYER(gbuf.closure_tx.layer_view(0), 0),
GPU_ATTACHMENT_TEXTURE_LAYER(gbuf.closure_tx.layer_view(1), 0));
inst_.pipelines.planar.render(
res.view, depth_tx_.layer_view(resource_index), res.gbuffer_fb, res.combined_fb, extent);
if (do_display_draw_ && probe.viewport_display) {
display_data_buf_.get_or_resize(display_index++) = {probe.plane_to_world, resource_index};
}
resource_index++;
}
gbuf.release();
if (resource_index < PLANAR_PROBE_MAX) {
/* Tag the end of the array. */
probe_planar_buf_[resource_index].layer_id = -1;
}
probe_planar_buf_.push_update();
do_display_draw_ = display_index > 0;
if (do_display_draw_) {
display_data_buf_.resize(display_index);
display_data_buf_.push_update();
}
}
void PlanarProbeModule::viewport_draw(View &view, GPUFrameBuffer *view_fb)
{
if (!do_display_draw_) {
return;
}
viewport_display_ps_.init();
viewport_display_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK);
viewport_display_ps_.framebuffer_set(&view_fb);
viewport_display_ps_.shader_set(inst_.shaders.static_shader_get(DISPLAY_PROBE_PLANAR));
SphereProbeData &world_data = *static_cast<SphereProbeData *>(&inst_.light_probes.world_sphere_);
viewport_display_ps_.push_constant("world_coord_packed",
reinterpret_cast<int4 *>(&world_data.atlas_coord));
viewport_display_ps_.bind_resources(*this);
viewport_display_ps_.bind_resources(inst_.sphere_probes);
viewport_display_ps_.bind_ssbo("display_data_buf", display_data_buf_);
viewport_display_ps_.draw_procedural(GPU_PRIM_TRIS, 1, display_data_buf_.size() * 6);
inst_.manager->submit(viewport_display_ps_, view);
}
/** \} */
} // namespace blender::eevee