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.
19 changed files with 291 additions and 31 deletions
Showing only changes of commit 9461d7fc9a - Show all commits

View File

@ -16,7 +16,7 @@ class DataButtonsPanel:
class DATA_PT_context_lightprobe(DataButtonsPanel, Panel):
bl_label = ""
bl_options = {'HIDE_HEADER'}
COMPAT_ENGINES = {'BLENDER_EEVEE', 'BLENDER_RENDER'}
COMPAT_ENGINES = {'BLENDER_EEVEE', 'BLENDER_RENDER', 'BLENDER_EEVEE_NEXT'}
def draw(self, context):
layout = self.layout
@ -33,7 +33,7 @@ class DATA_PT_context_lightprobe(DataButtonsPanel, Panel):
class DATA_PT_lightprobe(DataButtonsPanel, Panel):
bl_label = "Probe"
COMPAT_ENGINES = {'BLENDER_EEVEE', 'BLENDER_RENDER'}
COMPAT_ENGINES = {'BLENDER_EEVEE', 'BLENDER_RENDER', 'BLENDER_EEVEE_NEXT'}
def draw(self, context):
layout = self.layout

View File

@ -465,6 +465,8 @@ set(GLSL_SRC
engines/eevee_next/shaders/eevee_light_eval_lib.glsl
engines/eevee_next/shaders/eevee_light_iter_lib.glsl
engines/eevee_next/shaders/eevee_light_lib.glsl
engines/eevee_next/shaders/eevee_lightprobe_irradiance_ray_comp.glsl
engines/eevee_next/shaders/eevee_lightprobe_lib.glsl
engines/eevee_next/shaders/eevee_ltc_lib.glsl
engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl
engines/eevee_next/shaders/eevee_motion_blur_flatten_comp.glsl
@ -502,6 +504,7 @@ set(GLSL_SRC
engines/eevee_next/shaders/eevee_surfel_bounce_comp.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_lib.glsl
engines/eevee_next/shaders/eevee_surfel_list_sort_comp.glsl
engines/eevee_next/shaders/eevee_surfel_ray_comp.glsl
engines/eevee_next/shaders/eevee_transparency_lib.glsl

View File

@ -89,6 +89,7 @@
/* IrradianceBake. */
#define SURFEL_GROUP_SIZE 256
#define SURFEL_LIST_GROUP_SIZE 256
#define IRRADIANCE_GRID_GROUP_SIZE 4 /* In each dimension, do 4x4x4 workgroup size. */
/* Resource bindings. */

View File

@ -573,6 +573,7 @@ void Instance::light_bake_irradiance(LightCache *&r_light_cache,
}
}
r_light_cache->flag |= LIGHTCACHE_BAKED;
r_light_cache->flag &= ~LIGHTCACHE_BAKING;
}

View File

@ -17,9 +17,7 @@ namespace blender::eevee {
/** \name Interface
* \{ */
void IrradianceCache::init()
{
}
void IrradianceCache::init() {}
void IrradianceCache::sync()
{
@ -112,10 +110,33 @@ void IrradianceCache::display_pass_sync()
for (auto i : IndexRange(light_cache->grid_len)) {
LightCacheIrradianceGrid &grid = light_cache->grids[i];
display_grids_ps_.push_constant("sphere_radius", 0.1f);
if (grid.irradiance_L0_L1_a.data == nullptr) {
continue;
}
auto load_texture = [&](const char *name, LightCacheTexture &cache_texture) {
if ((light_cache->flag & LIGHTCACHE_BAKED) && cache_texture.tex != nullptr) {
return;
}
if (light_cache->flag & LIGHTCACHE_BAKING) {
GPU_TEXTURE_FREE_SAFE(cache_texture.tex);
}
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ;
cache_texture.tex = GPU_texture_create_3d(
name, UNPACK3(cache_texture.tex_size), 1, GPU_RGBA16F, usage, cache_texture.data);
};
load_texture("grid.irradiance_L0_L1_a", grid.irradiance_L0_L1_a);
load_texture("grid.irradiance_L0_L1_b", grid.irradiance_L0_L1_b);
load_texture("grid.irradiance_L0_L1_c", grid.irradiance_L0_L1_c);
display_grids_ps_.push_constant("sphere_radius", 0.3f);
display_grids_ps_.push_constant("grid_resolution", int3(grid.resolution));
float4x4 grid_to_world = math::invert(float4x4(grid.world_to_grid));
display_grids_ps_.push_constant("grid_to_world", grid_to_world);
display_grids_ps_.bind_texture("irradiance_a_tx", grid.irradiance_L0_L1_a.tex);
display_grids_ps_.bind_texture("irradiance_b_tx", grid.irradiance_L0_L1_b.tex);
display_grids_ps_.bind_texture("irradiance_c_tx", grid.irradiance_L0_L1_c.tex);
int cell_count = grid.resolution[0] * grid.resolution[1] * grid.resolution[2];
display_grids_ps_.draw_procedural(GPU_PRIM_TRIS, 1, cell_count * 3 * 2);
@ -187,7 +208,16 @@ void IrradianceBake::sync()
{
PassSimple &pass = irradiance_capture_ps_;
pass.init();
/* TODO */
pass.shader_set(inst_.shaders.static_shader_get(LIGHTPROBE_IRRADIANCE_RAY));
pass.bind_ssbo(SURFEL_BUF_SLOT, &surfels_buf_);
pass.bind_ssbo(CAPTURE_BUF_SLOT, &capture_info_buf_);
pass.bind_ssbo("list_start_buf", &list_start_buf_);
pass.bind_ssbo("list_info_buf", &list_info_buf_);
pass.bind_image("irradiance_L0_L1_a_img", &irradiance_L0_L1_a_tx_);
pass.bind_image("irradiance_L0_L1_b_img", &irradiance_L0_L1_b_tx_);
pass.bind_image("irradiance_L0_L1_c_img", &irradiance_L0_L1_c_tx_);
pass.barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_SHADER_IMAGE_ACCESS);
pass.dispatch(&dispatch_per_grid_sample_);
}
{
PassSimple &pass = surfel_light_bounce_ps_;
@ -237,6 +267,26 @@ void IrradianceBake::surfels_create(const IrradianceGrid &grid)
surfel_raster_views_sync(grid);
dispatch_per_grid_sample_ = math::divide_ceil(grid.resolution, int3(IRRADIANCE_GRID_GROUP_SIZE));
capture_info_buf_.irradiance_grid_size = grid.resolution;
capture_info_buf_.irradiance_grid_local_to_world = grid.transform;
capture_info_buf_.irradiance_accum_solid_angle = 0.0f;
/* Divide by twice the sample count because each ray is evaluated in both directions. */
capture_info_buf_.irradiance_sample_solid_angle = 4.0f * float(M_PI) /
(2 * inst_.sampling.sample_count());
eGPUTextureUsage texture_usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE |
GPU_TEXTURE_USAGE_HOST_READ;
/* 32bit float is needed here otherwise we loose too much energy from rounding error during the
* accumulation when the sample count is above 500. */
irradiance_L0_L1_a_tx_.ensure_3d(GPU_RGBA32F, grid.resolution, texture_usage);
irradiance_L0_L1_b_tx_.ensure_3d(GPU_RGBA32F, grid.resolution, texture_usage);
irradiance_L0_L1_c_tx_.ensure_3d(GPU_RGBA32F, grid.resolution, texture_usage);
irradiance_L0_L1_a_tx_.clear(float4(0.0f));
irradiance_L0_L1_b_tx_.clear(float4(0.0f));
irradiance_L0_L1_c_tx_.clear(float4(0.0f));
const float4x4 transform(grid.transform);
/* Extract bounding box. Order is arbitrary as it is not important for our usage. */
@ -367,6 +417,7 @@ void IrradianceBake::propagate_light_sample()
GPU_storagebuf_clear(list_start_buf_, -1);
inst_.manager->submit(surfel_light_propagate_ps_, ray_view);
inst_.manager->submit(irradiance_capture_ps_, ray_view);
}
void IrradianceBake::accumulate_bounce()
@ -376,6 +427,18 @@ void IrradianceBake::accumulate_bounce()
void IrradianceBake::read_result(LightCacheIrradianceGrid &light_cache_grid)
{
auto read_texture = [&](LightCacheTexture &cache_texture, draw::Texture &texture) {
MEM_SAFE_FREE(cache_texture.data);
cache_texture.data = (char *)texture.read<float4>(GPU_DATA_FLOAT);
copy_v3_v3_int(cache_texture.tex_size, light_cache_grid.resolution);
cache_texture.data_type = LIGHTCACHETEX_FLOAT;
cache_texture.components = 4;
};
GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE);
read_texture(light_cache_grid.irradiance_L0_L1_a, irradiance_L0_L1_a_tx_);
read_texture(light_cache_grid.irradiance_L0_L1_b, irradiance_L0_L1_b_tx_);
read_texture(light_cache_grid.irradiance_L0_L1_c, irradiance_L0_L1_c_tx_);
switch (inst_.debug_mode) {
case eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_NORMAL:
case eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_IRRADIANCE:

View File

@ -69,6 +69,13 @@ class IrradianceBake {
int3 dispatch_per_surfel_ = int3(1);
/* Dispatch size for per surfel list workload. */
int3 dispatch_per_list_ = int3(1);
/* Dispatch size for per grid sample workload. */
int3 dispatch_per_grid_sample_ = int3(1);
/** Irradiance textures for baking. Only represents one grid in there. */
Texture irradiance_L0_L1_a_tx_ = {"irradiance_L0_L1_a_tx_"};
Texture irradiance_L0_L1_b_tx_ = {"irradiance_L0_L1_b_tx_"};
Texture irradiance_L0_L1_c_tx_ = {"irradiance_L0_L1_c_tx_"};
/* Surfel per unit distance. */
float surfel_density_ = 2.0f;

View File

@ -339,6 +339,9 @@ void EEVEE_NEXT_lightcache_free(LightCache *light_cache)
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);
DRW_TEXTURE_FREE_SAFE(light_cache->grids[i].irradiance_L0_L1_a.tex);
DRW_TEXTURE_FREE_SAFE(light_cache->grids[i].irradiance_L0_L1_b.tex);
DRW_TEXTURE_FREE_SAFE(light_cache->grids[i].irradiance_L0_L1_c.tex);
}
MEM_SAFE_FREE(light_cache->grids);
}

View File

@ -148,6 +148,8 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_
return "eevee_light_culling_tile";
case LIGHT_CULLING_ZBIN:
return "eevee_light_culling_zbin";
case LIGHTPROBE_IRRADIANCE_RAY:
return "eevee_lightprobe_irradiance_ray";
case SHADOW_CLIPMAP_CLEAR:
return "eevee_shadow_clipmap_clear";
case SHADOW_DEBUG:

View File

@ -63,6 +63,8 @@ enum eShaderType {
LIGHT_CULLING_TILE,
LIGHT_CULLING_ZBIN,
LIGHTPROBE_IRRADIANCE_RAY,
MOTION_BLUR_GATHER,
MOTION_BLUR_TILE_DILATE,
MOTION_BLUR_TILE_FLATTEN_RENDER,

View File

@ -862,13 +862,20 @@ struct Surfel {
BLI_STATIC_ASSERT_ALIGN(Surfel, 16)
struct CaptureInfoData {
/** Number of surfels inside the surfel buffer or the needed len. */
int3 irradiance_grid_size;
/** True if the surface shader needs to write the surfel data. */
bool1 do_surfel_output;
/** True if the surface shader needs to increment the surfel_len. */
bool1 do_surfel_count;
/** Number of surfels inside the surfel buffer or the needed len. */
uint surfel_len;
int _pad0;
/** Solid angle subtended by a single ray sample. Equal to `4 * pi / sample_count`. */
float irradiance_sample_solid_angle;
/** Accumulated solid angle. Should reach `4 * pi` at the end of the accumulation. */
float irradiance_accum_solid_angle;
/** Transform of the lightprobe object. */
float4x4 irradiance_grid_local_to_world;
};
BLI_STATIC_ASSERT_ALIGN(CaptureInfoData, 16)

View File

@ -1,4 +1,5 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_spherical_harmonics_lib.glsl)
void main()
{
@ -10,7 +11,13 @@ void main()
return;
}
SphericalHarmonicL1 sh = spherical_harmonics_unpack(texelFetch(irradiance_a_tx, cell, 0),
texelFetch(irradiance_b_tx, cell, 0),
texelFetch(irradiance_c_tx, cell, 0));
vec3 vN = vec3(lP, sqrt(max(0.0, 1.0 - dist_sqr)));
vec3 P = mat3(ViewMatrixInverse) * vN;
out_color = vec4(normal_view_to_world(vN) * 0.5 + 0.5, 1.0);
vec3 N = normal_view_to_world(vN);
vec3 irradiance = spherical_harmonics_evaluate_lambert(N, sh);
out_color = vec4(irradiance, 0.0);
}

View File

@ -1,5 +1,6 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_lightprobe_lib.glsl)
void main()
{
@ -14,21 +15,21 @@ void main()
vec2(-1.0, 1.0));
lP = pos[gl_VertexID % 6];
cell_index = gl_VertexID / 6;
int cell_index = gl_VertexID / 6;
/* Keep in sync with update_irradiance_probe. */
ivec3 cell = ivec3(cell_index / (grid_resolution.z * grid_resolution.y),
(cell_index / grid_resolution.z) % grid_resolution.y,
cell_index % grid_resolution.z);
ivec3 grid_resolution = textureSize(irradiance_a_tx, 0);
vec3 ls_cell_pos = (vec3(cell) + vec3(0.5)) / vec3(grid_resolution);
ls_cell_pos = ls_cell_pos * 2.0 - 1.0; /* Remap to (-1 ... +1). */
cell = ivec3(cell_index / (grid_resolution.z * grid_resolution.y),
(cell_index / grid_resolution.z) % grid_resolution.y,
cell_index % grid_resolution.z);
vec3 ws_cell_pos = (grid_to_world * vec4(ls_cell_pos, 1.0)).xyz;
vec3 ws_cell_pos = lightprobe_irradiance_grid_sample_position(
grid_to_world, grid_resolution, cell);
vec3 vs_offset = vec3(lP, 0.0) * sphere_radius;
vec3 vP = (ViewMatrix * vec4(ws_cell_pos, 1.0)).xyz + vs_offset;
gl_Position = ProjectionMatrix * vec4(vP, 1.0);
gl_Position.z += 0.0001; /* Small bias to let the icon draw without zfighting. */
/* Small bias to let the icon draw without zfighting. */
gl_Position.z += 0.0001;
}

View File

@ -0,0 +1,88 @@
/**
* For every irradiance probe sample, compute the incomming radiance from both side.
* This is the same as the surfel ray but we do not actually transport the light, we only capture
* the irradiance as spherical harmonic coefficients.
*
* Dispatched as 1 thread per irradiance probe sample.
*/
#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_math_base_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_spherical_harmonics_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_surfel_list_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_lightprobe_lib.glsl)
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
void irradiance_capture(vec3 L, vec3 irradiance, inout SphericalHarmonicL1 sh)
{
spherical_harmonics_encode_signal_sample(
L, irradiance * capture_info_buf.irradiance_sample_solid_angle, sh);
}
void irradiance_capture(Surfel surfel_emitter, vec3 P, inout SphericalHarmonicL1 sh)
{
vec3 L = safe_normalize(surfel_emitter.position - P);
bool facing = dot(-L, surfel_emitter.normal) > 0.0;
vec3 irradiance = facing ? surfel_emitter.radiance_front : surfel_emitter.radiance_back;
irradiance_capture(L, irradiance, sh);
}
void main()
{
if (any(greaterThanEqual(gl_GlobalInvocationID, capture_info_buf.irradiance_grid_size))) {
return;
}
ivec3 grid_coord = ivec3(gl_GlobalInvocationID);
vec3 P = lightprobe_irradiance_grid_sample_position(
capture_info_buf.irradiance_grid_local_to_world,
capture_info_buf.irradiance_grid_size,
grid_coord);
/* Project to get ray linked list. */
float irradiance_sample_ray_distance;
int list_index = surfel_list_index_get(P, irradiance_sample_ray_distance);
/* Walk the ray to get which surfels the irradiance sample is between. */
int surfel_prev = -1;
int surfel_next = list_start_buf[list_index];
for (; surfel_next > -1; surfel_next = surfel_buf[surfel_next].next) {
/* Reminder: List is sorted with highest value first. */
if (surfel_buf[surfel_next].ray_distance < irradiance_sample_ray_distance) {
break;
}
surfel_prev = surfel_next;
}
vec3 sky_L = cameraVec(P);
SphericalHarmonicL1 sh = spherical_harmonics_unpack(
imageLoad(irradiance_L0_L1_a_img, grid_coord),
imageLoad(irradiance_L0_L1_b_img, grid_coord),
imageLoad(irradiance_L0_L1_c_img, grid_coord));
if (surfel_next > -1) {
irradiance_capture(surfel_buf[surfel_next], P, sh);
}
else {
/* TODO(fclem): Sky radiance. */
irradiance_capture(sky_L, vec3(0.0), sh);
}
if (surfel_prev > -1) {
irradiance_capture(surfel_buf[surfel_prev], P, sh);
}
else {
/* TODO(fclem): Sky radiance. */
irradiance_capture(-sky_L, vec3(0.0), sh);
}
vec4 sh_a, sh_b, sh_c;
spherical_harmonics_pack(sh, sh_a, sh_b, sh_c);
imageStore(irradiance_L0_L1_a_img, grid_coord, sh_a);
imageStore(irradiance_L0_L1_b_img, grid_coord, sh_b);
imageStore(irradiance_L0_L1_c_img, grid_coord, sh_c);
}

View File

@ -0,0 +1,10 @@
vec3 lightprobe_irradiance_grid_sample_position(mat4 grid_local_to_world,
ivec3 grid_resolution,
ivec3 cell_coord)
{
vec3 ls_cell_pos = (vec3(cell_coord) + vec3(0.5)) / vec3(grid_resolution);
ls_cell_pos = ls_cell_pos * 2.0 - 1.0;
vec3 ws_cell_pos = (grid_local_to_world * vec4(ls_cell_pos, 1.0)).xyz;
return ws_cell_pos;
}

View File

@ -102,6 +102,7 @@ struct SphericalHarmonicL2 {
/** \name Encode
*
* Decompose an input signal into spherical harmonic coefficients.
* Note that `amplitude` need to be scaled by solid angle.
* \{ */
void spherical_harmonics_L0_encode_signal_sample(vec3 direction,
@ -213,3 +214,34 @@ vec3 spherical_harmonics_evaluate_lambert(vec3 N, SphericalHarmonicL2 sh)
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Load/Store
*
* This section define the compression scheme of spherical harmonic data.
* \{ */
SphericalHarmonicL1 spherical_harmonics_unpack(vec4 L0_L1_a, vec4 L0_L1_b, vec4 L0_L1_c)
{
SphericalHarmonicL1 sh;
sh.L0.M0 = L0_L1_a.xyz;
sh.L1.Mn1 = L0_L1_b.xyz;
sh.L1.M0 = L0_L1_c.xyz;
sh.L1.Mp1 = vec3(L0_L1_a.w, L0_L1_b.w, L0_L1_c.w);
return sh;
}
void spherical_harmonics_pack(SphericalHarmonicL1 sh,
out vec4 L0_L1_a,
out vec4 L0_L1_b,
out vec4 L0_L1_c)
{
L0_L1_a.xyz = sh.L0.M0;
L0_L1_b.xyz = sh.L1.Mn1;
L0_L1_c.xyz = sh.L1.M0;
L0_L1_a.w = sh.L1.Mp1.x;
L0_L1_b.w = sh.L1.Mp1.y;
L0_L1_c.w = sh.L1.Mp1.z;
}
/** \} */

View File

@ -12,7 +12,7 @@
#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_math_base_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_surfel_list_lib.glsl)
void main()
{
@ -21,16 +21,11 @@ void main()
return;
}
vec4 hP = point_world_to_ndc(surfel_buf[surfel_index].position);
surfel_buf[surfel_index].ray_distance = -hP.z;
vec2 ssP_surfel = hP.xy * 0.5 + 0.5;
ivec2 ray_coord_on_grid = clamp(ivec2(ssP_surfel * vec2(list_info_buf.ray_grid_size)),
ivec2(0),
list_info_buf.ray_grid_size - 1);
int list_index = ray_coord_on_grid.y * list_info_buf.ray_grid_size.x + ray_coord_on_grid.x;
float ray_distance;
int list_index = surfel_list_index_get(surfel_buf[surfel_index].position, ray_distance);
/* Do separate assignement to avoid reference to buffer in arguments which is tricky to cross
* compile. */
surfel_buf[surfel_index].ray_distance = ray_distance;
/* NOTE: We only need to init the `list_start_buf` to -1 for the whole list to be valid since
* every surfel will load its `next` value from the list head. */
surfel_buf[surfel_index].next = atomicExchange(list_start_buf[list_index], surfel_index);

View File

@ -0,0 +1,19 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
/**
* Return the coresponding list index in the `list_start_buf` for a given world position.
* It will clamp any coordinate outside valid bounds to nearest list.
* Also return the surfel sorting value as `r_ray_distance`.
*/
int surfel_list_index_get(vec3 P, out float r_ray_distance)
{
vec4 hP = point_world_to_ndc(P);
r_ray_distance = -hP.z;
vec2 ssP = hP.xy * 0.5 + 0.5;
ivec2 ray_coord_on_grid = ivec2(ssP * vec2(list_info_buf.ray_grid_size));
ray_coord_on_grid = clamp(ray_coord_on_grid, ivec2(0), list_info_buf.ray_grid_size - 1);
int list_index = ray_coord_on_grid.y * list_info_buf.ray_grid_size.x + ray_coord_on_grid.x;
return list_index;
}

View File

@ -123,6 +123,9 @@ void main()
}
}
/* Update list start for irradiance sample capture. */
list_start_buf[list_index] = sorted_list.first;
/* Now that we have a sorted list, try to avoid connection from coplanar surfels.
* For that we disconnect them and link them to the first non-coplanar surfel.
* Note that this changes the list to a tree, which doesn't affect the rest of the algorithm.

View File

@ -63,7 +63,7 @@ GPU_SHADER_CREATE_INFO(eevee_surfel_ray)
GPU_SHADER_INTERFACE_INFO(eevee_display_probe_grid_iface, "")
.smooth(Type::VEC2, "lP")
.flat(Type::INT, "cell_index");
.flat(Type::IVEC3, "cell");
GPU_SHADER_CREATE_INFO(eevee_display_probe_grid)
.additional_info("eevee_shared", "draw_view")
@ -74,4 +74,20 @@ GPU_SHADER_CREATE_INFO(eevee_display_probe_grid)
.push_constant(Type::FLOAT, "sphere_radius")
.push_constant(Type::IVEC3, "grid_resolution")
.push_constant(Type::MAT4, "grid_to_world")
.sampler(0, ImageType::FLOAT_3D, "irradiance_a_tx")
.sampler(1, ImageType::FLOAT_3D, "irradiance_b_tx")
.sampler(2, ImageType::FLOAT_3D, "irradiance_c_tx")
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(eevee_lightprobe_irradiance_ray)
.local_group_size(IRRADIANCE_GRID_GROUP_SIZE,
IRRADIANCE_GRID_GROUP_SIZE,
IRRADIANCE_GRID_GROUP_SIZE)
.additional_info("eevee_shared", "eevee_surfel_common", "draw_view")
.storage_buf(0, Qualifier::READ, "int", "list_start_buf[]")
.storage_buf(6, Qualifier::READ, "SurfelListInfoData", "list_info_buf")
.image(0, GPU_RGBA16F, Qualifier::READ_WRITE, ImageType::FLOAT_3D, "irradiance_L0_L1_a_img")
.image(1, GPU_RGBA16F, Qualifier::READ_WRITE, ImageType::FLOAT_3D, "irradiance_L0_L1_b_img")
.image(2, GPU_RGBA16F, Qualifier::READ_WRITE, ImageType::FLOAT_3D, "irradiance_L0_L1_c_img")
.compute_source("eevee_lightprobe_irradiance_ray_comp.glsl")
.do_static_compilation(true);