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.
2 changed files with 59 additions and 3 deletions
Showing only changes of commit 5de76bbbff - Show all commits

View File

@ -275,7 +275,19 @@ void IrradianceBake::propagate_light_sample()
View ray_view = {"RayProjectionView"};
ray_view.sync(viewmat, winmat);
list_info_buf_.ray_grid_size = math::max(int2(1), int2(surfel_density_ * (max - min)));
/* This avoid light leaking by making sure that for one surface there will always be at least 1
* surfel capture inside a ray list. Since the surface with the maximum distance (after
* projection) between adjacent surfels is a slope that goes through 3 corners of a cube,
* the distance the grid needs to cover is the diagonal of a cube face.
*
* The lower the number the more surfels it clumps together in the same surfel-list.
* Biasing the grid_density like that will create many invalid link between coplanar surfels.
* These are dealt with during the list sorting pass.
*
* We add an extra epsilon just in case. We really need this step to be leak free. */
const float max_distance_between_neighbor_surfels_inv = M_SQRT1_2 - 1e-4;
const float ray_grid_density = surfel_density_ * max_distance_between_neighbor_surfels_inv;
list_info_buf_.ray_grid_size = math::max(int2(1), int2(ray_grid_density * (max - min)));
list_info_buf_.list_max = list_info_buf_.ray_grid_size.x * list_info_buf_.ray_grid_size.y;
list_info_buf_.push_update();

View File

@ -6,8 +6,6 @@
*
* Sort by increasing `ray_distance`. Start of list is smallest value.
*
* Outputs a flat array of surfel indices. Each ray is a range inside the array. This allows
* parallel processing in the light propagation phase.
* Dispatched as 1 thread per list.
*/
@ -62,6 +60,18 @@ void list_insert_link_before(inout List list, int next_link, int new_link)
}
}
/**
* Return true if link from `surfel[a]` to `surfel[b]` is valid.
* WARNING: this function is not commutative : `f(a, b) != f(b, a)`
*/
bool is_valid_surfel_link(int a, int b)
{
vec3 link_vector = normalize(surfel_buf[b].position - surfel_buf[a].position);
float link_angle_cos = dot(surfel_buf[a].normal, link_vector);
bool is_coplanar = abs(link_angle_cos) < 1.0e-3;
return !is_coplanar;
}
void main()
{
int list_index = int(gl_GlobalInvocationID);
@ -112,4 +122,38 @@ void main()
list_add_tail(sorted_list, i);
}
}
/* 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.
*
* This is a really important step since it allows to clump more surfels into one ray list and
* avoid light leaking through surfaces. If we don't disconnect coplanar surfels, we loose many
* good rays by evaluating null radiance transfer between the coplanar surfels for rays that
* are not directly perpendicular to the surface. */
/* Mutable foreach. */
for (int i = sorted_list.first, next; i > -1; i = next) {
next = surfel_buf[i].next;
int valid_next = surfel_buf[i].next;
int valid_prev = surfel_buf[i].prev;
/* Search the list for the first valid next and previous surfel. */
while (valid_next > -1) {
if (is_valid_surfel_link(i, valid_next)) {
break;
}
valid_next = surfel_buf[valid_next].next;
}
while (valid_prev > -1) {
if (is_valid_surfel_link(i, valid_prev)) {
break;
}
valid_prev = surfel_buf[valid_prev].prev;
}
surfel_buf[i].next = valid_next;
surfel_buf[i].prev = valid_prev;
}
}