WIP: eevee-next-world-irradiance #108304
|
@ -428,7 +428,6 @@ set(GLSL_SRC
|
|||
engines/eevee_next/shaders/eevee_camera_lib.glsl
|
||||
engines/eevee_next/shaders/eevee_colorspace_lib.glsl
|
||||
engines/eevee_next/shaders/eevee_cryptomatte_lib.glsl
|
||||
engines/eevee_next/shaders/eevee_transparency_lib.glsl
|
||||
engines/eevee_next/shaders/eevee_debug_surfels_vert.glsl
|
||||
engines/eevee_next/shaders/eevee_debug_surfels_frag.glsl
|
||||
engines/eevee_next/shaders/eevee_deferred_light_frag.glsl
|
||||
|
@ -500,6 +499,10 @@ set(GLSL_SRC
|
|||
engines/eevee_next/shaders/eevee_surf_lib.glsl
|
||||
engines/eevee_next/shaders/eevee_surf_shadow_frag.glsl
|
||||
engines/eevee_next/shaders/eevee_surf_world_frag.glsl
|
||||
engines/eevee_next/shaders/eevee_surfel_light_comp.glsl
|
||||
engines/eevee_next/shaders/eevee_surfel_list_build_comp.glsl
|
||||
engines/eevee_next/shaders/eevee_surfel_list_sort_comp.glsl
|
||||
engines/eevee_next/shaders/eevee_transparency_lib.glsl
|
||||
engines/eevee_next/shaders/eevee_velocity_lib.glsl
|
||||
|
||||
engines/eevee_next/eevee_defines.hh
|
||||
|
|
|
@ -86,6 +86,9 @@
|
|||
#define DOF_GATHER_GROUP_SIZE DOF_TILES_SIZE
|
||||
#define DOF_RESOLVE_GROUP_SIZE (DOF_TILES_SIZE * 2)
|
||||
|
||||
/* IrradianceBake. */
|
||||
#define SURFEL_LIGHT_GROUP_SIZE 256
|
||||
|
||||
/* Resource bindings. */
|
||||
|
||||
/* Texture. */
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "DNA_lightprobe_types.h"
|
||||
|
||||
#include "GPU_capabilities.h"
|
||||
#include "GPU_debug.h"
|
||||
|
||||
#include "BLI_math_rotation.hh"
|
||||
|
||||
#include "eevee_instance.hh"
|
||||
|
||||
|
@ -19,10 +23,7 @@ void IrradianceCache::init()
|
|||
|
||||
void IrradianceCache::sync()
|
||||
{
|
||||
if (inst_.is_baking()) {
|
||||
bake.sync();
|
||||
}
|
||||
else {
|
||||
if (!inst_.is_baking()) {
|
||||
debug_pass_sync();
|
||||
}
|
||||
}
|
||||
|
@ -87,11 +88,7 @@ void IrradianceCache::debug_draw(View &view, GPUFrameBuffer *view_fb)
|
|||
/** \name Baking
|
||||
* \{ */
|
||||
|
||||
void IrradianceBake::sync()
|
||||
{
|
||||
}
|
||||
|
||||
void IrradianceBake::surfels_create(const IrradianceGrid & /* grid */)
|
||||
void IrradianceBake::surfels_create(const IrradianceGrid &grid)
|
||||
{
|
||||
/**
|
||||
* We rasterize the scene along the 3 axes. Each generated fragment will write a surface element
|
||||
|
@ -100,32 +97,47 @@ void IrradianceBake::surfels_create(const IrradianceGrid & /* grid */)
|
|||
*/
|
||||
using namespace blender::math;
|
||||
|
||||
/* Attachment-less frame-buffer. */
|
||||
empty_raster_fb_.ensure(int2(20 * 4));
|
||||
float4x4 transform(grid.transform);
|
||||
float3 location, scale;
|
||||
Quaternion rotation;
|
||||
math::to_loc_rot_scale(transform, location, rotation, scale);
|
||||
|
||||
/** 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. */
|
||||
auto render_axis = [&](Axis axis) {
|
||||
/* TODO(fclem): get scene bounds GPU or CPU side. Or use the irradiance grid extents. */
|
||||
float4x4 winmat = math::projection::orthographic(-20.0f, 20.0f, -20.0f, 20.0f, -20.0f, 20.0f);
|
||||
|
||||
CartesianBasis basis = from_orthonormal_axes(AxisSigned(axis).next_after(), axis);
|
||||
view_.sync(from_rotation<float4x4>(basis), winmat);
|
||||
|
||||
inst_.pipelines.capture.render(view_);
|
||||
auto sync_view = [&](View &view, CartesianBasis basis) {
|
||||
float3 extent = scale;
|
||||
float4x4 winmat = projection::orthographic(
|
||||
-extent.x, extent.x, -extent.y, extent.y, -extent.z, extent.z);
|
||||
float4x4 viewinv = math::from_loc_rot<float4x4>(location,
|
||||
rotation * to_quaternion<float>(basis));
|
||||
view.sync(invert(viewinv), winmat);
|
||||
};
|
||||
|
||||
sync_view(view_x_, basis_x_);
|
||||
sync_view(view_y_, basis_y_);
|
||||
sync_view(view_z_, basis_z_);
|
||||
|
||||
/* Surfel per unit distance. */
|
||||
float surfel_density = 2.0f;
|
||||
grid_pixel_extent_ = max(int3(1), int3(surfel_density * 2.0f * scale));
|
||||
|
||||
DRW_stats_group_start("IrradianceBake.SurfelsCount");
|
||||
GPU_debug_capture_begin();
|
||||
|
||||
/* Raster the scene to query the number of surfel needed. */
|
||||
capture_info_buf_.do_surfel_count = true;
|
||||
capture_info_buf_.do_surfel_output = false;
|
||||
capture_info_buf_.surfel_len = 0u;
|
||||
capture_info_buf_.push_update();
|
||||
render_axis(Axis::X);
|
||||
render_axis(Axis::Y);
|
||||
render_axis(Axis::Z);
|
||||
|
||||
empty_raster_fb_.ensure(grid_pixel_extent_.yz());
|
||||
inst_.pipelines.capture.render(view_x_);
|
||||
empty_raster_fb_.ensure(int2(grid_pixel_extent_.x, grid_pixel_extent_.z));
|
||||
inst_.pipelines.capture.render(view_y_);
|
||||
empty_raster_fb_.ensure(grid_pixel_extent_.xy());
|
||||
inst_.pipelines.capture.render(view_z_);
|
||||
|
||||
GPU_debug_capture_end();
|
||||
DRW_stats_group_end();
|
||||
|
||||
/* Allocate surfel pool. */
|
||||
|
@ -146,15 +158,71 @@ void IrradianceBake::surfels_create(const IrradianceGrid & /* grid */)
|
|||
capture_info_buf_.do_surfel_output = true;
|
||||
capture_info_buf_.surfel_len = 0u;
|
||||
capture_info_buf_.push_update();
|
||||
render_axis(Axis::X);
|
||||
render_axis(Axis::Y);
|
||||
render_axis(Axis::Z);
|
||||
empty_raster_fb_.ensure(grid_pixel_extent_.yz());
|
||||
inst_.pipelines.capture.render(view_x_);
|
||||
empty_raster_fb_.ensure(int2(grid_pixel_extent_.x, grid_pixel_extent_.z));
|
||||
inst_.pipelines.capture.render(view_y_);
|
||||
empty_raster_fb_.ensure(grid_pixel_extent_.xy());
|
||||
inst_.pipelines.capture.render(view_z_);
|
||||
|
||||
DRW_stats_group_end();
|
||||
|
||||
/* Sync needs to happen after `surfels_buf_` is resized for correct dispatch size. */
|
||||
sync();
|
||||
}
|
||||
|
||||
void IrradianceBake::sync()
|
||||
{
|
||||
{
|
||||
PassSimple &pass = surfel_light_eval_ps_;
|
||||
pass.init();
|
||||
/* Apply lights contribution to scene surfel representation. */
|
||||
pass.shader_set(inst_.shaders.static_shader_get(SURFEL_LIGHT));
|
||||
pass.bind_ssbo(SURFEL_BUF_SLOT, &surfels_buf_);
|
||||
pass.bind_ssbo(CAPTURE_BUF_SLOT, &capture_info_buf_);
|
||||
pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
|
||||
inst_.lights.bind_resources(&pass);
|
||||
inst_.shadows.bind_resources(&pass);
|
||||
/* Sync with the surfel creation stage. */
|
||||
pass.barrier(GPU_BARRIER_SHADER_STORAGE);
|
||||
pass.dispatch(int3(divide_ceil_u(surfels_buf_.size(), SURFEL_LIGHT_GROUP_SIZE), 1, 1));
|
||||
pass.barrier(GPU_BARRIER_SHADER_STORAGE);
|
||||
}
|
||||
{
|
||||
PassSimple &pass = surfel_light_propagate_ps_;
|
||||
pass.init();
|
||||
{
|
||||
PassSimple::Sub &sub = pass.sub("ListBuild");
|
||||
sub.shader_set(inst_.shaders.static_shader_get(SURFEL_LIST_BUILD));
|
||||
/* TODO */
|
||||
}
|
||||
{
|
||||
PassSimple::Sub &sub = pass.sub("ListSort");
|
||||
sub.shader_set(inst_.shaders.static_shader_get(SURFEL_LIST_SORT));
|
||||
/* TODO */
|
||||
}
|
||||
}
|
||||
{
|
||||
PassSimple &pass = irradiance_capture_ps_;
|
||||
pass.init();
|
||||
/* TODO */
|
||||
}
|
||||
}
|
||||
|
||||
void IrradianceBake::surfels_lights_eval()
|
||||
{
|
||||
GPU_debug_capture_begin();
|
||||
/* Use the last setup view. This should work since the view is orthographic. */
|
||||
/* TODO(fclem): Remove this. It is only present to avoid crash inside `shadows.set_view` */
|
||||
inst_.render_buffers.acquire(int2(1));
|
||||
inst_.lights.set_view(view_z_, grid_pixel_extent_.xy());
|
||||
/* TODO: Instead of using the volume tagging we should tag using the surfels. */
|
||||
inst_.shadows.set_view(view_z_);
|
||||
inst_.render_buffers.release();
|
||||
|
||||
inst_.manager->submit(surfel_light_eval_ps_);
|
||||
|
||||
GPU_debug_capture_end();
|
||||
}
|
||||
|
||||
void IrradianceBake::propagate_light_sample()
|
||||
|
|
|
@ -33,7 +33,26 @@ class IrradianceBake {
|
|||
CaptureInfoBuf capture_info_buf_;
|
||||
/** Framebuffer. */
|
||||
Framebuffer empty_raster_fb_ = {"empty_raster_fb_"};
|
||||
View view_ = {"ortho_raster_view"};
|
||||
/** Evaluate light object contribution and store result to surfel. */
|
||||
PassSimple surfel_light_eval_ps_ = {"LightEval"};
|
||||
/** Propagate light from surfel to surfel. */
|
||||
PassSimple surfel_light_propagate_ps_ = {"LightPropagate"};
|
||||
/** Capture surfel lighting to irradiance samples. */
|
||||
PassSimple irradiance_capture_ps_ = {"IrradianceCapture"};
|
||||
|
||||
/** Basis orientation for each baking projection. */
|
||||
math::CartesianBasis basis_x_ = math::from_orthonormal_axes(math::AxisSigned::Y_POS,
|
||||
math::AxisSigned::X_POS);
|
||||
math::CartesianBasis basis_y_ = math::from_orthonormal_axes(math::AxisSigned::Z_POS,
|
||||
math::AxisSigned::Y_POS);
|
||||
math::CartesianBasis basis_z_ = math::from_orthonormal_axes(math::AxisSigned::X_POS,
|
||||
math::AxisSigned::Z_POS);
|
||||
/** Views for each baking projection. */
|
||||
View view_x_ = {"BakingViewX"};
|
||||
View view_y_ = {"BakingViewY"};
|
||||
View view_z_ = {"BakingViewZ"};
|
||||
/** Pixel resolution in each of the projection axes. Match the target surfel density. */
|
||||
int3 grid_pixel_extent_ = int3(0);
|
||||
|
||||
public:
|
||||
IrradianceBake(Instance &inst) : inst_(inst){};
|
||||
|
|
|
@ -21,8 +21,7 @@ typedef struct EEVEE_NEXT_LightBake EEVEE_NEXT_LightBake;
|
|||
* Create the job description.
|
||||
* This is called for async (modal) bake operator.
|
||||
* The actual work will be done by `EEVEE_NEXT_lightbake_job()`.
|
||||
* Will internally call `EEVEE_NEXT_lightbake_job_data_alloc()` or reuse data from an already
|
||||
* existing baking job.
|
||||
* Will internally call `EEVEE_NEXT_lightbake_job_data_alloc()`.
|
||||
* IMPORTANT: Must run on the main thread because of potential GPUContext creation.
|
||||
*/
|
||||
struct wmJob *EEVEE_NEXT_lightbake_job_create(struct wmWindowManager *wm,
|
||||
|
|
|
@ -26,7 +26,7 @@ void LightProbeModule::begin_sync()
|
|||
cubes.clear();
|
||||
}
|
||||
|
||||
void LightProbeModule::sync_grid(ObjectHandle &handle)
|
||||
void LightProbeModule::sync_grid(const Object *ob, ObjectHandle &handle)
|
||||
{
|
||||
LightProbe &grid = grid_map_.lookup_or_add_default(handle.object_key);
|
||||
grid.used = true;
|
||||
|
@ -36,7 +36,8 @@ void LightProbeModule::sync_grid(ObjectHandle &handle)
|
|||
}
|
||||
|
||||
if (inst_.is_baking()) {
|
||||
grids.append({});
|
||||
const ::LightProbe *light_probe = (const ::LightProbe *)ob->data;
|
||||
grids.append({float4x4(ob->object_to_world), &light_probe->grid_resolution_x});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,7 +66,7 @@ void LightProbeModule::sync_probe(const Object *ob, ObjectHandle &handle)
|
|||
/* TODO(fclem): Remove support? Add support? */
|
||||
return;
|
||||
case LIGHTPROBE_TYPE_GRID:
|
||||
sync_grid(handle);
|
||||
sync_grid(ob, handle);
|
||||
return;
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
|
|
|
@ -54,7 +54,7 @@ class LightProbeModule {
|
|||
void begin_sync();
|
||||
|
||||
void sync_cube(ObjectHandle &handle);
|
||||
void sync_grid(ObjectHandle &handle);
|
||||
void sync_grid(const Object *ob, ObjectHandle &handle);
|
||||
|
||||
void sync_probe(const Object *ob, ObjectHandle &handle);
|
||||
|
||||
|
|
|
@ -264,6 +264,12 @@ Material &MaterialModule::material_sync(Object *ob,
|
|||
mat.is_alpha_blend_transparent = (blender_mat->blend_method == MA_BM_BLEND) &&
|
||||
GPU_material_flag_get(mat.shading.gpumat,
|
||||
GPU_MATFLAG_TRANSPARENT);
|
||||
if (inst_.is_baking()) {
|
||||
/* WORKAROUND(fclem): This is to request the shadow for the surfels. This will well
|
||||
* over-request the number of shadow tiles. A better way would be to request from the surfels
|
||||
* directly. */
|
||||
mat.is_alpha_blend_transparent = true;
|
||||
}
|
||||
return mat;
|
||||
});
|
||||
|
||||
|
|
|
@ -172,6 +172,12 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_
|
|||
return "eevee_shadow_tag_usage_opaque";
|
||||
case SHADOW_TILEMAP_TAG_USAGE_TRANSPARENT:
|
||||
return "eevee_shadow_tag_usage_transparent";
|
||||
case SURFEL_LIGHT:
|
||||
return "eevee_surfel_light";
|
||||
case SURFEL_LIST_BUILD:
|
||||
return "eevee_surfel_list_build";
|
||||
case SURFEL_LIST_SORT:
|
||||
return "eevee_surfel_list_sort";
|
||||
/* To avoid compiler warning about missing case. */
|
||||
case MAX_SHADER_TYPE:
|
||||
return "";
|
||||
|
|
|
@ -80,6 +80,10 @@ enum eShaderType {
|
|||
SHADOW_TILEMAP_TAG_USAGE_OPAQUE,
|
||||
SHADOW_TILEMAP_TAG_USAGE_TRANSPARENT,
|
||||
|
||||
SURFEL_LIGHT,
|
||||
SURFEL_LIST_BUILD,
|
||||
SURFEL_LIST_SORT,
|
||||
|
||||
MAX_SHADER_TYPE,
|
||||
};
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ void light_eval_ex(ClosureDiffuse diffuse,
|
|||
vec3 P,
|
||||
vec3 Ng,
|
||||
vec3 V,
|
||||
float vP_z,
|
||||
float vP_z, /* TODO(fclem): Remove, is unused. */
|
||||
float thickness,
|
||||
vec4 ltc_mat,
|
||||
uint l_idx,
|
||||
|
@ -111,7 +111,11 @@ void light_eval(ClosureDiffuse diffuse,
|
|||
}
|
||||
LIGHT_FOREACH_END
|
||||
|
||||
#ifdef GPU_FRAGMENT_SHADER
|
||||
vec2 px = gl_FragCoord.xy;
|
||||
#else
|
||||
vec2 px = vec2(0.0);
|
||||
#endif
|
||||
LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, px, vP_z, l_idx) {
|
||||
light_eval_ex(diffuse,
|
||||
reflection,
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
|
||||
/**
|
||||
* Apply lights contribution to scene surfel representation.
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(eevee_light_eval_lib.glsl)
|
||||
|
||||
void light_eval_surfel(
|
||||
ClosureDiffuse diffuse, vec3 P, vec3 Ng, float thickness, inout vec3 out_diffuse)
|
||||
{
|
||||
/* Dummy closure. Not used. */
|
||||
ClosureReflection reflection;
|
||||
reflection.N = vec3(1.0, 0.0, 0.0);
|
||||
reflection.roughness = 0.0;
|
||||
vec3 out_specular = vec3(0.0);
|
||||
/* Dummy ltc mat parameters. Not used since we have no reflections. */
|
||||
vec4 ltc_mat_dummy = utility_tx_sample(utility_tx, vec2(0.0), UTIL_LTC_MAT_LAYER);
|
||||
|
||||
vec3 V = Ng;
|
||||
float vP_z = 0.0;
|
||||
|
||||
LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) {
|
||||
light_eval_ex(diffuse,
|
||||
reflection,
|
||||
true,
|
||||
P,
|
||||
Ng,
|
||||
V,
|
||||
vP_z,
|
||||
thickness,
|
||||
ltc_mat_dummy,
|
||||
l_idx,
|
||||
out_diffuse,
|
||||
out_specular);
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
|
||||
LIGHT_FOREACH_BEGIN_LOCAL_NO_CULL (light_cull_buf, l_idx) {
|
||||
light_eval_ex(diffuse,
|
||||
reflection,
|
||||
false,
|
||||
P,
|
||||
Ng,
|
||||
V,
|
||||
vP_z,
|
||||
thickness,
|
||||
ltc_mat_dummy,
|
||||
l_idx,
|
||||
out_diffuse,
|
||||
out_specular);
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
int index = int(gl_GlobalInvocationID.x);
|
||||
if (index >= capture_info_buf.surfel_len) {
|
||||
return;
|
||||
}
|
||||
|
||||
Surfel surfel = surfel_buf[index];
|
||||
|
||||
ClosureDiffuse diffuse_data;
|
||||
diffuse_data.N = surfel.normal;
|
||||
/* TODO: These could saved inside the surfel. */
|
||||
diffuse_data.sss_radius = vec3(0.0);
|
||||
diffuse_data.sss_id = 0u;
|
||||
float thickness = 0.0;
|
||||
|
||||
vec3 diffuse_light = vec3(0.0);
|
||||
vec3 reflection_light = vec3(0.0);
|
||||
|
||||
light_eval_surfel(diffuse_data, surfel.position, surfel.normal, thickness, diffuse_light);
|
||||
|
||||
surfel.radiance += diffuse_light * surfel.albedo;
|
||||
|
||||
surfel_buf[index] = surfel;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
/**
|
||||
* Takes scene surfel representation and build list of surfels aligning in a given direction.
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
/**
|
||||
* Sort a buffer of surfel list by distance along a direction.
|
||||
* The resulting surfel lists are then the equivalent of a series of ray cast in the same
|
||||
* direction. The fact that the surfels are sorted gives proper occlusion.
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
}
|
|
@ -17,3 +17,29 @@ GPU_SHADER_CREATE_INFO(eevee_debug_surfels)
|
|||
.push_constant(Type::FLOAT, "surfel_radius")
|
||||
.push_constant(Type::INT, "debug_mode")
|
||||
.do_static_compilation(true);
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_surfel_light)
|
||||
.local_group_size(CULLING_SELECT_GROUP_SIZE)
|
||||
.additional_info("eevee_shared",
|
||||
"draw_view",
|
||||
"eevee_utility_texture",
|
||||
"eevee_light_data",
|
||||
"eevee_shadow_data")
|
||||
.compute_source("eevee_surfel_light_comp.glsl")
|
||||
.storage_buf(SURFEL_BUF_SLOT, Qualifier::READ_WRITE, "Surfel", "surfel_buf[]")
|
||||
.storage_buf(CAPTURE_BUF_SLOT, Qualifier::READ, "CaptureInfoData", "capture_info_buf")
|
||||
.do_static_compilation(true);
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_surfel_list_build)
|
||||
.local_group_size(CULLING_SELECT_GROUP_SIZE)
|
||||
.additional_info("eevee_shared", "draw_view")
|
||||
.compute_source("eevee_surfel_list_build_comp.glsl")
|
||||
.storage_buf(0, Qualifier::READ_WRITE, "Surfel", "surfels_buf[]")
|
||||
.do_static_compilation(true);
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_surfel_list_sort)
|
||||
.local_group_size(CULLING_SELECT_GROUP_SIZE)
|
||||
.additional_info("eevee_shared", "draw_view")
|
||||
.compute_source("eevee_surfel_list_sort_comp.glsl")
|
||||
.storage_buf(0, Qualifier::READ_WRITE, "Surfel", "surfels_buf[]")
|
||||
.do_static_compilation(true);
|
||||
|
|
Loading…
Reference in New Issue