Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GPULightmapper exclude back-face triangles while calculating bounces #52618

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 37 additions & 36 deletions modules/lightmapper_rd/lm_compute.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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++) {
Expand All @@ -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
}
Expand All @@ -239,7 +231,7 @@ bool trace_ray(vec3 p_from, vec3 p_to
iters++;
}

return false;
return RAY_MISS;
}

const float PI = 3.14159265f;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -410,22 +402,25 @@ 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)));

uint tidx;
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;
vec2 uv2 = vertices.data[triangles.data[tidx].indices.z].uv;
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);

Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -477,15 +475,17 @@ 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));
accum.rgb += light_total;
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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -558,15 +558,16 @@ 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;
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;
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);

Expand Down