-
-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Improve layering in the solari BRDF #24243
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -5,7 +5,7 @@ enable wgpu_ray_query; | |||||
| #import bevy_pbr::utils::{rand_f, rand_vec2f} | ||||||
| #import bevy_render::maths::{PI, orthonormalize} | ||||||
| #import bevy_render::view::View | ||||||
| #import bevy_solari::brdf::{evaluate_brdf, evaluate_and_sample_brdf, fresnel} | ||||||
| #import bevy_solari::brdf::{evaluate_brdf, evaluate_and_sample_brdf, lobe_reflectances} | ||||||
| #import bevy_solari::sampling::{sample_random_light, random_emissive_light_pdf, ggx_vndf_pdf, power_heuristic} | ||||||
| #import bevy_solari::scene_bindings::{trace_ray, resolve_ray_hit_full, ResolvedRayHitFull, RAY_T_MIN, RAY_T_MAX, MIRROR_ROUGHNESS_THRESHOLD} | ||||||
|
|
||||||
|
|
@@ -98,10 +98,9 @@ fn pathtrace(@builtin(global_invocation_id) global_id: vec3<u32>) { | |||||
| fn brdf_pdf(wo: vec3<f32>, wi: vec3<f32>, ray_hit: ResolvedRayHitFull) -> f32 { | ||||||
| let NdotV = max(dot(ray_hit.world_normal, wo), 0.0001); | ||||||
| let F0 = calculate_F0(ray_hit.material.base_color, ray_hit.material.metallic, vec3(ray_hit.material.reflectance)); | ||||||
| let df = 1.0 - luminance(fresnel(F0, NdotV)); | ||||||
|
|
||||||
| let diffuse_weight = mix(df, 0.0, ray_hit.material.metallic); | ||||||
| let specular_weight = 1.0 - diffuse_weight; | ||||||
| let rho = lobe_reflectances(F0, ray_hit.material, NdotV); | ||||||
| let specular_weight = luminance(rho.rho_spec) / luminance(rho.rho_spec + rho.rho_diff); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if the denominator is 0, because you have a pure black material? |
||||||
| let diffuse_weight = 1 - specular_weight; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| let TBN = orthonormalize(ray_hit.world_normal); | ||||||
| let T = TBN[0]; | ||||||
|
|
@@ -113,6 +112,5 @@ fn brdf_pdf(wo: vec3<f32>, wi: vec3<f32>, ray_hit: ResolvedRayHitFull) -> f32 { | |||||
|
|
||||||
| let diffuse_pdf = wi_tangent.z / PI; | ||||||
| let specular_pdf = ggx_vndf_pdf(wo_tangent, wi_tangent, ray_hit.material.roughness); | ||||||
| let pdf = (diffuse_weight * diffuse_pdf) + (specular_weight * specular_pdf); | ||||||
| return pdf; | ||||||
| return specular_weight * specular_pdf + diffuse_weight * diffuse_pdf; | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,7 +4,7 @@ enable wgpu_ray_query; | |||||||||||||||||
|
|
||||||||||||||||||
| #import bevy_core_pipeline::tonemapping::tonemapping_luminance as luminance | ||||||||||||||||||
| #import bevy_pbr::lighting::{D_GGX, V_SmithGGXCorrelated, specular_multiscatter} | ||||||||||||||||||
| #import bevy_pbr::pbr_functions::{calculate_diffuse_color, calculate_F0} | ||||||||||||||||||
| #import bevy_pbr::pbr_functions::calculate_F0 | ||||||||||||||||||
| #import bevy_pbr::utils::{rand_f, sample_cosine_hemisphere} | ||||||||||||||||||
| #import bevy_render::maths::{PI, orthonormalize} | ||||||||||||||||||
| #import bevy_solari::sampling::{sample_ggx_vndf, ggx_vndf_pdf, ggx_vndf_sample_invalid} | ||||||||||||||||||
|
|
@@ -16,6 +16,22 @@ struct EvaluateAndSampleBrdfResult { | |||||||||||||||||
| pdf: f32, | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| struct LobeReflectances { | ||||||||||||||||||
| rho_spec: vec3<f32>, | ||||||||||||||||||
| rho_diff: vec3<f32>, | ||||||||||||||||||
| } | ||||||||||||||||||
|
Comment on lines
+19
to
+22
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
|
|
||||||||||||||||||
| // Hemispherical reflectance of each lobe | ||||||||||||||||||
| fn lobe_reflectances(F0: vec3<f32>, material: ResolvedMaterial, NdotV: f32) -> LobeReflectances { | ||||||||||||||||||
| let F_ab = F_AB(material.perceptual_roughness, NdotV); | ||||||||||||||||||
| let ms_factor = 1.0 / (F_ab.x + F_ab.y) - 1.0; | ||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
| let rho_spec = (F0 * F_ab.x + vec3(F_ab.y)) * (vec3(1.0) + F0 * ms_factor); | ||||||||||||||||||
| return LobeReflectances( | ||||||||||||||||||
| rho_spec, | ||||||||||||||||||
| (1.0 - material.metallic) * (vec3(1.0) - rho_spec) * material.base_color, | ||||||||||||||||||
| ); | ||||||||||||||||||
|
Comment on lines
+28
to
+32
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you need the vec3() around the 1.0? |
||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| fn evaluate_and_sample_brdf( | ||||||||||||||||||
| wo: vec3<f32>, | ||||||||||||||||||
| world_normal: vec3<f32>, | ||||||||||||||||||
|
|
@@ -25,10 +41,9 @@ fn evaluate_and_sample_brdf( | |||||||||||||||||
| let NdotV = dot(world_normal, wo); | ||||||||||||||||||
| if NdotV < 0.0001 { return EvaluateAndSampleBrdfResult(vec3(0.0), vec3(0.0), 0.0); } | ||||||||||||||||||
| let F0 = calculate_F0(material.base_color, material.metallic, vec3(material.reflectance)); | ||||||||||||||||||
| let df = 1.0 - luminance(fresnel(F0, NdotV)); | ||||||||||||||||||
|
|
||||||||||||||||||
| let diffuse_weight = mix(df, 0.0, material.metallic); | ||||||||||||||||||
| let specular_weight = 1.0 - diffuse_weight; | ||||||||||||||||||
| let rho = lobe_reflectances(F0, material, NdotV); | ||||||||||||||||||
| let specular_weight = luminance(rho.rho_spec) / luminance(rho.rho_spec + rho.rho_diff); | ||||||||||||||||||
| let diffuse_weight = 1 - specular_weight; | ||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
|
|
||||||||||||||||||
| let TBN = orthonormalize(world_normal); | ||||||||||||||||||
| let T = TBN[0]; | ||||||||||||||||||
|
|
@@ -49,19 +64,17 @@ fn evaluate_and_sample_brdf( | |||||||||||||||||
| return EvaluateAndSampleBrdfResult(vec3(0.0), vec3(0.0), 0.0); | ||||||||||||||||||
| } | ||||||||||||||||||
| wi = wi_tangent.x * T + wi_tangent.y * B + wi_tangent.z * N; | ||||||||||||||||||
|
|
||||||||||||||||||
| // Mirror specular is a delta function | ||||||||||||||||||
| if material.roughness <= MIRROR_ROUGHNESS_THRESHOLD { | ||||||||||||||||||
| return EvaluateAndSampleBrdfResult(wi, rho.rho_spec / specular_weight, 1.0); | ||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Didn't we return INF for the PDF before for mirrors? I'm trying to remember how to handle mirrors, it's hurting my brain... |
||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| let diffuse_pdf = wi_tangent.z / PI; | ||||||||||||||||||
| let specular_pdf = ggx_vndf_pdf(wo_tangent, wi_tangent, material.roughness); | ||||||||||||||||||
| let pdf = (diffuse_weight * diffuse_pdf) + (specular_weight * specular_pdf); | ||||||||||||||||||
|
|
||||||||||||||||||
| var throughput = evaluate_brdf(wo, wi, world_normal, material); | ||||||||||||||||||
| if diffuse_selected || material.roughness > MIRROR_ROUGHNESS_THRESHOLD { | ||||||||||||||||||
| throughput /= pdf; | ||||||||||||||||||
| } else { | ||||||||||||||||||
| throughput /= specular_weight; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| let pdf = specular_weight * specular_pdf + diffuse_weight * diffuse_pdf; | ||||||||||||||||||
| let throughput = evaluate_brdf(wo, wi, world_normal, material) / pdf; | ||||||||||||||||||
| return EvaluateAndSampleBrdfResult(wi, throughput, pdf); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
@@ -75,15 +88,12 @@ fn evaluate_brdf( | |||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| fn evaluate_diffuse_brdf(wo: vec3<f32>, wi: vec3<f32>, world_normal: vec3<f32>, material: ResolvedMaterial) -> vec3<f32> { | ||||||||||||||||||
| let diffuse_color = calculate_diffuse_color(material.base_color, material.metallic, 0.0, 0.0) / PI; | ||||||||||||||||||
|
|
||||||||||||||||||
| let NdotL = dot(world_normal, wi); | ||||||||||||||||||
| let NdotV = dot(world_normal, wo); | ||||||||||||||||||
| if NdotL < 0.0001 || NdotV < 0.0001 { return vec3(0.0); } | ||||||||||||||||||
| let F0 = calculate_F0(material.base_color, material.metallic, vec3(material.reflectance)); | ||||||||||||||||||
| let layering = (1.0 - fresnel(F0, NdotL)) * (1.0 - fresnel(F0, NdotV)); | ||||||||||||||||||
|
|
||||||||||||||||||
| return diffuse_color * layering * NdotL; | ||||||||||||||||||
| let rho = lobe_reflectances(F0, material, NdotV); | ||||||||||||||||||
| return rho.rho_diff / PI * NdotL; | ||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is PI here, and not part of rho_diffuse? |
||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| fn evaluate_specular_brdf(wo: vec3<f32>, wi: vec3<f32>, world_normal: vec3<f32>, material: ResolvedMaterial) -> vec3<f32> { | ||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does anything in evaluate_specular_brdf need to change, similar to how evaluate_diffuse_brdf relies on rho_diffuse? |
||||||||||||||||||
|
|
@@ -93,7 +103,6 @@ fn evaluate_specular_brdf(wo: vec3<f32>, wi: vec3<f32>, world_normal: vec3<f32>, | |||||||||||||||||
| let LdotH = dot(wi, H); | ||||||||||||||||||
| let NdotV = dot(world_normal, wo); | ||||||||||||||||||
| if NdotL < 0.0001 || NdotH < 0.0001 || LdotH < 0.0001 || NdotV < 0.0001 { return vec3(0.0); } | ||||||||||||||||||
|
|
||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add back the newline please! |
||||||||||||||||||
| let F0 = calculate_F0(material.base_color, material.metallic, vec3(material.reflectance)); | ||||||||||||||||||
| let F = fresnel(F0, LdotH); | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move brdf_pdf into brdf.wgsl