WIP: eevee-next-world-irradiance #108304
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue