WIP: eevee-next-world-irradiance #108304
|
@ -85,8 +85,7 @@ static void eevee_engine_init(void *vedata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ved->instance->init(
|
ved->instance->init(size, &rect, nullptr, depsgraph, camera, nullptr, default_view, v3d, rv3d);
|
||||||
size, &rect, nullptr, depsgraph, nullptr, camera, nullptr, default_view, v3d, rv3d);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void eevee_draw_scene(void *vedata)
|
static void eevee_draw_scene(void *vedata)
|
||||||
|
@ -161,7 +160,7 @@ static void eevee_render_to_image(void *vedata,
|
||||||
rcti rect;
|
rcti rect;
|
||||||
RE_GetViewPlane(render, &view_rect, &rect);
|
RE_GetViewPlane(render, &view_rect, &rect);
|
||||||
|
|
||||||
instance->init(size, &rect, engine, depsgraph, nullptr, camera_original_ob, layer);
|
instance->init(size, &rect, engine, depsgraph, camera_original_ob, layer);
|
||||||
instance->render_frame(layer, viewname);
|
instance->render_frame(layer, viewname);
|
||||||
|
|
||||||
EEVEE_Data *ved = static_cast<EEVEE_Data *>(vedata);
|
EEVEE_Data *ved = static_cast<EEVEE_Data *>(vedata);
|
||||||
|
|
|
@ -19,7 +19,9 @@
|
||||||
#include "DNA_modifier_types.h"
|
#include "DNA_modifier_types.h"
|
||||||
#include "RE_pipeline.h"
|
#include "RE_pipeline.h"
|
||||||
|
|
||||||
|
#include "eevee_engine.h"
|
||||||
#include "eevee_instance.hh"
|
#include "eevee_instance.hh"
|
||||||
|
#include "eevee_lightcache.h"
|
||||||
|
|
||||||
namespace blender::eevee {
|
namespace blender::eevee {
|
||||||
|
|
||||||
|
@ -37,14 +39,12 @@ void Instance::init(const int2 &output_res,
|
||||||
const rcti *output_rect,
|
const rcti *output_rect,
|
||||||
RenderEngine *render_,
|
RenderEngine *render_,
|
||||||
Depsgraph *depsgraph_,
|
Depsgraph *depsgraph_,
|
||||||
const LightProbe *light_probe_,
|
|
||||||
Object *camera_object_,
|
Object *camera_object_,
|
||||||
const RenderLayer *render_layer_,
|
const RenderLayer *render_layer_,
|
||||||
const DRWView *drw_view_,
|
const DRWView *drw_view_,
|
||||||
const View3D *v3d_,
|
const View3D *v3d_,
|
||||||
const RegionView3D *rv3d_)
|
const RegionView3D *rv3d_)
|
||||||
{
|
{
|
||||||
UNUSED_VARS(light_probe_);
|
|
||||||
render = render_;
|
render = render_;
|
||||||
depsgraph = depsgraph_;
|
depsgraph = depsgraph_;
|
||||||
camera_orig_object = camera_object_;
|
camera_orig_object = camera_object_;
|
||||||
|
@ -73,6 +73,36 @@ void Instance::init(const int2 &output_res,
|
||||||
irradiance_cache.init();
|
irradiance_cache.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Instance::init_light_bake(Depsgraph *depsgraph, draw::Manager *manager)
|
||||||
|
{
|
||||||
|
this->depsgraph = depsgraph;
|
||||||
|
this->manager = manager;
|
||||||
|
camera_orig_object = nullptr;
|
||||||
|
render = nullptr;
|
||||||
|
render_layer = nullptr;
|
||||||
|
drw_view = nullptr;
|
||||||
|
v3d = nullptr;
|
||||||
|
rv3d = nullptr;
|
||||||
|
|
||||||
|
is_light_bake = true;
|
||||||
|
debug_mode = (eDebugMode)G.debug_value;
|
||||||
|
info = "";
|
||||||
|
|
||||||
|
update_eval_members();
|
||||||
|
|
||||||
|
sampling.init(scene);
|
||||||
|
camera.init();
|
||||||
|
/* Film isn't used but init to avoid side effects in other module. */
|
||||||
|
rcti empty_rect{0, 0, 0, 0};
|
||||||
|
film.init(int2(1), &empty_rect);
|
||||||
|
velocity.init();
|
||||||
|
depth_of_field.init();
|
||||||
|
shadows.init();
|
||||||
|
motion_blur.init();
|
||||||
|
main_view.init();
|
||||||
|
irradiance_cache.init();
|
||||||
|
}
|
||||||
|
|
||||||
void Instance::set_time(float time)
|
void Instance::set_time(float time)
|
||||||
{
|
{
|
||||||
BLI_assert(render);
|
BLI_assert(render);
|
||||||
|
@ -255,8 +285,6 @@ void Instance::render_sample()
|
||||||
|
|
||||||
main_view.render();
|
main_view.render();
|
||||||
|
|
||||||
irradiance_cache.create_surfels();
|
|
||||||
|
|
||||||
motion_blur.step();
|
motion_blur.step();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,6 +334,50 @@ void Instance::render_read_result(RenderLayer *render_layer, const char *view_na
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Light Bake
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
LightCache *Instance::light_cache_create(Vector<IrradianceGrid> grids,
|
||||||
|
Vector<ReflectionCube> cubes)
|
||||||
|
{
|
||||||
|
LightCache *light_cache = EEVEE_NEXT_lightcache_create();
|
||||||
|
light_cache->flag = LIGHTCACHE_BAKING;
|
||||||
|
|
||||||
|
light_cache->grid_len = grids.size();
|
||||||
|
light_cache->grids = MEM_cnew_array<LightCacheIrradianceGrid>(grids.size(),
|
||||||
|
"LightCacheIrradianceGrid");
|
||||||
|
|
||||||
|
for (const auto i : grids.index_range()) {
|
||||||
|
const IrradianceGrid &grid = grids[i];
|
||||||
|
size_t sample_count = grid.resolution.x * grid.resolution.y * grid.resolution.z;
|
||||||
|
size_t grid_texture_sample_size = sizeof(uint16_t) * 4;
|
||||||
|
if (sample_count * grid_texture_sample_size > INT_MAX) {
|
||||||
|
/* The size of the texture doesn't fit on a 32bit system. */
|
||||||
|
light_cache->flag |= LIGHTCACHE_INVALID;
|
||||||
|
info = "Scene contains an irradiance grid with too many samples points";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
LightCacheIrradianceGrid &irradiance_grid = light_cache->grids[i];
|
||||||
|
copy_m4_m4(irradiance_grid.world_to_grid, grid.transform.ptr());
|
||||||
|
irradiance_grid.resolution[0] = grid.resolution.x;
|
||||||
|
irradiance_grid.resolution[1] = grid.resolution.y;
|
||||||
|
irradiance_grid.resolution[2] = grid.resolution.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
light_cache->cube_len = cubes.size();
|
||||||
|
// light_cache->cubes = MEM_cnew_array<LightCacheIrradianceGrid>(cubes.size(),
|
||||||
|
// "LightCacheIrradianceGrid");
|
||||||
|
|
||||||
|
// for (const auto i : cubes.index_range()) {
|
||||||
|
/* TODO */
|
||||||
|
// }
|
||||||
|
|
||||||
|
return light_cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/** \name Interface
|
/** \name Interface
|
||||||
* \{ */
|
* \{ */
|
||||||
|
@ -426,6 +498,69 @@ void Instance::update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view
|
||||||
EEVEE_RENDER_PASS_CRYPTOMATTE_MATERIAL);
|
EEVEE_RENDER_PASS_CRYPTOMATTE_MATERIAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Instance::light_bake_irradiance(LightCache *&r_light_cache,
|
||||||
|
std::function<void()> context_enable,
|
||||||
|
std::function<void()> context_disable)
|
||||||
|
{
|
||||||
|
BLI_assert(is_baking());
|
||||||
|
BLI_assert(r_light_cache == nullptr);
|
||||||
|
|
||||||
|
auto custom_pipeline_wrapper = [&](std::function<void()> callback) {
|
||||||
|
context_enable();
|
||||||
|
DRW_custom_pipeline_begin(&draw_engine_eevee_next_type, depsgraph);
|
||||||
|
callback();
|
||||||
|
DRW_custom_pipeline_end();
|
||||||
|
context_disable();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto context_wrapper = [&](std::function<void()> callback) {
|
||||||
|
context_enable();
|
||||||
|
callback();
|
||||||
|
context_disable();
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Count probes. */
|
||||||
|
custom_pipeline_wrapper([&]() { render_sync(); });
|
||||||
|
/* Allocate CPU storage. */
|
||||||
|
r_light_cache = this->light_cache_create(light_probes.grids, light_probes.cubes);
|
||||||
|
|
||||||
|
if (r_light_cache->flag & LIGHTCACHE_INVALID) {
|
||||||
|
/* Something happened and the light cache couldn't be created. */
|
||||||
|
// stop = true;
|
||||||
|
// do_update = true;
|
||||||
|
r_light_cache->flag &= ~LIGHTCACHE_BAKING;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO(fclem): Multiple bounce. We need to use the previous bounce result. */
|
||||||
|
for (int bounce = 0; bounce < 1; bounce++) {
|
||||||
|
for (auto i : light_probes.grids.index_range()) {
|
||||||
|
custom_pipeline_wrapper([&]() {
|
||||||
|
/* TODO: lightprobe visibility group option. */
|
||||||
|
render_sync();
|
||||||
|
irradiance_cache.bake.surfels_create(light_probes.grids[i]);
|
||||||
|
irradiance_cache.bake.surfels_lights_eval();
|
||||||
|
});
|
||||||
|
|
||||||
|
sampling.reset();
|
||||||
|
while (!sampling.finished()) {
|
||||||
|
context_wrapper([&]() {
|
||||||
|
/* Batch ray cast by pack of 16 to avoid too much overhead of
|
||||||
|
* the update function & context switch. */
|
||||||
|
for (int i = 0; i < 16 && !sampling.finished(); i++) {
|
||||||
|
sampling.step();
|
||||||
|
irradiance_cache.bake.propagate_light_sample();
|
||||||
|
}
|
||||||
|
irradiance_cache.bake.read_result(r_light_cache->grids[i]);
|
||||||
|
});
|
||||||
|
// do_update = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r_light_cache->flag &= ~LIGHTCACHE_BAKING;
|
||||||
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
} // namespace blender::eevee
|
} // namespace blender::eevee
|
||||||
|
|
|
@ -73,6 +73,7 @@ class Instance {
|
||||||
/** Evaluated IDs. */
|
/** Evaluated IDs. */
|
||||||
Scene *scene;
|
Scene *scene;
|
||||||
ViewLayer *view_layer;
|
ViewLayer *view_layer;
|
||||||
|
/** Camera object if rendering through a camera. nullptr otherwise. */
|
||||||
Object *camera_eval_object;
|
Object *camera_eval_object;
|
||||||
Object *camera_orig_object;
|
Object *camera_orig_object;
|
||||||
/** Only available when rendering for final render. */
|
/** Only available when rendering for final render. */
|
||||||
|
@ -85,6 +86,8 @@ class Instance {
|
||||||
|
|
||||||
/** True if the grease pencil engine might be running. */
|
/** True if the grease pencil engine might be running. */
|
||||||
bool gpencil_engine_enabled;
|
bool gpencil_engine_enabled;
|
||||||
|
/** True if the instance is created for light baking. */
|
||||||
|
bool is_light_bake = false;
|
||||||
|
|
||||||
/** Info string displayed at the top of the render / viewport. */
|
/** Info string displayed at the top of the render / viewport. */
|
||||||
std::string info = "";
|
std::string info = "";
|
||||||
|
@ -114,11 +117,12 @@ class Instance {
|
||||||
irradiance_cache(*this){};
|
irradiance_cache(*this){};
|
||||||
~Instance(){};
|
~Instance(){};
|
||||||
|
|
||||||
|
/* Render & Viewport. */
|
||||||
|
/* TODO(fclem): Split for clarity. */
|
||||||
void init(const int2 &output_res,
|
void init(const int2 &output_res,
|
||||||
const rcti *output_rect,
|
const rcti *output_rect,
|
||||||
RenderEngine *render,
|
RenderEngine *render,
|
||||||
Depsgraph *depsgraph,
|
Depsgraph *depsgraph,
|
||||||
const LightProbe *light_probe_ = nullptr,
|
|
||||||
Object *camera_object = nullptr,
|
Object *camera_object = nullptr,
|
||||||
const RenderLayer *render_layer = nullptr,
|
const RenderLayer *render_layer = nullptr,
|
||||||
const DRWView *drw_view = nullptr,
|
const DRWView *drw_view = nullptr,
|
||||||
|
@ -129,17 +133,33 @@ class Instance {
|
||||||
void object_sync(Object *ob);
|
void object_sync(Object *ob);
|
||||||
void end_sync();
|
void end_sync();
|
||||||
|
|
||||||
|
/* Render. */
|
||||||
|
|
||||||
void render_sync();
|
void render_sync();
|
||||||
void render_frame(RenderLayer *render_layer, const char *view_name);
|
void render_frame(RenderLayer *render_layer, const char *view_name);
|
||||||
void store_metadata(RenderResult *render_result);
|
void store_metadata(RenderResult *render_result);
|
||||||
|
|
||||||
|
/* Viewport. */
|
||||||
|
|
||||||
void draw_viewport(DefaultFramebufferList *dfbl);
|
void draw_viewport(DefaultFramebufferList *dfbl);
|
||||||
|
|
||||||
|
/* Light bake. */
|
||||||
|
|
||||||
|
void init_light_bake(Depsgraph *depsgraph, draw::Manager *manager);
|
||||||
|
void light_bake_irradiance(LightCache *&r_light_cache,
|
||||||
|
std::function<void()> context_enable,
|
||||||
|
std::function<void()> context_disable);
|
||||||
|
|
||||||
static void update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer);
|
static void update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer);
|
||||||
|
|
||||||
bool is_viewport() const
|
bool is_viewport() const
|
||||||
{
|
{
|
||||||
return render == nullptr;
|
return render == nullptr && !is_baking();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_baking() const
|
||||||
|
{
|
||||||
|
return is_light_bake;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool overlays_enabled() const
|
bool overlays_enabled() const
|
||||||
|
@ -176,6 +196,13 @@ class Instance {
|
||||||
void scene_sync();
|
void scene_sync();
|
||||||
void mesh_sync(Object *ob, ObjectHandle &ob_handle);
|
void mesh_sync(Object *ob, ObjectHandle &ob_handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a light cache big enough to fit all light-probes inside.
|
||||||
|
* IMPORTANT: Can return nullptr on failure, in which case, the `Instance::info` will be set
|
||||||
|
* to an error message.
|
||||||
|
*/
|
||||||
|
LightCache *light_cache_create(Vector<IrradianceGrid> grids, Vector<ReflectionCube> cubes);
|
||||||
|
|
||||||
void update_eval_members();
|
void update_eval_members();
|
||||||
|
|
||||||
void set_time(float time);
|
void set_time(float time);
|
||||||
|
|
|
@ -1,18 +1,30 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
#include "DNA_lightprobe_types.h"
|
||||||
|
#include "GPU_capabilities.h"
|
||||||
|
|
||||||
#include "eevee_instance.hh"
|
#include "eevee_instance.hh"
|
||||||
|
|
||||||
#include "eevee_irradiance_cache.hh"
|
#include "eevee_irradiance_cache.hh"
|
||||||
|
|
||||||
namespace blender::eevee {
|
namespace blender::eevee {
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Interface
|
||||||
|
* \{ */
|
||||||
|
|
||||||
void IrradianceCache::init()
|
void IrradianceCache::init()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrradianceCache::sync()
|
void IrradianceCache::sync()
|
||||||
{
|
{
|
||||||
debug_pass_sync();
|
if (inst_.is_baking()) {
|
||||||
|
bake.sync();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
debug_pass_sync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrradianceCache::debug_pass_sync()
|
void IrradianceCache::debug_pass_sync()
|
||||||
|
@ -22,13 +34,32 @@ void IrradianceCache::debug_pass_sync()
|
||||||
eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_IRRADIANCE)) {
|
eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_IRRADIANCE)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LightCache *light_cache = inst_.scene->eevee.light_cache_data;
|
||||||
|
if (light_cache == nullptr || light_cache->version != LIGHTCACHE_NEXT_STATIC_VERSION ||
|
||||||
|
light_cache->grids == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
debug_surfels_ps_.init();
|
debug_surfels_ps_.init();
|
||||||
debug_surfels_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
|
debug_surfels_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
|
||||||
DRW_STATE_DEPTH_LESS_EQUAL);
|
DRW_STATE_DEPTH_LESS_EQUAL);
|
||||||
debug_surfels_ps_.shader_set(inst_.shaders.static_shader_get(DEBUG_SURFELS));
|
debug_surfels_ps_.shader_set(inst_.shaders.static_shader_get(DEBUG_SURFELS));
|
||||||
debug_surfels_ps_.bind_ssbo("surfels_buf", surfels_buf_);
|
|
||||||
debug_surfels_ps_.push_constant("surfel_radius", 0.5f / 4.0f);
|
debug_surfels_ps_.push_constant("surfel_radius", 0.5f / 4.0f);
|
||||||
debug_surfels_ps_.push_constant("debug_mode", static_cast<int>(inst_.debug_mode));
|
debug_surfels_ps_.push_constant("debug_mode", static_cast<int>(inst_.debug_mode));
|
||||||
|
|
||||||
|
surfels_buf_.clear();
|
||||||
|
for (auto i : IndexRange(light_cache->grid_len)) {
|
||||||
|
LightCacheIrradianceGrid &grid = light_cache->grids[i];
|
||||||
|
if (grid.surfels_len > 0 && grid.surfels != nullptr) {
|
||||||
|
Span<Surfel> grid_surfels(static_cast<Surfel *>(grid.surfels), grid.surfels_len);
|
||||||
|
for (const Surfel &surfel : grid_surfels) {
|
||||||
|
surfels_buf_.append(surfel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
surfels_buf_.push_update();
|
||||||
|
debug_surfels_ps_.bind_ssbo("surfels_buf", surfels_buf_);
|
||||||
debug_surfels_ps_.draw_procedural(GPU_PRIM_TRI_STRIP, surfels_buf_.size(), 4);
|
debug_surfels_ps_.draw_procedural(GPU_PRIM_TRI_STRIP, surfels_buf_.size(), 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +81,17 @@ void IrradianceCache::debug_draw(View &view, GPUFrameBuffer *view_fb)
|
||||||
inst_.manager->submit(debug_surfels_ps_, view);
|
inst_.manager->submit(debug_surfels_ps_, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrradianceCache::create_surfels()
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Baking
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
void IrradianceBake::sync()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void IrradianceBake::surfels_create(const IrradianceGrid & /* grid */)
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* We rasterize the scene along the 3 axes. Each generated fragment will write a surface element
|
* We rasterize the scene along the 3 axes. Each generated fragment will write a surface element
|
||||||
|
@ -60,7 +101,7 @@ void IrradianceCache::create_surfels()
|
||||||
using namespace blender::math;
|
using namespace blender::math;
|
||||||
|
|
||||||
/* Attachment-less frame-buffer. */
|
/* Attachment-less frame-buffer. */
|
||||||
empty_raster_fb_.ensure(int2(40 * 4));
|
empty_raster_fb_.ensure(int2(10 * 4));
|
||||||
|
|
||||||
/** We could use multi-view rendering here to avoid multiple submissions but it is unlikely to
|
/** We could use multi-view rendering here to avoid multiple submissions but it is unlikely to
|
||||||
* make any difference. The bottleneck is still the light propagation loop. */
|
* make any difference. The bottleneck is still the light propagation loop. */
|
||||||
|
@ -89,17 +130,15 @@ void IrradianceCache::create_surfels()
|
||||||
DRW_stats_group_end();
|
DRW_stats_group_end();
|
||||||
|
|
||||||
/* Allocate surfel pool. */
|
/* Allocate surfel pool. */
|
||||||
|
GPU_memory_barrier(GPU_BARRIER_BUFFER_UPDATE);
|
||||||
capture_info_buf_.read();
|
capture_info_buf_.read();
|
||||||
if (capture_info_buf_.surfel_len == 0) {
|
if (capture_info_buf_.surfel_len == 0) {
|
||||||
/* Not surfel to allocated. */
|
/* Not surfel to allocated. */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* 1000000 for testing. */
|
|
||||||
if (capture_info_buf_.surfel_len * sizeof(Surfel) > 1000000) {
|
/* TODO(fclem): Check for GL limit and abort if the surfel cache doesn't fit the GPU memory. */
|
||||||
/* TODO(fclem): Display error message. */
|
std::cout << "Resize " << capture_info_buf_.surfel_len << std::endl;
|
||||||
/* Not enough GPU memory to fit all needed surfels. */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
surfels_buf_.resize(capture_info_buf_.surfel_len);
|
surfels_buf_.resize(capture_info_buf_.surfel_len);
|
||||||
|
|
||||||
DRW_stats_group_start("IrradianceBake.SurfelsCreate");
|
DRW_stats_group_start("IrradianceBake.SurfelsCreate");
|
||||||
|
@ -114,17 +153,37 @@ void IrradianceCache::create_surfels()
|
||||||
render_axis(Axis::Z);
|
render_axis(Axis::Z);
|
||||||
|
|
||||||
DRW_stats_group_end();
|
DRW_stats_group_end();
|
||||||
|
|
||||||
/* TODO(fclem): Resize at the end of the light propagation. */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrradianceCache::propagate_light()
|
void IrradianceBake::surfels_lights_eval()
|
||||||
{
|
{
|
||||||
/* Evaluate direct lighting (and also clear the surfels radiance). */
|
}
|
||||||
/* For every ray direction over the sphere. */
|
|
||||||
/* Create the surfels lists. */
|
void IrradianceBake::propagate_light_sample()
|
||||||
|
{
|
||||||
|
/* Pick random ray direction over the sphere. */
|
||||||
|
/* Project to regular grid and create the surfels lists. */
|
||||||
/* Sort the surfels lists. */
|
/* Sort the surfels lists. */
|
||||||
/* Propagate light. */
|
/* Propagate light. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IrradianceBake::read_result(LightCacheIrradianceGrid &light_cache_grid)
|
||||||
|
{
|
||||||
|
switch (inst_.debug_mode) {
|
||||||
|
case eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_NORMAL:
|
||||||
|
case eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_IRRADIANCE:
|
||||||
|
GPU_memory_barrier(GPU_BARRIER_BUFFER_UPDATE);
|
||||||
|
std::cout << "Read " << capture_info_buf_.surfel_len << std::endl;
|
||||||
|
surfels_buf_.read();
|
||||||
|
light_cache_grid.surfels_len = capture_info_buf_.surfel_len;
|
||||||
|
light_cache_grid.surfels = MEM_dupallocN(surfels_buf_.data());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Nothing to display. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
||||||
} // namespace blender::eevee
|
} // namespace blender::eevee
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "DNA_lightprobe_types.h"
|
||||||
|
|
||||||
|
#include "eevee_lightprobe.hh"
|
||||||
#include "eevee_shader_shared.hh"
|
#include "eevee_shader_shared.hh"
|
||||||
|
|
||||||
namespace blender::eevee {
|
namespace blender::eevee {
|
||||||
|
@ -13,32 +16,63 @@ namespace blender::eevee {
|
||||||
class Instance;
|
class Instance;
|
||||||
class CapturePipeline;
|
class CapturePipeline;
|
||||||
|
|
||||||
class IrradianceCache {
|
/**
|
||||||
|
* Baking related pass and data. Not used at runtime.
|
||||||
|
*/
|
||||||
|
class IrradianceBake {
|
||||||
friend CapturePipeline;
|
friend CapturePipeline;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Instance &inst_;
|
Instance &inst_;
|
||||||
|
|
||||||
|
/** Light cache being baked. */
|
||||||
|
LightCache *light_cache_ = nullptr;
|
||||||
/** Surface elements that represent the scene. */
|
/** Surface elements that represent the scene. */
|
||||||
SurfelBuf surfels_buf_;
|
SurfelBuf surfels_buf_;
|
||||||
/** Capture state. */
|
/** Capture state. */
|
||||||
CaptureInfoBuf capture_info_buf_;
|
CaptureInfoBuf capture_info_buf_;
|
||||||
|
/** Framebuffer. */
|
||||||
PassSimple debug_surfels_ps_ = {"IrradianceCache.Debug"};
|
|
||||||
|
|
||||||
Framebuffer empty_raster_fb_ = {"empty_raster_fb_"};
|
Framebuffer empty_raster_fb_ = {"empty_raster_fb_"};
|
||||||
View view_ = {"ortho_raster_view"};
|
View view_ = {"ortho_raster_view"};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IrradianceCache(Instance &inst) : inst_(inst){};
|
IrradianceBake(Instance &inst) : inst_(inst){};
|
||||||
|
|
||||||
|
void sync();
|
||||||
|
|
||||||
|
/** Create a surfel representation of the scene from the \a grid using the capture pipeline. */
|
||||||
|
void surfels_create(const IrradianceGrid &grid);
|
||||||
|
/** Evaluate direct lighting (and also clear the surfels radiance). */
|
||||||
|
void surfels_lights_eval();
|
||||||
|
/** Propagate light from surfel to surfel in a random direction over the sphere. */
|
||||||
|
void propagate_light_sample();
|
||||||
|
|
||||||
|
/** Read grid final irradiance back to CPU into \a light_cache_grid . */
|
||||||
|
void read_result(LightCacheIrradianceGrid &light_cache_grid);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runtime container of diffuse indirect lighting.
|
||||||
|
* Also have debug and baking components.
|
||||||
|
*/
|
||||||
|
class IrradianceCache {
|
||||||
|
public:
|
||||||
|
IrradianceBake bake;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Instance &inst_;
|
||||||
|
|
||||||
|
PassSimple debug_surfels_ps_ = {"IrradianceCache.Debug"};
|
||||||
|
/** Debug surfel elements copied from the light cache. */
|
||||||
|
draw::StorageVectorBuffer<Surfel> surfels_buf_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
IrradianceCache(Instance &inst) : bake(inst), inst_(inst){};
|
||||||
~IrradianceCache(){};
|
~IrradianceCache(){};
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void sync();
|
void sync();
|
||||||
|
|
||||||
void create_surfels();
|
|
||||||
void propagate_light();
|
|
||||||
|
|
||||||
void debug_pass_sync();
|
void debug_pass_sync();
|
||||||
void debug_draw(View &view, GPUFrameBuffer *view_fb);
|
void debug_draw(View &view, GPUFrameBuffer *view_fb);
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
#include "wm_window.h"
|
#include "wm_window.h"
|
||||||
|
|
||||||
|
#include "eevee_engine.h"
|
||||||
#include "eevee_instance.hh"
|
#include "eevee_instance.hh"
|
||||||
|
|
||||||
#include "eevee_lightcache.h"
|
#include "eevee_lightcache.h"
|
||||||
|
@ -57,6 +58,11 @@ class LightBake {
|
||||||
|
|
||||||
/** Baking instance. Created and freed in the worker thread. */
|
/** Baking instance. Created and freed in the worker thread. */
|
||||||
Instance *instance_ = nullptr;
|
Instance *instance_ = nullptr;
|
||||||
|
/** Light Cache being baked. Create in worker thread and pass ownership to original scene on
|
||||||
|
* first `update()` call. */
|
||||||
|
::LightCache *light_cache_ = nullptr;
|
||||||
|
/** Manager used for command submission. Created and freed in the worker thread. */
|
||||||
|
draw::Manager *manager_ = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LightBake(struct Main *bmain,
|
LightBake(struct Main *bmain,
|
||||||
|
@ -93,18 +99,14 @@ class LightBake {
|
||||||
{
|
{
|
||||||
BLI_assert(BLI_thread_is_main());
|
BLI_assert(BLI_thread_is_main());
|
||||||
Scene *original_scene = DEG_get_input_scene(depsgraph_);
|
Scene *original_scene = DEG_get_input_scene(depsgraph_);
|
||||||
|
LightCache *&scene_light_cache = original_scene->eevee.light_cache_data;
|
||||||
|
|
||||||
if (original_scene->eevee.light_cache_data == nullptr) {
|
if (scene_light_cache != light_cache_) {
|
||||||
LightCache *light_cache = EEVEE_NEXT_lightcache_create();
|
if (scene_light_cache != nullptr) {
|
||||||
|
/* Delete old data if existing. */
|
||||||
LightCacheIrradianceGrid *grids = (LightCacheIrradianceGrid *)MEM_callocN(
|
EEVEE_NEXT_lightcache_free(scene_light_cache);
|
||||||
1 * sizeof(LightCacheIrradianceGrid), "LightCacheIrradianceGrid");
|
}
|
||||||
grids[0].resolution[0] = 1;
|
scene_light_cache = light_cache_;
|
||||||
grids[0].resolution[1] = 2;
|
|
||||||
grids[0].resolution[2] = 3;
|
|
||||||
light_cache->grid_len = 1;
|
|
||||||
light_cache->grids = grids;
|
|
||||||
original_scene->eevee.light_cache_data = light_cache;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EEVEE_NEXT_lightcache_info_update(&original_scene->eevee);
|
EEVEE_NEXT_lightcache_info_update(&original_scene->eevee);
|
||||||
|
@ -120,14 +122,19 @@ class LightBake {
|
||||||
DEG_graph_relations_update(depsgraph_);
|
DEG_graph_relations_update(depsgraph_);
|
||||||
DEG_evaluate_on_framechange(depsgraph_, frame_);
|
DEG_evaluate_on_framechange(depsgraph_, frame_);
|
||||||
|
|
||||||
PIL_sleep_ms(1000);
|
|
||||||
|
|
||||||
context_enable();
|
context_enable();
|
||||||
|
manager_ = new draw::Manager();
|
||||||
instance_ = new eevee::Instance();
|
instance_ = new eevee::Instance();
|
||||||
|
instance_->init_light_bake(depsgraph_, manager_);
|
||||||
context_disable();
|
context_disable();
|
||||||
|
|
||||||
|
if (delay_ms_ > 0) {
|
||||||
|
PIL_sleep_ms(delay_ms_);
|
||||||
|
}
|
||||||
|
|
||||||
|
instance_->light_bake_irradiance(
|
||||||
|
light_cache_, [this]() { context_enable(); }, [this]() { context_disable(); });
|
||||||
|
|
||||||
delete_resources();
|
delete_resources();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,8 +197,9 @@ class LightBake {
|
||||||
/* Bind context without GPU_render_begin(). */
|
/* Bind context without GPU_render_begin(). */
|
||||||
context_enable(false);
|
context_enable(false);
|
||||||
|
|
||||||
/* Free instance and its resources (Textures, Framebuffers, etc...). */
|
/* Free GPU data (Textures, Framebuffers, etc...). */
|
||||||
delete instance_;
|
delete instance_;
|
||||||
|
delete manager_;
|
||||||
|
|
||||||
/* Delete / unbind the GL & GPU context. Assumes it is currently bound. */
|
/* Delete / unbind the GL & GPU context. Assumes it is currently bound. */
|
||||||
if (GPU_use_main_context_workaround() && !BLI_thread_is_main()) {
|
if (GPU_use_main_context_workaround() && !BLI_thread_is_main()) {
|
||||||
|
@ -323,8 +331,15 @@ void EEVEE_NEXT_lightcache_free(LightCache *light_cache)
|
||||||
MEM_SAFE_FREE(light_cache->cube_data);
|
MEM_SAFE_FREE(light_cache->cube_data);
|
||||||
MEM_SAFE_FREE(light_cache->grid_data);
|
MEM_SAFE_FREE(light_cache->grid_data);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
MEM_SAFE_FREE(light_cache->grids);
|
for (int i = 0; i < light_cache->grid_len; i++) {
|
||||||
|
MEM_SAFE_FREE(light_cache->grids[i].surfels);
|
||||||
|
MEM_SAFE_FREE(light_cache->grids[i].irradiance_L0_L1_a.data);
|
||||||
|
MEM_SAFE_FREE(light_cache->grids[i].irradiance_L0_L1_b.data);
|
||||||
|
MEM_SAFE_FREE(light_cache->grids[i].irradiance_L0_L1_c.data);
|
||||||
|
}
|
||||||
|
MEM_SAFE_FREE(light_cache->grids);
|
||||||
|
}
|
||||||
MEM_freeN(light_cache);
|
MEM_freeN(light_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,13 +401,76 @@ void EEVEE_NEXT_lightcache_info_update(SceneEEVEE *eevee)
|
||||||
|
|
||||||
void EEVEE_NEXT_lightcache_blend_write(BlendWriter *writer, LightCache *light_cache)
|
void EEVEE_NEXT_lightcache_blend_write(BlendWriter *writer, LightCache *light_cache)
|
||||||
{
|
{
|
||||||
|
auto write_lightcache_texture = [&](LightCacheTexture &tex) {
|
||||||
|
if (tex.data) {
|
||||||
|
size_t data_size = tex.components * tex.tex_size[0] * tex.tex_size[1] * tex.tex_size[2];
|
||||||
|
if (tex.data_type == LIGHTCACHETEX_FLOAT) {
|
||||||
|
data_size *= sizeof(float);
|
||||||
|
}
|
||||||
|
else if (tex.data_type == LIGHTCACHETEX_UINT) {
|
||||||
|
data_size *= sizeof(uint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: We can't save more than what 32bit systems can handle.
|
||||||
|
* The solution would be to split the texture but it is too late for 2.90. (see #78529) */
|
||||||
|
if (data_size < INT_MAX) {
|
||||||
|
BLO_write_raw(writer, data_size, tex.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
BLO_write_struct_array(
|
BLO_write_struct_array(
|
||||||
writer, LightCacheIrradianceGrid, light_cache->grid_len, light_cache->grids);
|
writer, LightCacheIrradianceGrid, light_cache->grid_len, light_cache->grids);
|
||||||
|
|
||||||
|
for (int i = 0; i < light_cache->grid_len; i++) {
|
||||||
|
LightCacheIrradianceGrid &grid = light_cache->grids[i];
|
||||||
|
/* Surfels are runtime data. Not stored in the blend file. */
|
||||||
|
write_lightcache_texture(grid.irradiance_L0_L1_a);
|
||||||
|
write_lightcache_texture(grid.irradiance_L0_L1_b);
|
||||||
|
write_lightcache_texture(grid.irradiance_L0_L1_c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EEVEE_NEXT_lightcache_blend_read_data(BlendDataReader *reader, LightCache *light_cache)
|
void EEVEE_NEXT_lightcache_blend_read_data(BlendDataReader *reader, LightCache *light_cache)
|
||||||
{
|
{
|
||||||
BLO_read_data_address(reader, &light_cache->grids);
|
|
||||||
|
if (light_cache->grids) {
|
||||||
|
BLO_read_data_address(reader, &light_cache->grids);
|
||||||
|
|
||||||
|
auto direct_link_lightcache_texture = [&](LightCacheTexture &lctex) {
|
||||||
|
/* Runtime data. Not stored in the blend file. */
|
||||||
|
lctex.tex = nullptr;
|
||||||
|
|
||||||
|
if (lctex.data) {
|
||||||
|
BLO_read_data_address(reader, &lctex.data);
|
||||||
|
if (lctex.data && BLO_read_requires_endian_switch(reader)) {
|
||||||
|
int data_size = lctex.components * lctex.tex_size[0] * lctex.tex_size[1] *
|
||||||
|
lctex.tex_size[2];
|
||||||
|
|
||||||
|
if (lctex.data_type == LIGHTCACHETEX_FLOAT) {
|
||||||
|
BLI_endian_switch_float_array((float *)lctex.data, data_size * sizeof(float));
|
||||||
|
}
|
||||||
|
else if (lctex.data_type == LIGHTCACHETEX_UINT) {
|
||||||
|
BLI_endian_switch_uint32_array((uint *)lctex.data, data_size * sizeof(uint));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lctex.data == nullptr) {
|
||||||
|
zero_v3_int(lctex.tex_size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < light_cache->grid_len; i++) {
|
||||||
|
LightCacheIrradianceGrid &grid = light_cache->grids[i];
|
||||||
|
/* Runtime data. Not stored in the blend file. */
|
||||||
|
grid.surfels_len = 0;
|
||||||
|
grid.surfels = nullptr;
|
||||||
|
direct_link_lightcache_texture(grid.irradiance_L0_L1_a);
|
||||||
|
direct_link_lightcache_texture(grid.irradiance_L0_L1_b);
|
||||||
|
direct_link_lightcache_texture(grid.irradiance_L0_L1_c);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
|
@ -21,6 +21,9 @@ void LightProbeModule::begin_sync()
|
||||||
(inst_.scene->eevee.flag & SCE_EEVEE_GI_AUTOBAKE) != 0;
|
(inst_.scene->eevee.flag & SCE_EEVEE_GI_AUTOBAKE) != 0;
|
||||||
grid_update_ = false;
|
grid_update_ = false;
|
||||||
cube_update_ = false;
|
cube_update_ = false;
|
||||||
|
|
||||||
|
grids.clear();
|
||||||
|
cubes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightProbeModule::sync_grid(ObjectHandle &handle)
|
void LightProbeModule::sync_grid(ObjectHandle &handle)
|
||||||
|
@ -31,6 +34,10 @@ void LightProbeModule::sync_grid(ObjectHandle &handle)
|
||||||
grid.initialized = true;
|
grid.initialized = true;
|
||||||
grid_update_ = true;
|
grid_update_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inst_.is_baking()) {
|
||||||
|
grids.append({});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightProbeModule::sync_cube(ObjectHandle &handle)
|
void LightProbeModule::sync_cube(ObjectHandle &handle)
|
||||||
|
@ -41,6 +48,10 @@ void LightProbeModule::sync_cube(ObjectHandle &handle)
|
||||||
cube.initialized = true;
|
cube.initialized = true;
|
||||||
cube_update_ = true;
|
cube_update_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inst_.is_baking()) {
|
||||||
|
cubes.append({});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightProbeModule::sync_probe(const Object *ob, ObjectHandle &handle)
|
void LightProbeModule::sync_probe(const Object *ob, ObjectHandle &handle)
|
||||||
|
|
|
@ -17,12 +17,24 @@ namespace blender::eevee {
|
||||||
|
|
||||||
class Instance;
|
class Instance;
|
||||||
|
|
||||||
|
struct IrradianceGrid {
|
||||||
|
float4x4 transform;
|
||||||
|
int3 resolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ReflectionCube {};
|
||||||
|
|
||||||
struct LightProbe {
|
struct LightProbe {
|
||||||
bool used = false;
|
bool used = false;
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LightProbeModule {
|
class LightProbeModule {
|
||||||
|
public:
|
||||||
|
/** Synced probe data. Only valid if the `eevee::Instance` is a baking instance. */
|
||||||
|
Vector<IrradianceGrid> grids;
|
||||||
|
Vector<ReflectionCube> cubes;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Instance &inst_;
|
Instance &inst_;
|
||||||
|
|
||||||
|
|
|
@ -239,14 +239,20 @@ Material &MaterialModule::material_sync(Object *ob,
|
||||||
|
|
||||||
Material &mat = material_map_.lookup_or_add_cb(material_key, [&]() {
|
Material &mat = material_map_.lookup_or_add_cb(material_key, [&]() {
|
||||||
Material mat;
|
Material mat;
|
||||||
/* Order is important for transparent. */
|
if (inst_.is_baking()) {
|
||||||
mat.prepass = material_pass_get(ob, blender_mat, prepass_pipe, geometry_type);
|
mat.prepass = MaterialPass();
|
||||||
mat.shading = material_pass_get(ob, blender_mat, surface_pipe, geometry_type);
|
/* TODO(fclem): Still need the shading pass for correct attribute extraction. Would be better
|
||||||
if (true) {
|
* to avoid this shader compilation in another context. */
|
||||||
/* TODO(fclem): This can be expensive since it can trigger a shader compilation. So better
|
mat.shading = material_pass_get(ob, blender_mat, surface_pipe, geometry_type);
|
||||||
* avoid this if we can. */
|
|
||||||
mat.capture = material_pass_get(ob, blender_mat, MAT_PIPE_CAPTURE, geometry_type);
|
mat.capture = material_pass_get(ob, blender_mat, MAT_PIPE_CAPTURE, geometry_type);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
/* Order is important for transparent. */
|
||||||
|
mat.prepass = material_pass_get(ob, blender_mat, prepass_pipe, geometry_type);
|
||||||
|
mat.shading = material_pass_get(ob, blender_mat, surface_pipe, geometry_type);
|
||||||
|
mat.capture = MaterialPass();
|
||||||
|
}
|
||||||
|
|
||||||
if (blender_mat->blend_shadow == MA_BS_NONE) {
|
if (blender_mat->blend_shadow == MA_BS_NONE) {
|
||||||
mat.shadow = MaterialPass();
|
mat.shadow = MaterialPass();
|
||||||
}
|
}
|
||||||
|
|
|
@ -514,10 +514,10 @@ void CapturePipeline::sync()
|
||||||
/* Surfel output is done using a SSBO, so no need for a fragment shader output color or depth. */
|
/* Surfel output is done using a SSBO, so no need for a fragment shader output color or depth. */
|
||||||
/* WORKAROUND: Avoid rasterizer discard, but the shaders actually use no fragment output. */
|
/* WORKAROUND: Avoid rasterizer discard, but the shaders actually use no fragment output. */
|
||||||
surface_ps_.state_set(DRW_STATE_WRITE_STENCIL);
|
surface_ps_.state_set(DRW_STATE_WRITE_STENCIL);
|
||||||
surface_ps_.framebuffer_set(&inst_.irradiance_cache.empty_raster_fb_);
|
surface_ps_.framebuffer_set(&inst_.irradiance_cache.bake.empty_raster_fb_);
|
||||||
|
|
||||||
surface_ps_.bind_ssbo(SURFEL_BUF_SLOT, &inst_.irradiance_cache.surfels_buf_);
|
surface_ps_.bind_ssbo(SURFEL_BUF_SLOT, &inst_.irradiance_cache.bake.surfels_buf_);
|
||||||
surface_ps_.bind_ssbo(CAPTURE_BUF_SLOT, &inst_.irradiance_cache.capture_info_buf_);
|
surface_ps_.bind_ssbo(CAPTURE_BUF_SLOT, &inst_.irradiance_cache.bake.capture_info_buf_);
|
||||||
|
|
||||||
surface_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
|
surface_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
|
||||||
/* TODO(fclem): Remove. There should be no view dependent behavior during capture. */
|
/* TODO(fclem): Remove. There should be no view dependent behavior during capture. */
|
||||||
|
|
|
@ -21,7 +21,13 @@ namespace blender::eevee {
|
||||||
|
|
||||||
void Sampling::init(const Scene *scene)
|
void Sampling::init(const Scene *scene)
|
||||||
{
|
{
|
||||||
sample_count_ = inst_.is_viewport() ? scene->eevee.taa_samples : scene->eevee.taa_render_samples;
|
if (inst_.is_baking()) {
|
||||||
|
sample_count_ = max_ii(1, scene->eevee.gi_irradiance_samples);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sample_count_ = inst_.is_viewport() ? scene->eevee.taa_samples :
|
||||||
|
scene->eevee.taa_render_samples;
|
||||||
|
}
|
||||||
|
|
||||||
if (sample_count_ == 0) {
|
if (sample_count_ == 0) {
|
||||||
BLI_assert(inst_.is_viewport());
|
BLI_assert(inst_.is_viewport());
|
||||||
|
|
|
@ -838,6 +838,11 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
|
||||||
struct Depsgraph *depsgraph,
|
struct Depsgraph *depsgraph,
|
||||||
void (*callback)(void *vedata, void *user_data),
|
void (*callback)(void *vedata, void *user_data),
|
||||||
void *user_data);
|
void *user_data);
|
||||||
|
/**
|
||||||
|
* Same as `DRW_custom_pipeline` but allow better code-flow than a callback.
|
||||||
|
*/
|
||||||
|
void DRW_custom_pipeline_begin(DrawEngineType *draw_engine_type, struct Depsgraph *depsgraph);
|
||||||
|
void DRW_custom_pipeline_end(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used when the render engine want to redo another cache populate inside the same render frame.
|
* Used when the render engine want to redo another cache populate inside the same render frame.
|
||||||
|
|
|
@ -2094,10 +2094,7 @@ void DRW_render_object_iter(
|
||||||
drw_task_graph_deinit();
|
drw_task_graph_deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
|
void DRW_custom_pipeline_begin(DrawEngineType *draw_engine_type, struct Depsgraph *depsgraph)
|
||||||
struct Depsgraph *depsgraph,
|
|
||||||
void (*callback)(void *vedata, void *user_data),
|
|
||||||
void *user_data)
|
|
||||||
{
|
{
|
||||||
Scene *scene = DEG_get_evaluated_scene(depsgraph);
|
Scene *scene = DEG_get_evaluated_scene(depsgraph);
|
||||||
ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
|
ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
|
||||||
|
@ -2124,11 +2121,11 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
|
||||||
DRW_volume_init(DST.vmempool);
|
DRW_volume_init(DST.vmempool);
|
||||||
DRW_smoke_init(DST.vmempool);
|
DRW_smoke_init(DST.vmempool);
|
||||||
|
|
||||||
ViewportEngineData *data = DRW_view_data_engine_data_get_ensure(DST.view_data_active,
|
DRW_view_data_engine_data_get_ensure(DST.view_data_active, draw_engine_type);
|
||||||
draw_engine_type);
|
}
|
||||||
|
|
||||||
/* Execute the callback */
|
void DRW_custom_pipeline_end()
|
||||||
callback(data, user_data);
|
{
|
||||||
DST.buffer_finish_called = false;
|
DST.buffer_finish_called = false;
|
||||||
|
|
||||||
DRW_smoke_exit(DST.vmempool);
|
DRW_smoke_exit(DST.vmempool);
|
||||||
|
@ -2147,6 +2144,21 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
|
||||||
drw_manager_exit(&DST);
|
drw_manager_exit(&DST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
|
||||||
|
struct Depsgraph *depsgraph,
|
||||||
|
void (*callback)(void *vedata, void *user_data),
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
DRW_custom_pipeline_begin(draw_engine_type, depsgraph);
|
||||||
|
|
||||||
|
ViewportEngineData *data = DRW_view_data_engine_data_get_ensure(DST.view_data_active,
|
||||||
|
draw_engine_type);
|
||||||
|
/* Execute the callback. */
|
||||||
|
callback(data, user_data);
|
||||||
|
|
||||||
|
DRW_custom_pipeline_end();
|
||||||
|
}
|
||||||
|
|
||||||
void DRW_cache_restart(void)
|
void DRW_cache_restart(void)
|
||||||
{
|
{
|
||||||
DRW_smoke_exit(DST.vmempool);
|
DRW_smoke_exit(DST.vmempool);
|
||||||
|
|
|
@ -150,11 +150,11 @@ typedef struct LightCacheIrradianceGrid {
|
||||||
/** Number of surfels in the cache. */
|
/** Number of surfels in the cache. */
|
||||||
int surfels_len;
|
int surfels_len;
|
||||||
/** Currently only used at runtime for debugging the baking process. Not written to file. */
|
/** Currently only used at runtime for debugging the baking process. Not written to file. */
|
||||||
// struct GPUStorageBuf *surfels;
|
void *surfels;
|
||||||
/** Irradiance Data. Stored as spherical harmonic. */
|
/** Irradiance Data. Stored as spherical harmonic. */
|
||||||
// LightCacheTexture *irradiance_L0_L1_a;
|
LightCacheTexture irradiance_L0_L1_a;
|
||||||
// LightCacheTexture *irradiance_L0_L1_b;
|
LightCacheTexture irradiance_L0_L1_b;
|
||||||
// LightCacheTexture *irradiance_L0_L1_c;
|
LightCacheTexture irradiance_L0_L1_c;
|
||||||
} LightCacheIrradianceGrid;
|
} LightCacheIrradianceGrid;
|
||||||
|
|
||||||
typedef struct LightCache {
|
typedef struct LightCache {
|
||||||
|
|
Loading…
Reference in New Issue