EEVEE-Next: Irradiance Volume validity weighting #110851
|
@ -116,6 +116,7 @@ class DATA_PT_lightprobe_eevee_next(DataButtonsPanel, Panel):
|
|||
col.prop(probe, "grid_normal_bias")
|
||||
col.prop(probe, "grid_view_bias")
|
||||
col.prop(probe, "grid_irradiance_smoothing")
|
||||
col.prop(probe, "grid_validity_threshold")
|
||||
|
||||
col.separator()
|
||||
|
||||
|
|
|
@ -34,6 +34,9 @@ void IrradianceCache::init()
|
|||
int texel_byte_size = 8; /* Assumes GPU_RGBA16F. */
|
||||
int3 atlas_extent(IRRADIANCE_GRID_BRICK_SIZE);
|
||||
atlas_extent.z *= sh_coef_len;
|
||||
/* Add space for validity bits. */
|
||||
atlas_extent.z += IRRADIANCE_GRID_BRICK_SIZE / 4;
|
||||
|
||||
int atlas_col_count = 256;
|
||||
atlas_extent.x *= atlas_col_count;
|
||||
/* Determine the row count depending on the scene settings. */
|
||||
|
@ -279,6 +282,7 @@ void IrradianceCache::set_view(View & /*view*/)
|
|||
grid_upload_ps_.init();
|
||||
grid_upload_ps_.shader_set(inst_.shaders.static_shader_get(LIGHTPROBE_IRRADIANCE_LOAD));
|
||||
|
||||
grid_upload_ps_.push_constant("validity_threshold", grid->validity_threshold);
|
||||
grid_upload_ps_.push_constant("dilation_threshold", grid->dilation_threshold);
|
||||
grid_upload_ps_.push_constant("dilation_radius", grid->dilation_radius);
|
||||
grid_upload_ps_.push_constant("grid_index", grid->grid_index);
|
||||
|
@ -326,6 +330,9 @@ void IrradianceCache::debug_pass_draw(View &view, GPUFrameBuffer *view_fb)
|
|||
case eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_IRRADIANCE:
|
||||
inst_.info = "Debug Mode: Surfels Irradiance";
|
||||
break;
|
||||
case eDebugMode::DEBUG_IRRADIANCE_CACHE_VALIDITY:
|
||||
inst_.info = "Debug Mode: Irradiance Validity";
|
||||
break;
|
||||
case eDebugMode::DEBUG_IRRADIANCE_CACHE_VIRTUAL_OFFSET:
|
||||
inst_.info = "Debug Mode: Virtual Offset";
|
||||
break;
|
||||
|
@ -370,10 +377,8 @@ void IrradianceCache::debug_pass_draw(View &view, GPUFrameBuffer *view_fb)
|
|||
break;
|
||||
}
|
||||
|
||||
case eDebugMode::DEBUG_IRRADIANCE_CACHE_VALIDITY:
|
||||
case eDebugMode::DEBUG_IRRADIANCE_CACHE_VIRTUAL_OFFSET: {
|
||||
if (cache->baking.virtual_offset == nullptr) {
|
||||
continue;
|
||||
}
|
||||
int3 grid_size = int3(cache->size);
|
||||
debug_ps_.init();
|
||||
debug_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
|
||||
|
@ -383,14 +388,45 @@ void IrradianceCache::debug_pass_draw(View &view, GPUFrameBuffer *view_fb)
|
|||
debug_ps_.push_constant("debug_mode", int(inst_.debug_mode));
|
||||
debug_ps_.push_constant("grid_mat", grid.object_to_world);
|
||||
|
||||
float4 *data = (float4 *)cache->baking.virtual_offset;
|
||||
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ;
|
||||
Texture debug_data_tx = {"debug_data_tx"};
|
||||
debug_data_tx.ensure_3d(
|
||||
GPU_RGBA16F, grid_size, GPU_TEXTURE_USAGE_SHADER_READ, (float *)data);
|
||||
|
||||
debug_ps_.bind_texture("debug_data_tx", debug_data_tx);
|
||||
debug_ps_.draw_procedural(GPU_PRIM_LINES, 1, grid_size.x * grid_size.y * grid_size.z * 2);
|
||||
if (inst_.debug_mode == eDebugMode::DEBUG_IRRADIANCE_CACHE_VALIDITY) {
|
||||
float *data;
|
||||
if (cache->baking.validity) {
|
||||
data = (float *)cache->baking.validity;
|
||||
debug_data_tx.ensure_3d(GPU_R16F, grid_size, usage, (float *)data);
|
||||
}
|
||||
else if (cache->connectivity.validity) {
|
||||
debug_data_tx.ensure_3d(GPU_R8, grid_size, usage);
|
||||
/* TODO(fclem): Make texture creation API work with different data types. */
|
||||
GPU_texture_update_sub(debug_data_tx,
|
||||
GPU_DATA_UBYTE,
|
||||
cache->connectivity.validity,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
UNPACK3(grid_size));
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
debug_ps_.push_constant("debug_value", grid.validity_threshold);
|
||||
debug_ps_.bind_texture("debug_data_tx", debug_data_tx);
|
||||
debug_ps_.draw_procedural(GPU_PRIM_POINTS, 1, grid_size.x * grid_size.y * grid_size.z);
|
||||
}
|
||||
else {
|
||||
if (cache->baking.virtual_offset) {
|
||||
float *data = (float *)cache->baking.virtual_offset;
|
||||
debug_data_tx.ensure_3d(GPU_RGBA16F, grid_size, usage, data);
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
debug_ps_.bind_texture("debug_data_tx", debug_data_tx);
|
||||
debug_ps_.draw_procedural(
|
||||
GPU_PRIM_LINES, 1, grid_size.x * grid_size.y * grid_size.z * 2);
|
||||
}
|
||||
|
||||
inst_.manager->submit(debug_ps_, view);
|
||||
break;
|
||||
|
|
|
@ -44,6 +44,7 @@ void LightProbeModule::sync_grid(const Object *ob, ObjectHandle &handle)
|
|||
grid.view_bias = lightprobe->grid_view_bias;
|
||||
grid.facing_bias = lightprobe->grid_facing_bias;
|
||||
|
||||
grid.validity_threshold = lightprobe->grid_validity_threshold;
|
||||
grid.dilation_threshold = lightprobe->grid_dilation_threshold;
|
||||
grid.dilation_radius = lightprobe->grid_dilation_radius;
|
||||
/* Force reupload. */
|
||||
|
|
|
@ -45,6 +45,7 @@ struct IrradianceGrid : public LightProbe, IrradianceGridData {
|
|||
/** Copy of surfel density for debugging purpose. */
|
||||
float surfel_density;
|
||||
/** Copy of DNA members. */
|
||||
float validity_threshold;
|
||||
float dilation_threshold;
|
||||
float dilation_radius;
|
||||
};
|
||||
|
|
|
@ -60,6 +60,7 @@ enum eDebugMode : uint32_t {
|
|||
* Display IrradianceCache virtual offset.
|
||||
*/
|
||||
DEBUG_IRRADIANCE_CACHE_VIRTUAL_OFFSET = 6u,
|
||||
DEBUG_IRRADIANCE_CACHE_VALIDITY = 7u,
|
||||
/**
|
||||
* Show tiles depending on their status.
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
void main()
|
||||
{
|
||||
out_color = vec4(0.0, 1.0, 1.0, 0.0);
|
||||
out_color = interp_color;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,16 @@ void main()
|
|||
{
|
||||
ivec3 grid_resolution = textureSize(debug_data_tx, 0);
|
||||
ivec3 grid_sample;
|
||||
int sample_id = gl_VertexID / 2;
|
||||
int sample_id = 0;
|
||||
if (debug_mode == DEBUG_IRRADIANCE_CACHE_VALIDITY) {
|
||||
/* Points. */
|
||||
sample_id = gl_VertexID;
|
||||
}
|
||||
else if (debug_mode == DEBUG_IRRADIANCE_CACHE_VIRTUAL_OFFSET) {
|
||||
/* Lines. */
|
||||
sample_id = gl_VertexID / 2;
|
||||
}
|
||||
|
||||
grid_sample.x = (sample_id % grid_resolution.x);
|
||||
grid_sample.y = (sample_id / grid_resolution.x) % grid_resolution.y;
|
||||
grid_sample.z = (sample_id / (grid_resolution.x * grid_resolution.y));
|
||||
|
@ -14,7 +23,17 @@ void main()
|
|||
vec3 P = lightprobe_irradiance_grid_sample_position(grid_mat, grid_resolution, grid_sample);
|
||||
|
||||
vec4 debug_data = texelFetch(debug_data_tx, grid_sample, 0);
|
||||
if (debug_mode == DEBUG_IRRADIANCE_CACHE_VIRTUAL_OFFSET) {
|
||||
if (debug_mode == DEBUG_IRRADIANCE_CACHE_VALIDITY) {
|
||||
interp_color = vec4(1.0 - debug_data.r, debug_data.r, 0.0, 0.0);
|
||||
gl_PointSize = 3.0;
|
||||
if (debug_data.r > debug_value) {
|
||||
/* Only render points that are below threshold. */
|
||||
gl_Position = vec4(0.0);
|
||||
gl_PointSize = 0.0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (debug_mode == DEBUG_IRRADIANCE_CACHE_VIRTUAL_OFFSET) {
|
||||
if (is_zero(debug_data.xyz)) {
|
||||
/* Only render points that have offset. */
|
||||
gl_Position = vec4(0.0);
|
||||
|
|
|
@ -36,6 +36,15 @@ vec3 lightprobe_irradiance_grid_atlas_coord(IrradianceGridData grid_data,
|
|||
vec3 cell_lP = brick_lP - 0.5;
|
||||
vec3 cell_start = floor(cell_lP);
|
||||
vec3 cell_fract = cell_lP - cell_start;
|
||||
|
||||
/* NOTE(fclem): Use uint to avoid signed int modulo. */
|
||||
uint vis_comp = uint(cell_start.z) % 4u;
|
||||
/* Visibility is stored after the irradiance. */
|
||||
ivec3 vis_coord = ivec3(brick.atlas_coord, IRRADIANCE_GRID_BRICK_SIZE * 4) + ivec3(cell_start);
|
||||
/* Visibility is stored packed 1 cell per channel. */
|
||||
vis_coord.z -= int(vis_comp);
|
||||
float cell_visibility = texelFetch(irradiance_atlas_tx, vis_coord, 0)[vis_comp];
|
||||
int cell_visibility_bits = int(cell_visibility);
|
||||
/**
|
||||
* References:
|
||||
*
|
||||
|
@ -51,7 +60,7 @@ vec3 lightprobe_irradiance_grid_atlas_coord(IrradianceGridData grid_data,
|
|||
float trilinear_weights[8];
|
||||
float total_weight = 0.0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ivec3 sample_position = (ivec3(i) >> ivec3(0, 1, 2)) & 1;
|
||||
ivec3 sample_position = lightprobe_irradiance_grid_cell_corner(i);
|
||||
|
||||
vec3 trilinear = select(1.0 - cell_fract, cell_fract, bvec3(sample_position));
|
||||
float positional_weight = trilinear.x * trilinear.y * trilinear.z;
|
||||
|
@ -62,8 +71,7 @@ vec3 lightprobe_irradiance_grid_atlas_coord(IrradianceGridData grid_data,
|
|||
float cos_theta = (len > 1e-8) ? dot(lNg, corner_dir) : 1.0;
|
||||
float geometry_weight = saturate(cos_theta * 0.5 + 0.5);
|
||||
|
||||
/* TODO(fclem): Need to bake validity. */
|
||||
float validity_weight = 1.0;
|
||||
float validity_weight = float((cell_visibility_bits >> i) & 1);
|
||||
|
||||
/* Biases. See McGuire's presentation. */
|
||||
positional_weight += 0.001;
|
||||
|
|
|
@ -94,4 +94,23 @@ void main()
|
|||
atlas_store(sh.L1.Mn1, output_coord, 1);
|
||||
atlas_store(sh.L1.M0, output_coord, 2);
|
||||
atlas_store(sh.L1.Mp1, output_coord, 3);
|
||||
|
||||
if (gl_LocalInvocationID.z % 4 == 0u) {
|
||||
/* Encode 4 cells into one volume sample. */
|
||||
ivec4 cell_validity_bits = ivec4(0);
|
||||
/* Encode validty of each samples in the grid cell. */
|
||||
for (int cell = 0; cell < 4; cell++) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ivec3 offset = lightprobe_irradiance_grid_cell_corner(i);
|
||||
ivec3 coord = input_coord + offset + ivec3(0, 0, cell);
|
||||
float validity = texelFetch(validity_tx, coord, 0).r;
|
||||
if (validity > validity_threshold) {
|
||||
cell_validity_bits[cell] |= (1 << i);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* NOTE: We could use another sampler to reduce the memory overhead, but that would take
|
||||
* another sampler slot for forward materials. */
|
||||
atlas_store(vec4(cell_validity_bits), output_coord, 4);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,3 +35,9 @@ int lightprobe_irradiance_grid_brick_index_get(IrradianceGridData grid_data, ive
|
|||
brick_index += brick_coord.z * grid_size_in_bricks.x * grid_size_in_bricks.y;
|
||||
return brick_index;
|
||||
}
|
||||
|
||||
/* Return cell corner from a corner ID [0..7]. */
|
||||
ivec3 lightprobe_irradiance_grid_cell_corner(int cell_corner_id)
|
||||
{
|
||||
return (ivec3(cell_corner_id) >> ivec3(0, 1, 2)) & 1;
|
||||
}
|
||||
|
|
|
@ -24,12 +24,17 @@ GPU_SHADER_CREATE_INFO(eevee_debug_surfels)
|
|||
.push_constant(Type::INT, "debug_mode")
|
||||
.do_static_compilation(true);
|
||||
|
||||
GPU_SHADER_INTERFACE_INFO(eevee_debug_irradiance_grid_iface, "")
|
||||
.smooth(Type::VEC4, "interp_color");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_debug_irradiance_grid)
|
||||
.additional_info("eevee_shared", "draw_view")
|
||||
.fragment_out(0, Type::VEC4, "out_color")
|
||||
.vertex_out(eevee_debug_irradiance_grid_iface)
|
||||
.sampler(0, ImageType::FLOAT_3D, "debug_data_tx")
|
||||
.push_constant(Type::MAT4, "grid_mat")
|
||||
.push_constant(Type::INT, "debug_mode")
|
||||
.push_constant(Type::FLOAT, "debug_value")
|
||||
.vertex_source("eevee_debug_irradiance_grid_vert.glsl")
|
||||
.fragment_source("eevee_debug_irradiance_grid_frag.glsl")
|
||||
.do_static_compilation(true);
|
||||
|
@ -166,6 +171,7 @@ GPU_SHADER_CREATE_INFO(eevee_lightprobe_irradiance_load)
|
|||
IRRADIANCE_GRID_BRICK_SIZE)
|
||||
.additional_info("eevee_shared")
|
||||
.push_constant(Type::INT, "grid_index")
|
||||
.push_constant(Type::FLOAT, "validity_threshold")
|
||||
.push_constant(Type::FLOAT, "dilation_threshold")
|
||||
.push_constant(Type::FLOAT, "dilation_radius")
|
||||
.uniform_buf(0, "IrradianceGridData", "grids_infos_buf[IRRADIANCE_GRID_MAX]")
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
.grid_normal_bias = 0.3f, \
|
||||
.grid_view_bias = 0.0f, \
|
||||
.grid_facing_bias = 0.5f, \
|
||||
.grid_validity_threshold = 0.40f, \
|
||||
.grid_dilation_threshold = 0.5f, \
|
||||
.grid_dilation_radius = 1.0f, \
|
||||
.surfel_density = 1.0f, \
|
||||
|
|
|
@ -64,7 +64,7 @@ typedef struct LightProbe {
|
|||
float grid_normal_bias;
|
||||
float grid_view_bias;
|
||||
float grid_facing_bias;
|
||||
float _pad0;
|
||||
float grid_validity_threshold;
|
||||
/** Irradiance grid: Dilation. */
|
||||
float grid_dilation_threshold;
|
||||
float grid_dilation_radius;
|
||||
|
|
|
@ -217,6 +217,14 @@ static void rna_def_lightprobe(BlenderRNA *brna)
|
|||
"Number of surfels per unit distance (higher values improve quality)");
|
||||
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
|
||||
|
||||
prop = RNA_def_property(srna, "grid_validity_threshold", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Validity Threshold",
|
||||
"Ratio of front-facing surface hits under which a grid sample will "
|
||||
"not be considered for lighting");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
|
||||
|
||||
prop = RNA_def_property(srna, "grid_dilation_threshold", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Dilation Threshold",
|
||||
|
|
Loading…
Reference in New Issue