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