From 9e28dd327740b50db0b97e8b51a5c064e2a3dfb4 Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Tue, 4 Nov 2025 21:51:54 -0500 Subject: [PATCH 1/6] Solari fixes --- crates/bevy_solari/src/realtime/restir_gi.wgsl | 2 +- crates/bevy_solari/src/realtime/world_cache_update.wgsl | 2 +- crates/bevy_solari/src/scene/brdf.wgsl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_solari/src/realtime/restir_gi.wgsl b/crates/bevy_solari/src/realtime/restir_gi.wgsl index 4fcf537a496b4..7d3a60ac9e6d3 100644 --- a/crates/bevy_solari/src/realtime/restir_gi.wgsl +++ b/crates/bevy_solari/src/realtime/restir_gi.wgsl @@ -274,7 +274,7 @@ fn merge_reservoirs( ); // Don't merge samples with huge jacobians, as it explodes the variance - if canonical_target_function_other_sample_jacobian > 2.0 { + if canonical_target_function_other_sample_jacobian > 1.2 { return ReservoirMergeResult(canonical_reservoir, canonical_sample_radiance); } diff --git a/crates/bevy_solari/src/realtime/world_cache_update.wgsl b/crates/bevy_solari/src/realtime/world_cache_update.wgsl index 44a387c8fce71..87638f9d8dc03 100644 --- a/crates/bevy_solari/src/realtime/world_cache_update.wgsl +++ b/crates/bevy_solari/src/realtime/world_cache_update.wgsl @@ -19,7 +19,7 @@ struct PushConstants { frame_index: u32, reset: u32 } var constants: PushConstants; -const DIRECT_LIGHT_SAMPLE_COUNT: u32 = 32u; +const DIRECT_LIGHT_SAMPLE_COUNT: u32 = 8u; @compute @workgroup_size(1024, 1, 1) fn sample_radiance(@builtin(workgroup_id) workgroup_id: vec3, @builtin(global_invocation_id) active_cell_id: vec3) { diff --git a/crates/bevy_solari/src/scene/brdf.wgsl b/crates/bevy_solari/src/scene/brdf.wgsl index dd78e83c7ff88..b6fae4b6b13bf 100644 --- a/crates/bevy_solari/src/scene/brdf.wgsl +++ b/crates/bevy_solari/src/scene/brdf.wgsl @@ -50,7 +50,7 @@ fn evaluate_specular_brdf( let F_ab = F_AB(perceptual_roughness, NdotV); let D = D_GGX(roughness, NdotH); - let Vs = V_SmithGGXCorrelated(roughness, NdotV, NdotL); + let Vs = saturate(V_SmithGGXCorrelated(roughness, NdotV, NdotL)); let F = fresnel(F0, LdotH); return specular_multiscatter(D, Vs, F, F0, F_ab, 1.0); } From 0dfa41774e221ac751874d3da8fb5b3546f6491d Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Fri, 7 Nov 2025 09:55:04 -0500 Subject: [PATCH 2/6] Properly fix NaNs --- crates/bevy_solari/src/realtime/gbuffer_utils.wgsl | 2 +- crates/bevy_solari/src/realtime/specular_gi.wgsl | 2 +- crates/bevy_solari/src/scene/brdf.wgsl | 10 ++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/crates/bevy_solari/src/realtime/gbuffer_utils.wgsl b/crates/bevy_solari/src/realtime/gbuffer_utils.wgsl index a9d513f77e8e1..43e0a314ba020 100644 --- a/crates/bevy_solari/src/realtime/gbuffer_utils.wgsl +++ b/crates/bevy_solari/src/realtime/gbuffer_utils.wgsl @@ -22,7 +22,7 @@ fn gpixel_resolve(gpixel: vec4, depth: f32, pixel_id: vec2, view_size: let roughness = clamp(perceptual_roughness * perceptual_roughness, 0.001, 1.0); let props = unpack4x8unorm(gpixel.b); let reflectance = vec3(props.r); - let metallic = props.g; + let metallic = saturate(props.g); // TODO: Not sure why saturate is needed here to prevent NaNs let emissive = rgb9e5_to_vec3_(gpixel.g); let material = ResolvedMaterial(base_color, emissive, reflectance, perceptual_roughness, roughness, metallic); diff --git a/crates/bevy_solari/src/realtime/specular_gi.wgsl b/crates/bevy_solari/src/realtime/specular_gi.wgsl index 9900b190db9fc..4ddeaff08b1b7 100644 --- a/crates/bevy_solari/src/realtime/specular_gi.wgsl +++ b/crates/bevy_solari/src/realtime/specular_gi.wgsl @@ -52,7 +52,7 @@ fn specular_gi(@builtin(global_invocation_id) global_id: vec3) { } let brdf = evaluate_specular_brdf(surface.world_normal, wo, wi, surface.material.base_color, surface.material.metallic, - surface.material.reflectance, surface.material.perceptual_roughness, surface.material.roughness); + surface.material.reflectance, surface.material.perceptual_roughness); let cos_theta = saturate(dot(wi, surface.world_normal)); radiance *= brdf * cos_theta * view.exposure; diff --git a/crates/bevy_solari/src/scene/brdf.wgsl b/crates/bevy_solari/src/scene/brdf.wgsl index b6fae4b6b13bf..51ee63c782dd4 100644 --- a/crates/bevy_solari/src/scene/brdf.wgsl +++ b/crates/bevy_solari/src/scene/brdf.wgsl @@ -20,7 +20,6 @@ fn evaluate_brdf( material.metallic, material.reflectance, material.perceptual_roughness, - material.roughness, ); return diffuse_brdf + specular_brdf; } @@ -38,8 +37,11 @@ fn evaluate_specular_brdf( metallic: f32, reflectance: vec3, perceptual_roughness: f32, - roughness: f32, ) -> vec3 { + // Clamp roughness to prevent NaNs + let perceptual_roughness_clamped = clamp(perceptual_roughness, 0.0316227766, 1.0); + let roughness = perceptual_roughness_clamped * perceptual_roughness_clamped; + let H = normalize(L + V); let NdotL = saturate(dot(N, L)); let NdotH = saturate(dot(N, H)); @@ -47,10 +49,10 @@ fn evaluate_specular_brdf( let NdotV = max(dot(N, V), 0.0001); let F0 = calculate_F0(base_color, metallic, reflectance); - let F_ab = F_AB(perceptual_roughness, NdotV); + let F_ab = F_AB(perceptual_roughness_clamped, NdotV); let D = D_GGX(roughness, NdotH); - let Vs = saturate(V_SmithGGXCorrelated(roughness, NdotV, NdotL)); + let Vs = V_SmithGGXCorrelated(roughness, NdotV, NdotL); let F = fresnel(F0, LdotH); return specular_multiscatter(D, Vs, F, F0, F_ab, 1.0); } From 4a7376dc2b24bf96ed739c3d1e8b6b57adfd806f Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Fri, 7 Nov 2025 10:14:33 -0500 Subject: [PATCH 3/6] Revert world cache changes --- DLSS | 1 + crates/bevy_solari/src/realtime/world_cache_update.wgsl | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 160000 DLSS diff --git a/DLSS b/DLSS new file mode 160000 index 0000000000000..9a6b48a79d5ae --- /dev/null +++ b/DLSS @@ -0,0 +1 @@ +Subproject commit 9a6b48a79d5ae41bf1481d0c83d73859ec481bd2 diff --git a/crates/bevy_solari/src/realtime/world_cache_update.wgsl b/crates/bevy_solari/src/realtime/world_cache_update.wgsl index 87638f9d8dc03..44a387c8fce71 100644 --- a/crates/bevy_solari/src/realtime/world_cache_update.wgsl +++ b/crates/bevy_solari/src/realtime/world_cache_update.wgsl @@ -19,7 +19,7 @@ struct PushConstants { frame_index: u32, reset: u32 } var constants: PushConstants; -const DIRECT_LIGHT_SAMPLE_COUNT: u32 = 8u; +const DIRECT_LIGHT_SAMPLE_COUNT: u32 = 32u; @compute @workgroup_size(1024, 1, 1) fn sample_radiance(@builtin(workgroup_id) workgroup_id: vec3, @builtin(global_invocation_id) active_cell_id: vec3) { From d88fa9ddb4d65df2aa894ff7c03df2910bc3eafd Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Fri, 7 Nov 2025 10:15:56 -0500 Subject: [PATCH 4/6] Remove subproject --- DLSS | 1 - 1 file changed, 1 deletion(-) delete mode 160000 DLSS diff --git a/DLSS b/DLSS deleted file mode 160000 index 9a6b48a79d5ae..0000000000000 --- a/DLSS +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9a6b48a79d5ae41bf1481d0c83d73859ec481bd2 From bb9e690067f0067403b940bc3b0eb39ce01bde26 Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Tue, 11 Nov 2025 15:03:20 -0500 Subject: [PATCH 5/6] Move around roughness clamp --- crates/bevy_solari/src/pathtracer/pathtracer.wgsl | 4 ++-- crates/bevy_solari/src/realtime/gbuffer_utils.wgsl | 5 +++-- crates/bevy_solari/src/realtime/specular_gi.wgsl | 2 +- crates/bevy_solari/src/scene/brdf.wgsl | 8 +++----- .../bevy_solari/src/scene/raytracing_scene_bindings.wgsl | 5 ++++- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/crates/bevy_solari/src/pathtracer/pathtracer.wgsl b/crates/bevy_solari/src/pathtracer/pathtracer.wgsl index 68cb45e207ffb..77fc834b2f5a5 100644 --- a/crates/bevy_solari/src/pathtracer/pathtracer.wgsl +++ b/crates/bevy_solari/src/pathtracer/pathtracer.wgsl @@ -104,7 +104,7 @@ fn importance_sample_next_bounce(wo: vec3, ray_hit: ResolvedRayHitFull, rng if is_perfectly_specular { return NextBounce(reflect(-wo, ray_hit.world_normal), 1.0, true); } - let diffuse_weight = mix(mix(0.4f, 0.9f, ray_hit.material.perceptual_roughness), 0.f, ray_hit.material.metallic); + let diffuse_weight = mix(mix(0.4, 0.9, ray_hit.material.perceptual_roughness), 0.0, ray_hit.material.metallic); let specular_weight = 1.0 - diffuse_weight; let TBN = calculate_tbn_mikktspace(ray_hit.world_normal, ray_hit.world_tangent); @@ -133,7 +133,7 @@ fn importance_sample_next_bounce(wo: vec3, ray_hit: ResolvedRayHitFull, rng } fn brdf_pdf(wo: vec3, wi: vec3, ray_hit: ResolvedRayHitFull) -> f32 { - let diffuse_weight = mix(mix(0.4f, 0.9f, ray_hit.material.roughness), 0.f, ray_hit.material.metallic); + let diffuse_weight = mix(mix(0.4, 0.9, ray_hit.material.roughness), 0.0, ray_hit.material.metallic); let specular_weight = 1.0 - diffuse_weight; let TBN = calculate_tbn_mikktspace(ray_hit.world_normal, ray_hit.world_tangent); diff --git a/crates/bevy_solari/src/realtime/gbuffer_utils.wgsl b/crates/bevy_solari/src/realtime/gbuffer_utils.wgsl index 43e0a314ba020..21028a4b5cb32 100644 --- a/crates/bevy_solari/src/realtime/gbuffer_utils.wgsl +++ b/crates/bevy_solari/src/realtime/gbuffer_utils.wgsl @@ -18,8 +18,9 @@ fn gpixel_resolve(gpixel: vec4, depth: f32, pixel_id: vec2, view_size: let base_rough = unpack4x8unorm(gpixel.r); let base_color = pow(base_rough.rgb, vec3(2.2)); - let perceptual_roughness = base_rough.a; - let roughness = clamp(perceptual_roughness * perceptual_roughness, 0.001, 1.0); + // Clamp roughness to prevent NaNs + let perceptual_roughness = clamp(base_rough.a, 0.0316227766, 1.0); + let roughness = perceptual_roughness * perceptual_roughness; let props = unpack4x8unorm(gpixel.b); let reflectance = vec3(props.r); let metallic = saturate(props.g); // TODO: Not sure why saturate is needed here to prevent NaNs diff --git a/crates/bevy_solari/src/realtime/specular_gi.wgsl b/crates/bevy_solari/src/realtime/specular_gi.wgsl index 4ddeaff08b1b7..9900b190db9fc 100644 --- a/crates/bevy_solari/src/realtime/specular_gi.wgsl +++ b/crates/bevy_solari/src/realtime/specular_gi.wgsl @@ -52,7 +52,7 @@ fn specular_gi(@builtin(global_invocation_id) global_id: vec3) { } let brdf = evaluate_specular_brdf(surface.world_normal, wo, wi, surface.material.base_color, surface.material.metallic, - surface.material.reflectance, surface.material.perceptual_roughness); + surface.material.reflectance, surface.material.perceptual_roughness, surface.material.roughness); let cos_theta = saturate(dot(wi, surface.world_normal)); radiance *= brdf * cos_theta * view.exposure; diff --git a/crates/bevy_solari/src/scene/brdf.wgsl b/crates/bevy_solari/src/scene/brdf.wgsl index 51ee63c782dd4..dd78e83c7ff88 100644 --- a/crates/bevy_solari/src/scene/brdf.wgsl +++ b/crates/bevy_solari/src/scene/brdf.wgsl @@ -20,6 +20,7 @@ fn evaluate_brdf( material.metallic, material.reflectance, material.perceptual_roughness, + material.roughness, ); return diffuse_brdf + specular_brdf; } @@ -37,11 +38,8 @@ fn evaluate_specular_brdf( metallic: f32, reflectance: vec3, perceptual_roughness: f32, + roughness: f32, ) -> vec3 { - // Clamp roughness to prevent NaNs - let perceptual_roughness_clamped = clamp(perceptual_roughness, 0.0316227766, 1.0); - let roughness = perceptual_roughness_clamped * perceptual_roughness_clamped; - let H = normalize(L + V); let NdotL = saturate(dot(N, L)); let NdotH = saturate(dot(N, H)); @@ -49,7 +47,7 @@ fn evaluate_specular_brdf( let NdotV = max(dot(N, V), 0.0001); let F0 = calculate_F0(base_color, metallic, reflectance); - let F_ab = F_AB(perceptual_roughness_clamped, NdotV); + let F_ab = F_AB(perceptual_roughness, NdotV); let D = D_GGX(roughness, NdotH); let Vs = V_SmithGGXCorrelated(roughness, NdotV, NdotL); diff --git a/crates/bevy_solari/src/scene/raytracing_scene_bindings.wgsl b/crates/bevy_solari/src/scene/raytracing_scene_bindings.wgsl index 9e346bbf2d783..6983483e3c261 100644 --- a/crates/bevy_solari/src/scene/raytracing_scene_bindings.wgsl +++ b/crates/bevy_solari/src/scene/raytracing_scene_bindings.wgsl @@ -142,7 +142,10 @@ fn resolve_material(material: Material, uv: vec2) -> ResolvedMaterial { m.perceptual_roughness *= metallic_roughness.g; m.metallic *= metallic_roughness.b; } - m.roughness = clamp(m.perceptual_roughness * m.perceptual_roughness, 0.001, 1.0); + + // Clamp roughness to prevent NaNs + m.perceptual_roughness = clamp(m.perceptual_roughness, 0.0316227766, 1.0); + m.roughness = m.perceptual_roughness * m.perceptual_roughness; return m; } From 81b53e04461dab2f5d91df92ee34250cdf292f62 Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Fri, 21 Nov 2025 10:05:33 -0500 Subject: [PATCH 6/6] Add comment --- crates/bevy_solari/src/realtime/gbuffer_utils.wgsl | 2 +- crates/bevy_solari/src/scene/raytracing_scene_bindings.wgsl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_solari/src/realtime/gbuffer_utils.wgsl b/crates/bevy_solari/src/realtime/gbuffer_utils.wgsl index 21028a4b5cb32..baf1556806b6e 100644 --- a/crates/bevy_solari/src/realtime/gbuffer_utils.wgsl +++ b/crates/bevy_solari/src/realtime/gbuffer_utils.wgsl @@ -19,7 +19,7 @@ fn gpixel_resolve(gpixel: vec4, depth: f32, pixel_id: vec2, view_size: let base_rough = unpack4x8unorm(gpixel.r); let base_color = pow(base_rough.rgb, vec3(2.2)); // Clamp roughness to prevent NaNs - let perceptual_roughness = clamp(base_rough.a, 0.0316227766, 1.0); + let perceptual_roughness = clamp(base_rough.a, 0.0316227766, 1.0); // Clamp roughness to 0.001 let roughness = perceptual_roughness * perceptual_roughness; let props = unpack4x8unorm(gpixel.b); let reflectance = vec3(props.r); diff --git a/crates/bevy_solari/src/scene/raytracing_scene_bindings.wgsl b/crates/bevy_solari/src/scene/raytracing_scene_bindings.wgsl index 6983483e3c261..8b1e875fc5423 100644 --- a/crates/bevy_solari/src/scene/raytracing_scene_bindings.wgsl +++ b/crates/bevy_solari/src/scene/raytracing_scene_bindings.wgsl @@ -144,7 +144,7 @@ fn resolve_material(material: Material, uv: vec2) -> ResolvedMaterial { } // Clamp roughness to prevent NaNs - m.perceptual_roughness = clamp(m.perceptual_roughness, 0.0316227766, 1.0); + m.perceptual_roughness = clamp(m.perceptual_roughness, 0.0316227766, 1.0); // Clamp roughness to 0.001 m.roughness = m.perceptual_roughness * m.perceptual_roughness; return m;