Files
test2/source/blender/draw/engines/eevee/eevee_light.hh
2025-04-17 12:06:12 +10:00

198 lines
6.1 KiB
C++

/* SPDX-FileCopyrightText: 2021 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup eevee
*
* The light module manages light data buffers and light culling system.
*
* The culling follows the principles of Tiled Culling + Z binning from:
* "Improved Culling for Tiled and Clustered Rendering"
* by Michal Drobot
* http://advances.realtimerendering.com/s2017/2017_Sig_Improved_Culling_final.pdf
*
* The culling is separated in 4 compute phases:
* - View Culling (select pass): Create a z distance and a index buffer of visible lights.
* - Light sorting: Outputs visible lights sorted by Z distance.
* - Z binning: Compute the Z bins min/max light indices.
* - Tile intersection: Fine grained 2D culling of each lights outputting a bitmap per tile.
*/
#pragma once
#include "DNA_light_types.h"
#include "eevee_camera.hh"
#include "eevee_sampling.hh"
#include "eevee_shader_shared.hh"
#include "eevee_sync.hh"
namespace blender::eevee {
class Instance;
class ShadowModule;
/* -------------------------------------------------------------------- */
/** \name Light Object
* \{ */
struct Light : public LightData, NonCopyable {
public:
bool initialized = false;
bool used = false;
/** Pointers to source Shadow. Type depends on `LightData::type`. */
ShadowDirectional *directional = nullptr;
ShadowPunctual *punctual = nullptr;
Light()
{
/* Avoid valgrind warning. */
this->type = LIGHT_SUN;
}
/* Only used for debugging. */
#ifndef NDEBUG
Light(Light &&other)
{
*static_cast<LightData *>(this) = other;
this->initialized = other.initialized;
this->used = other.used;
this->directional = other.directional;
this->punctual = other.punctual;
other.directional = nullptr;
other.punctual = nullptr;
}
~Light()
{
BLI_assert(directional == nullptr);
BLI_assert(punctual == nullptr);
}
#endif
void sync(ShadowModule &shadows,
float4x4 object_to_world,
char visibility_flag,
const ::Light *la,
const LightLinking *light_linking,
float threshold);
void shadow_ensure(ShadowModule &shadows);
void shadow_discard_safe(ShadowModule &shadows);
void debug_draw();
private:
float shadow_lod_min_get(const ::Light *la);
float shadow_shape_size_get(const ::Light *la);
float attenuation_radius_get(const ::Light *la, float light_threshold, float light_power);
void shape_parameters_set(const ::Light *la,
const float3 &scale,
const float3 &z_axis,
float threshold,
bool use_jitter);
float shape_radiance_get();
float point_radiance_get();
};
/** \} */
/* -------------------------------------------------------------------- */
/** \name LightModule
* \{ */
/**
* The light module manages light data buffers and light culling system.
*/
class LightModule {
friend ShadowModule;
private:
/* Keep tile count reasonable for memory usage and 2D culling performance. */
static constexpr uint max_memory_threshold = 32 * 1024 * 1024; /* 32 MiB */
static constexpr uint max_word_count_threshold = max_memory_threshold / sizeof(uint);
static constexpr uint max_tile_count_threshold = 8192;
Instance &inst_;
/** Map of light objects data. Converted to flat array each frame. */
Map<ObjectKey, Light> light_map_;
ObjectKey world_sunlight_key;
/** Flat array sent to GPU, populated from light_map_. Source buffer for light culling. */
LightDataBuf light_buf_ = {"Lights_no_cull"};
/** Luminous intensity to consider the light boundary at. Used for culling. */
float light_threshold_ = 0.01f;
/** If false, will prevent all scene lights from being synced. */
bool use_scene_lights_ = false;
/** If false, will prevent all sun lights from being synced. */
bool use_sun_lights_ = false;
/** Number of sun lights synced during the last sync. Used as offset. */
int sun_lights_len_ = 0;
int local_lights_len_ = 0;
/** Sun plus local lights count for convenience. */
int lights_len_ = 0;
/**
* Light Culling
*/
/** LightData buffer used for rendering. Filled by the culling pass. */
LightDataBuf culling_light_buf_ = {"Lights_culled"};
/** Culling information. */
LightCullingDataBuf culling_data_buf_ = {"LightCull_data"};
/** Z-distance matching the key for each visible lights. Used for sorting. */
LightCullingZdistBuf culling_zdist_buf_ = {"LightCull_zdist"};
/** Key buffer containing only visible lights indices. Used for sorting. */
LightCullingKeyBuf culling_key_buf_ = {"LightCull_key"};
/** Zbins containing min and max light index for each Z bin. */
LightCullingZbinBuf culling_zbin_buf_ = {"LightCull_zbin"};
/** Bitmap of lights touching each tiles. */
LightCullingTileBuf culling_tile_buf_ = {"LightCull_tile"};
/** Culling compute passes. */
PassSimple culling_ps_ = {"LightCulling"};
/** Total number of words the tile buffer needs to contain for the render resolution. */
uint total_word_count_ = 0;
/** Flipped state of the view being processed. True for planar probe views. */
bool view_is_flipped_ = false;
/** Update light on the GPU after culling. Ran for each sample. */
PassSimple update_ps_ = {"LightUpdate"};
/** Debug Culling visualization. */
PassSimple debug_draw_ps_ = {"LightCulling.Debug"};
public:
LightModule(Instance &inst) : inst_(inst){};
~LightModule();
void begin_sync();
void sync_light(const Object *ob, ObjectHandle &handle);
void end_sync();
/**
* Update acceleration structure for the given view.
*/
void set_view(View &view, const int2 extent);
void debug_draw(View &view, GPUFrameBuffer *view_fb);
template<typename PassType> void bind_resources(PassType &pass)
{
pass.bind_ssbo(LIGHT_CULL_BUF_SLOT, &culling_data_buf_);
pass.bind_ssbo(LIGHT_BUF_SLOT, &culling_light_buf_);
pass.bind_ssbo(LIGHT_ZBIN_BUF_SLOT, &culling_zbin_buf_);
pass.bind_ssbo(LIGHT_TILE_BUF_SLOT, &culling_tile_buf_);
}
private:
void culling_pass_sync();
void update_pass_sync();
void debug_pass_sync();
};
/** \} */
} // namespace blender::eevee