GPULightmapper exclude back-face triangles while calculating bounces
Edges that are at the edge of a plane, may get behind the scene and will hit back-face triangles which where included in the lighting calculations. This caused leaking of light at the edge of planes. In case a ray hits back-face triangle, it is skipped in the bounce calculations.
This commit is contained in:
parent
cd5a8f8dd4
commit
7c19684ee9
|
@ -115,7 +115,12 @@ bool ray_hits_triangle(vec3 from, vec3 dir, float max_dist, vec3 p0, vec3 p1, ve
|
|||
return (r_distance > params.bias) && (r_distance < max_dist) && all(greaterThanEqual(r_barycentric, vec3(0.0)));
|
||||
}
|
||||
|
||||
bool trace_ray(vec3 p_from, vec3 p_to
|
||||
const uint RAY_MISS = 0;
|
||||
const uint RAY_FRONT = 1;
|
||||
const uint RAY_BACK = 2;
|
||||
const uint RAY_ANY = 3;
|
||||
|
||||
uint trace_ray(vec3 p_from, vec3 p_to
|
||||
#if defined(MODE_BOUNCE_LIGHT) || defined(MODE_LIGHT_PROBES)
|
||||
,
|
||||
out uint r_triangle, out vec3 r_barycentric
|
||||
|
@ -125,6 +130,7 @@ bool trace_ray(vec3 p_from, vec3 p_to
|
|||
out float r_distance, out vec3 r_normal
|
||||
#endif
|
||||
) {
|
||||
|
||||
/* world coords */
|
||||
|
||||
vec3 rel = p_to - p_from;
|
||||
|
@ -150,10 +156,7 @@ bool trace_ray(vec3 p_from, vec3 p_to
|
|||
while (all(greaterThanEqual(icell, ivec3(0))) && all(lessThan(icell, ivec3(params.grid_size))) && iters < 1000) {
|
||||
uvec2 cell_data = texelFetch(usampler3D(grid, linear_sampler), icell, 0).xy;
|
||||
if (cell_data.x > 0) { //triangles here
|
||||
bool hit = false;
|
||||
#if defined(MODE_UNOCCLUDE)
|
||||
bool hit_backface = false;
|
||||
#endif
|
||||
uint hit = RAY_MISS;
|
||||
float best_distance = 1e20;
|
||||
|
||||
for (uint i = 0; i < cell_data.x; i++) {
|
||||
|
@ -173,57 +176,46 @@ bool trace_ray(vec3 p_from, vec3 p_to
|
|||
vec3 vtx0 = vertices.data[triangle.indices.x].position;
|
||||
vec3 vtx1 = vertices.data[triangle.indices.y].position;
|
||||
vec3 vtx2 = vertices.data[triangle.indices.z].position;
|
||||
#if defined(MODE_UNOCCLUDE)
|
||||
#if defined(MODE_UNOCCLUDE) || defined(MODE_BOUNCE_LIGHT) || defined(MODE_LIGHT_PROBES)
|
||||
vec3 normal = -normalize(cross((vtx0 - vtx1), (vtx0 - vtx2)));
|
||||
|
||||
bool backface = dot(normal, dir) >= 0.0;
|
||||
#endif
|
||||
|
||||
float distance;
|
||||
vec3 barycentric;
|
||||
|
||||
if (ray_hits_triangle(p_from, dir, rel_len, vtx0, vtx1, vtx2, distance, barycentric)) {
|
||||
#ifdef MODE_DIRECT_LIGHT
|
||||
return true; //any hit good
|
||||
return RAY_ANY; //any hit good
|
||||
#endif
|
||||
|
||||
#if defined(MODE_UNOCCLUDE)
|
||||
#if defined(MODE_UNOCCLUDE) || defined(MODE_BOUNCE_LIGHT) || defined(MODE_LIGHT_PROBES)
|
||||
if (!backface) {
|
||||
// the case of meshes having both a front and back face in the same plane is more common than
|
||||
// expected, so if this is a front-face, bias it closer to the ray origin, so it always wins over the back-face
|
||||
distance = max(params.bias, distance - params.bias);
|
||||
}
|
||||
|
||||
hit = true;
|
||||
|
||||
if (distance < best_distance) {
|
||||
hit_backface = backface;
|
||||
hit = backface ? RAY_BACK : RAY_FRONT;
|
||||
best_distance = distance;
|
||||
#if defined(MODE_UNOCCLUDE)
|
||||
r_distance = distance;
|
||||
r_normal = normal;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(MODE_BOUNCE_LIGHT) || defined(MODE_LIGHT_PROBES)
|
||||
|
||||
hit = true;
|
||||
if (distance < best_distance) {
|
||||
best_distance = distance;
|
||||
r_triangle = tidx;
|
||||
r_barycentric = barycentric;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if defined(MODE_UNOCCLUDE)
|
||||
#if defined(MODE_UNOCCLUDE) || defined(MODE_BOUNCE_LIGHT) || defined(MODE_LIGHT_PROBES)
|
||||
|
||||
if (hit) {
|
||||
return hit_backface;
|
||||
}
|
||||
#endif
|
||||
#if defined(MODE_BOUNCE_LIGHT) || defined(MODE_LIGHT_PROBES)
|
||||
if (hit) {
|
||||
return true;
|
||||
if (hit != RAY_MISS) {
|
||||
return hit;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -239,7 +231,7 @@ bool trace_ray(vec3 p_from, vec3 p_to
|
|||
iters++;
|
||||
}
|
||||
|
||||
return false;
|
||||
return RAY_MISS;
|
||||
}
|
||||
|
||||
const float PI = 3.14159265f;
|
||||
|
@ -339,7 +331,7 @@ void main() {
|
|||
continue; //no need to do anything
|
||||
}
|
||||
|
||||
if (!trace_ray(position + light_dir * params.bias, light_pos)) {
|
||||
if (trace_ray(position + light_dir * params.bias, light_pos) == RAY_MISS) {
|
||||
vec3 light = lights.data[i].color * lights.data[i].energy * attenuation;
|
||||
if (lights.data[i].static_bake) {
|
||||
static_light += light;
|
||||
|
@ -410,6 +402,7 @@ void main() {
|
|||
vec4(0.0, 0.0, 0.0, 1.0));
|
||||
#endif
|
||||
vec3 light_average = vec3(0.0);
|
||||
float active_rays = 0.0;
|
||||
for (uint i = params.ray_from; i < params.ray_to; i++) {
|
||||
vec3 ray_dir = normal_mat * vogel_hemisphere(i, params.ray_count, quick_hash(vec2(atlas_pos)));
|
||||
|
||||
|
@ -417,7 +410,8 @@ void main() {
|
|||
vec3 barycentric;
|
||||
|
||||
vec3 light = vec3(0.0);
|
||||
if (trace_ray(position + ray_dir * params.bias, position + ray_dir * length(params.world_size), tidx, barycentric)) {
|
||||
uint trace_result = trace_ray(position + ray_dir * params.bias, position + ray_dir * length(params.world_size), tidx, barycentric);
|
||||
if (trace_result == RAY_FRONT) {
|
||||
//hit a triangle
|
||||
vec2 uv0 = vertices.data[triangles.data[tidx].indices.x].uv;
|
||||
vec2 uv1 = vertices.data[triangles.data[tidx].indices.y].uv;
|
||||
|
@ -425,7 +419,8 @@ void main() {
|
|||
vec3 uvw = vec3(barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2, float(triangles.data[tidx].slice));
|
||||
|
||||
light = textureLod(sampler2DArray(source_light, linear_sampler), uvw, 0.0).rgb;
|
||||
} else if (params.env_transform[0][3] == 0.0) { // Use env_transform[0][3] to indicate when we are computing the first bounce
|
||||
active_rays += 1.0;
|
||||
} else if (trace_result == RAY_MISS && params.env_transform[0][3] == 0.0) { // Use env_transform[0][3] to indicate when we are computing the first bounce
|
||||
// Did not hit a triangle, reach out for the sky
|
||||
vec3 sky_dir = normalize(mat3(params.env_transform) * ray_dir);
|
||||
|
||||
|
@ -439,6 +434,7 @@ void main() {
|
|||
st /= vec2(PI * 2.0, PI);
|
||||
|
||||
light = textureLod(sampler2D(environment, linear_sampler), st, 0.0).rgb;
|
||||
active_rays += 1.0;
|
||||
}
|
||||
|
||||
light_average += light;
|
||||
|
@ -462,7 +458,9 @@ void main() {
|
|||
if (params.ray_from == 0) {
|
||||
light_total = vec3(0.0);
|
||||
} else {
|
||||
light_total = imageLoad(bounce_accum, ivec3(atlas_pos, params.atlas_slice)).rgb;
|
||||
vec4 accum = imageLoad(bounce_accum, ivec3(atlas_pos, params.atlas_slice));
|
||||
light_total = accum.rgb;
|
||||
active_rays += accum.a;
|
||||
}
|
||||
|
||||
light_total += light_average;
|
||||
|
@ -477,7 +475,9 @@ void main() {
|
|||
|
||||
#endif
|
||||
if (params.ray_to == params.ray_count) {
|
||||
light_total /= float(params.ray_count);
|
||||
if (active_rays > 0) {
|
||||
light_total /= active_rays;
|
||||
}
|
||||
imageStore(dest_light, ivec3(atlas_pos, params.atlas_slice), vec4(light_total, 1.0));
|
||||
#ifndef USE_SH_LIGHTMAPS
|
||||
vec4 accum = imageLoad(accum_light, ivec3(atlas_pos, params.atlas_slice));
|
||||
|
@ -485,7 +485,7 @@ void main() {
|
|||
imageStore(accum_light, ivec3(atlas_pos, params.atlas_slice), accum);
|
||||
#endif
|
||||
} else {
|
||||
imageStore(bounce_accum, ivec3(atlas_pos, params.atlas_slice), vec4(light_total, 1.0));
|
||||
imageStore(bounce_accum, ivec3(atlas_pos, params.atlas_slice), vec4(light_total, active_rays));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -518,7 +518,7 @@ void main() {
|
|||
float d;
|
||||
vec3 norm;
|
||||
|
||||
if (trace_ray(base_pos, ray_to, d, norm)) {
|
||||
if (trace_ray(base_pos, ray_to, d, norm) == RAY_BACK) {
|
||||
if (d < min_d) {
|
||||
vertex_pos = base_pos + rays[i] * d + norm * params.bias * 10.0; //this bias needs to be greater than the regular bias, because otherwise later, rays will go the other side when pointing back.
|
||||
min_d = d;
|
||||
|
@ -558,7 +558,8 @@ void main() {
|
|||
vec3 barycentric;
|
||||
vec3 light;
|
||||
|
||||
if (trace_ray(position + ray_dir * params.bias, position + ray_dir * length(params.world_size), tidx, barycentric)) {
|
||||
uint trace_result = trace_ray(position + ray_dir * params.bias, position + ray_dir * length(params.world_size), tidx, barycentric);
|
||||
if (trace_result == RAY_FRONT) {
|
||||
vec2 uv0 = vertices.data[triangles.data[tidx].indices.x].uv;
|
||||
vec2 uv1 = vertices.data[triangles.data[tidx].indices.y].uv;
|
||||
vec2 uv2 = vertices.data[triangles.data[tidx].indices.z].uv;
|
||||
|
@ -566,7 +567,7 @@ void main() {
|
|||
|
||||
light = textureLod(sampler2DArray(source_light, linear_sampler), uvw, 0.0).rgb;
|
||||
light += textureLod(sampler2DArray(source_direct_light, linear_sampler), uvw, 0.0).rgb;
|
||||
} else {
|
||||
} else if (trace_result == RAY_MISS) {
|
||||
//did not hit a triangle, reach out for the sky
|
||||
vec3 sky_dir = normalize(mat3(params.env_transform) * ray_dir);
|
||||
|
||||
|
|
Loading…
Reference in New Issue