close
Skip to content

Improve layering in the solari BRDF#24243

Open
dylansechet wants to merge 5 commits into
bevyengine:mainfrom
dylansechet:solari_brdf_layering
Open

Improve layering in the solari BRDF#24243
dylansechet wants to merge 5 commits into
bevyengine:mainfrom
dylansechet:solari_brdf_layering

Conversation

@dylansechet
Copy link
Copy Markdown
Contributor

@dylansechet dylansechet commented May 11, 2026

Objective

Improve the solari BRDF. Split off from #23818.

Solution

The layering approach used in the current brdf to distribute energy between the specular and diffuse lobes doesn't work, for reasons I honestly don't quite understand.

The suggested changes are roughly inspired by OpenPBR's equation 42. We're not using EON though, so this uses Filament's multiscattering correction instead of equation 39.
This formulation has the downside of breaking reciprocity. As far as I can tell the path tracer is unidirectional, so this shouldn't cause issues.


Showcase

White furnace

Main:
main

This PR:
layering


PICA PICA pathtraced

animated

Main:
main

This PR:
pr

@kfc35 kfc35 added A-Rendering Drawing game state to the screen S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels May 11, 2026
@github-project-automation github-project-automation Bot moved this to Needs SME Triage in Rendering May 11, 2026
@kfc35 kfc35 added the D-Shaders This code uses GPU shader languages label May 11, 2026
Comment thread crates/bevy_solari/src/pathtracer/pathtracer.wgsl Outdated
Comment thread crates/bevy_solari/src/pathtracer/pathtracer.wgsl Outdated
Comment thread crates/bevy_solari/src/scene/brdf.wgsl
Comment thread crates/bevy_solari/src/scene/brdf.wgsl Outdated
Comment thread crates/bevy_solari/src/scene/brdf.wgsl Outdated
Comment thread crates/bevy_solari/src/scene/brdf.wgsl
Comment thread crates/bevy_solari/src/scene/brdf.wgsl Outdated
Comment thread crates/bevy_solari/src/scene/brdf.wgsl
Comment thread crates/bevy_solari/src/scene/brdf.wgsl Outdated
Comment thread crates/bevy_solari/src/pathtracer/pathtracer.wgsl Outdated
@JMS55
Copy link
Copy Markdown
Contributor

JMS55 commented May 13, 2026

Btw would love to know the code you used for the white furnace test for solari - I lost mine.

@dylansechet
Copy link
Copy Markdown
Contributor Author

dylansechet commented May 13, 2026

Thanks for the review! I think I've addressed everything, with the only logic change being the mirror pdf handling.
I've set up a gist with the white furnace code.

Comment thread crates/bevy_solari/src/scene/brdf.wgsl Outdated
Comment thread crates/bevy_solari/src/scene/brdf.wgsl Outdated
Comment thread crates/bevy_solari/src/scene/brdf.wgsl Outdated
if material.roughness <= MIRROR_ROUGHNESS_THRESHOLD {
return EvaluateAndSampleBrdfResult(
wi,
rho.specular / specular_weight,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think rho.specular / specular_weight is right here. You need to evaluate the BRDF.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be the same thing, as the total reflected energy for a mirror is the same as the brdf evaluated for the reflected ray.
Doing a brdf evaluation does feel more readable though, and the lut at 0 roughness probably isn't that great.

Comment thread crates/bevy_solari/src/scene/brdf.wgsl Outdated
Comment thread crates/bevy_solari/src/scene/brdf.wgsl Outdated
Copy link
Copy Markdown
Contributor

@JMS55 JMS55 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One last potential issues (not sure which it should be, my brain is a little fried).

Also, we have a couple usages of F_AB, which samples a texture. Can we hoist that out now?

if material.roughness <= MIRROR_ROUGHNESS_THRESHOLD {
return EvaluateAndSampleBrdfResult(
wi,
evaluate_specular_brdf(wo, wi, world_normal, material) / specular_weight,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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.

#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, brdf_pdf, lobe_reflectances}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lobe_reflectances unused


let diffuse_pdf = wi_tangent.z / PI;
let specular_pdf = ggx_vndf_pdf(wo_tangent, wi_tangent, material.roughness);
return specular_weight * specular_pdf + diffuse_weight * diffuse_pdf;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Reverse these to match evaluate_and_sample_brdf.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Rendering Drawing game state to the screen D-Shaders This code uses GPU shader languages S-Needs-Review Needs reviewer attention (from anyone!) to move forward

Projects

Status: Needs SME Triage

Development

Successfully merging this pull request may close these issues.

3 participants