-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Changes from 6 commits
1cb0fe4
53c1416
6afa995
33c85db
f877012
4c523b3
5f63ce7
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 |
|---|---|---|
|
|
@@ -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 { | ||
| specular: vec3<f32>, | ||
| diffuse: vec3<f32>, | ||
| } | ||
|
|
||
| // 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 multiscattering_factor = 1.0 / (F_ab.x + F_ab.y) - 1.0; | ||
| let rho_specular = (F0 * F_ab.x + F_ab.y) * (1.0 + F0 * multiscattering_factor); | ||
| return LobeReflectances( | ||
| rho_specular, | ||
| (1.0 - material.metallic) * (1.0 - rho_specular) * material.base_color, | ||
| ); | ||
| } | ||
|
|
||
| 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.specular) / luminance(rho.specular + rho.diffuse); | ||
| let diffuse_weight = 1.0 - specular_weight; | ||
|
|
||
| let TBN = orthonormalize(world_normal); | ||
| let T = TBN[0]; | ||
|
|
@@ -49,19 +64,21 @@ 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, | ||
| evaluate_specular_brdf(wo, wi, world_normal, material) / 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. Are we sure that we should be using evaluate_specular_brdf and not evaluate_brdf here?
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. Old code evaluated the full BRDF, but not sure if that was right.
Contributor
Author
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. That's what I tested first, and the white furnace has excess energy if we try and evaluate the full brdf here.
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. Weird. I don't understand why that is!
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 it still break if this thresholding is removed? |
||
| bitcast<f32>(0x7F800000u) // INF | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| 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 throughput = evaluate_brdf(wo, wi, world_normal, material) / pdf; | ||
| return EvaluateAndSampleBrdfResult(wi, throughput, pdf); | ||
| } | ||
|
|
||
|
|
@@ -75,15 +92,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.diffuse / PI * NdotL; | ||
| } | ||
|
|
||
| fn evaluate_specular_brdf(wo: vec3<f32>, wi: vec3<f32>, world_normal: vec3<f32>, material: ResolvedMaterial) -> vec3<f32> { | ||
|
dylansechet marked this conversation as resolved.
Outdated
|
||
|
|
@@ -111,6 +125,26 @@ fn evaluate_specular_brdf(wo: vec3<f32>, wi: vec3<f32>, world_normal: vec3<f32>, | |
| return specular_multiscatter(D, Vs, F, F0, F_ab, 1.0) * NdotL; | ||
| } | ||
|
|
||
| fn brdf_pdf(wo: vec3<f32>, wi: vec3<f32>, world_normal: vec3<f32>, material: ResolvedMaterial) -> f32 { | ||
| let NdotV = max(dot(world_normal, wo), 0.0001); | ||
| let F0 = calculate_F0(material.base_color, material.metallic, vec3(material.reflectance)); | ||
| let rho = lobe_reflectances(F0, material, NdotV); | ||
| let specular_weight = luminance(rho.specular) / luminance(rho.specular + rho.diffuse); | ||
| let diffuse_weight = 1.0 - specular_weight; | ||
|
|
||
| let TBN = orthonormalize(world_normal); | ||
| let T = TBN[0]; | ||
| let B = TBN[1]; | ||
| let N = TBN[2]; | ||
|
|
||
| let wo_tangent = vec3(dot(wo, T), dot(wo, B), dot(wo, N)); | ||
| let wi_tangent = vec3(dot(wi, T), dot(wi, B), dot(wi, N)); | ||
|
|
||
| let diffuse_pdf = wi_tangent.z / PI; | ||
| let specular_pdf = ggx_vndf_pdf(wo_tangent, wi_tangent, material.roughness); | ||
| return (diffuse_weight * diffuse_pdf) + (specular_weight * specular_pdf); | ||
| } | ||
|
|
||
| fn fresnel(f0: vec3<f32>, LdotH: f32) -> vec3<f32> { | ||
| return f0 + (1.0 - f0) * pow(1.0 - LdotH, 5.0); | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.