WIP: eevee-next-world-irradiance #108304

Closed
Jeroen Bakker wants to merge 79 commits from Jeroen-Bakker:eevee-next-world-irradiance into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
14 changed files with 458 additions and 74 deletions
Showing only changes of commit 38f6de30cf - Show all commits

View File

@ -85,8 +85,7 @@ static void eevee_engine_init(void *vedata)
}
}
ved->instance->init(
size, &rect, nullptr, depsgraph, nullptr, camera, nullptr, default_view, v3d, rv3d);
ved->instance->init(size, &rect, nullptr, depsgraph, camera, nullptr, default_view, v3d, rv3d);
}
static void eevee_draw_scene(void *vedata)
@ -161,7 +160,7 @@ static void eevee_render_to_image(void *vedata,
rcti 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);
EEVEE_Data *ved = static_cast<EEVEE_Data *>(vedata);

View File

@ -19,7 +19,9 @@
#include "DNA_modifier_types.h"
#include "RE_pipeline.h"
#include "eevee_engine.h"
#include "eevee_instance.hh"
#include "eevee_lightcache.h"
namespace blender::eevee {
@ -37,14 +39,12 @@ void Instance::init(const int2 &output_res,
const rcti *output_rect,
RenderEngine *render_,
Depsgraph *depsgraph_,
const LightProbe *light_probe_,
Object *camera_object_,
const RenderLayer *render_layer_,
const DRWView *drw_view_,
const View3D *v3d_,
const RegionView3D *rv3d_)
{
UNUSED_VARS(light_probe_);
render = render_;
depsgraph = depsgraph_;
camera_orig_object = camera_object_;
@ -73,6 +73,36 @@ void Instance::init(const int2 &output_res,
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)
{
BLI_assert(render);
@ -255,8 +285,6 @@ void Instance::render_sample()
main_view.render();
irradiance_cache.create_surfels();
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
* \{ */
@ -426,6 +498,69 @@ void Instance::update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view
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

View File

@ -73,6 +73,7 @@ class Instance {
/** Evaluated IDs. */
Scene *scene;
ViewLayer *view_layer;
/** Camera object if rendering through a camera. nullptr otherwise. */
Object *camera_eval_object;
Object *camera_orig_object;
/** Only available when rendering for final render. */
@ -85,6 +86,8 @@ class Instance {
/** True if the grease pencil engine might be running. */
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. */
std::string info = "";
@ -114,11 +117,12 @@ class Instance {
irradiance_cache(*this){};
~Instance(){};
/* Render & Viewport. */
/* TODO(fclem): Split for clarity. */
void init(const int2 &output_res,
const rcti *output_rect,
RenderEngine *render,
Depsgraph *depsgraph,
const LightProbe *light_probe_ = nullptr,
Object *camera_object = nullptr,
const RenderLayer *render_layer = nullptr,
const DRWView *drw_view = nullptr,
@ -129,17 +133,33 @@ class Instance {
void object_sync(Object *ob);
void end_sync();
/* Render. */
void render_sync();
void render_frame(RenderLayer *render_layer, const char *view_name);
void store_metadata(RenderResult *render_result);
/* Viewport. */
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);
bool is_viewport() const
{
return render == nullptr;
return render == nullptr && !is_baking();
}
bool is_baking() const
{
return is_light_bake;
}
bool overlays_enabled() const
@ -176,6 +196,13 @@ class Instance {
void scene_sync();
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 set_time(float time);

View File

@ -1,18 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "DNA_lightprobe_types.h"
#include "GPU_capabilities.h"
#include "eevee_instance.hh"
#include "eevee_irradiance_cache.hh"
namespace blender::eevee {
/* -------------------------------------------------------------------- */
/** \name Interface
* \{ */
void IrradianceCache::init()
{
}
void IrradianceCache::sync()
{
debug_pass_sync();
if (inst_.is_baking()) {
bake.sync();
}
else {
debug_pass_sync();
}
}
void IrradianceCache::debug_pass_sync()
@ -22,13 +34,32 @@ void IrradianceCache::debug_pass_sync()
eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_IRRADIANCE)) {
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_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
DRW_STATE_DEPTH_LESS_EQUAL);
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("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);
}
@ -50,7 +81,17 @@ void IrradianceCache::debug_draw(View &view, GPUFrameBuffer *view_fb)
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
@ -60,7 +101,7 @@ void IrradianceCache::create_surfels()
using namespace blender::math;
/* 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
* make any difference. The bottleneck is still the light propagation loop. */
@ -89,17 +130,15 @@ void IrradianceCache::create_surfels()
DRW_stats_group_end();
/* Allocate surfel pool. */
GPU_memory_barrier(GPU_BARRIER_BUFFER_UPDATE);
capture_info_buf_.read();
if (capture_info_buf_.surfel_len == 0) {
/* Not surfel to allocated. */
return;
}
/* 1000000 for testing. */
if (capture_info_buf_.surfel_len * sizeof(Surfel) > 1000000) {
/* TODO(fclem): Display error message. */
/* Not enough GPU memory to fit all needed surfels. */
return;
}
/* TODO(fclem): Check for GL limit and abort if the surfel cache doesn't fit the GPU memory. */
std::cout << "Resize " << capture_info_buf_.surfel_len << std::endl;
surfels_buf_.resize(capture_info_buf_.surfel_len);
DRW_stats_group_start("IrradianceBake.SurfelsCreate");
@ -114,17 +153,37 @@ void IrradianceCache::create_surfels()
render_axis(Axis::Z);
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. */
/* 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

View File

@ -6,6 +6,9 @@
#pragma once
#include "DNA_lightprobe_types.h"
#include "eevee_lightprobe.hh"
#include "eevee_shader_shared.hh"
namespace blender::eevee {
@ -13,32 +16,63 @@ namespace blender::eevee {
class Instance;
class CapturePipeline;
class IrradianceCache {
/**
* Baking related pass and data. Not used at runtime.
*/
class IrradianceBake {
friend CapturePipeline;
private:
Instance &inst_;
/** Light cache being baked. */
LightCache *light_cache_ = nullptr;
/** Surface elements that represent the scene. */
SurfelBuf surfels_buf_;
/** Capture state. */
CaptureInfoBuf capture_info_buf_;
PassSimple debug_surfels_ps_ = {"IrradianceCache.Debug"};
/** Framebuffer. */
Framebuffer empty_raster_fb_ = {"empty_raster_fb_"};
View view_ = {"ortho_raster_view"};
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(){};
void init();
void sync();
void create_surfels();
void propagate_light();
void debug_pass_sync();
void debug_draw(View &view, GPUFrameBuffer *view_fb);
};

View File

@ -28,6 +28,7 @@
#include "wm_window.h"
#include "eevee_engine.h"
#include "eevee_instance.hh"
#include "eevee_lightcache.h"
@ -57,6 +58,11 @@ class LightBake {
/** Baking instance. Created and freed in the worker thread. */
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:
LightBake(struct Main *bmain,
@ -93,18 +99,14 @@ class LightBake {
{
BLI_assert(BLI_thread_is_main());
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) {
LightCache *light_cache = EEVEE_NEXT_lightcache_create();
LightCacheIrradianceGrid *grids = (LightCacheIrradianceGrid *)MEM_callocN(
1 * sizeof(LightCacheIrradianceGrid), "LightCacheIrradianceGrid");
grids[0].resolution[0] = 1;
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;
if (scene_light_cache != light_cache_) {
if (scene_light_cache != nullptr) {
/* Delete old data if existing. */
EEVEE_NEXT_lightcache_free(scene_light_cache);
}
scene_light_cache = light_cache_;
}
EEVEE_NEXT_lightcache_info_update(&original_scene->eevee);
@ -120,14 +122,19 @@ class LightBake {
DEG_graph_relations_update(depsgraph_);
DEG_evaluate_on_framechange(depsgraph_, frame_);
PIL_sleep_ms(1000);
context_enable();
manager_ = new draw::Manager();
instance_ = new eevee::Instance();
instance_->init_light_bake(depsgraph_, manager_);
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();
}
@ -190,8 +197,9 @@ class LightBake {
/* Bind context without GPU_render_begin(). */
context_enable(false);
/* Free instance and its resources (Textures, Framebuffers, etc...). */
/* Free GPU data (Textures, Framebuffers, etc...). */
delete instance_;
delete manager_;
/* Delete / unbind the GL & GPU context. Assumes it is currently bound. */
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->grid_data);
}
MEM_SAFE_FREE(light_cache->grids);
else {
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);
}
@ -386,13 +401,76 @@ void EEVEE_NEXT_lightcache_info_update(SceneEEVEE *eevee)
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(
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)
{
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);
}
}
}
/** \} */

View File

@ -21,6 +21,9 @@ void LightProbeModule::begin_sync()
(inst_.scene->eevee.flag & SCE_EEVEE_GI_AUTOBAKE) != 0;
grid_update_ = false;
cube_update_ = false;
grids.clear();
cubes.clear();
}
void LightProbeModule::sync_grid(ObjectHandle &handle)
@ -31,6 +34,10 @@ void LightProbeModule::sync_grid(ObjectHandle &handle)
grid.initialized = true;
grid_update_ = true;
}
if (inst_.is_baking()) {
grids.append({});
}
}
void LightProbeModule::sync_cube(ObjectHandle &handle)
@ -41,6 +48,10 @@ void LightProbeModule::sync_cube(ObjectHandle &handle)
cube.initialized = true;
cube_update_ = true;
}
if (inst_.is_baking()) {
cubes.append({});
}
}
void LightProbeModule::sync_probe(const Object *ob, ObjectHandle &handle)

View File

@ -17,12 +17,24 @@ namespace blender::eevee {
class Instance;
struct IrradianceGrid {
float4x4 transform;
int3 resolution;
};
struct ReflectionCube {};
struct LightProbe {
bool used = false;
bool initialized = false;
};
class LightProbeModule {
public:
/** Synced probe data. Only valid if the `eevee::Instance` is a baking instance. */
Vector<IrradianceGrid> grids;
Vector<ReflectionCube> cubes;
private:
Instance &inst_;

View File

@ -239,14 +239,20 @@ Material &MaterialModule::material_sync(Object *ob,
Material &mat = material_map_.lookup_or_add_cb(material_key, [&]() {
Material mat;
/* 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);
if (true) {
/* TODO(fclem): This can be expensive since it can trigger a shader compilation. So better
* avoid this if we can. */
if (inst_.is_baking()) {
mat.prepass = MaterialPass();
/* TODO(fclem): Still need the shading pass for correct attribute extraction. Would be better
* to avoid this shader compilation in another context. */
mat.shading = material_pass_get(ob, blender_mat, surface_pipe, 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) {
mat.shadow = MaterialPass();
}

View File

@ -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. */
/* WORKAROUND: Avoid rasterizer discard, but the shaders actually use no fragment output. */
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(CAPTURE_BUF_SLOT, &inst_.irradiance_cache.capture_info_buf_);
surface_ps_.bind_ssbo(SURFEL_BUF_SLOT, &inst_.irradiance_cache.bake.surfels_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);
/* TODO(fclem): Remove. There should be no view dependent behavior during capture. */

View File

@ -21,7 +21,13 @@ namespace blender::eevee {
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) {
BLI_assert(inst_.is_viewport());

View File

@ -838,6 +838,11 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
struct Depsgraph *depsgraph,
void (*callback)(void *vedata, 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.

View File

@ -2094,10 +2094,7 @@ void DRW_render_object_iter(
drw_task_graph_deinit();
}
void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
struct Depsgraph *depsgraph,
void (*callback)(void *vedata, void *user_data),
void *user_data)
void DRW_custom_pipeline_begin(DrawEngineType *draw_engine_type, struct Depsgraph *depsgraph)
{
Scene *scene = DEG_get_evaluated_scene(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_smoke_init(DST.vmempool);
ViewportEngineData *data = DRW_view_data_engine_data_get_ensure(DST.view_data_active,
draw_engine_type);
DRW_view_data_engine_data_get_ensure(DST.view_data_active, draw_engine_type);
}
/* Execute the callback */
callback(data, user_data);
void DRW_custom_pipeline_end()
{
DST.buffer_finish_called = false;
DRW_smoke_exit(DST.vmempool);
@ -2147,6 +2144,21 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
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)
{
DRW_smoke_exit(DST.vmempool);

View File

@ -150,11 +150,11 @@ typedef struct LightCacheIrradianceGrid {
/** Number of surfels in the cache. */
int surfels_len;
/** 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. */
// LightCacheTexture *irradiance_L0_L1_a;
// LightCacheTexture *irradiance_L0_L1_b;
// LightCacheTexture *irradiance_L0_L1_c;
LightCacheTexture irradiance_L0_L1_a;
LightCacheTexture irradiance_L0_L1_b;
LightCacheTexture irradiance_L0_L1_c;
} LightCacheIrradianceGrid;
typedef struct LightCache {