Skip to content

Improve layering in the solari BRDF#24243

Merged
alice-i-cecile merged 7 commits into
bevyengine:mainfrom
dylansechet:solari_brdf_layering
May 15, 2026
Merged

Improve layering in the solari BRDF#24243
alice-i-cecile merged 7 commits into
bevyengine:mainfrom
dylansechet:solari_brdf_layering

Conversation

@dylansechet

@dylansechet dylansechet commented May 11, 2026

Copy link
Copy Markdown
Contributor

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 Outdated
Comment thread crates/bevy_solari/src/scene/brdf.wgsl Outdated
Comment thread crates/bevy_solari/src/pathtracer/pathtracer.wgsl Outdated
@JMS55

JMS55 commented May 13, 2026

Copy link
Copy Markdown
Contributor

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

@dylansechet

dylansechet commented May 13, 2026

Copy link
Copy Markdown
Contributor Author

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

@JMS55 JMS55 left a comment

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.

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?

Comment thread crates/bevy_solari/src/scene/brdf.wgsl Outdated
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.

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.

That's what I tested first, and the white furnace has excess energy if we try and evaluate the full 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.

Weird. I don't understand why that is!

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.

Does it still break if this thresholding is removed?

Comment thread crates/bevy_solari/src/pathtracer/pathtracer.wgsl Outdated
Comment thread crates/bevy_solari/src/scene/brdf.wgsl Outdated
@JMS55 JMS55 added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels May 15, 2026
@alice-i-cecile alice-i-cecile added this pull request to the merge queue May 15, 2026
Merged via the queue into bevyengine:main with commit 370be1b May 15, 2026
@github-project-automation github-project-automation Bot moved this from Needs SME Triage to Done in Rendering May 15, 2026
mockersf pushed a commit to mockersf/bevy that referenced this pull request May 21, 2026
# Objective

Improve the solari BRDF. Split off from
bevyengine#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](https://academysoftwarefoundation.github.io/OpenPBR/#model/basesubstrate/glossy-diffuse).
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:
<img width="1280" height="720" alt="main"
src="https://github.com/user-attachments/assets/c5fe02c7-1e3e-41ee-99af-e73e0fc8ae5c"
/>


This PR:
<img width="1280" height="720" alt="layering"
src="https://github.com/user-attachments/assets/8d28097f-572e-4a9e-aa66-875730357856"
/>

---
### PICA PICA pathtraced

<img width="1280" height="720" alt="animated"
src="https://github.com/user-attachments/assets/98716de5-1215-413a-a985-7d3fb0638dc0"
/>

Main:
<img width="1280" height="720" alt="main"
src="https://github.com/user-attachments/assets/32da9aa1-5235-4200-8c2a-33fd78b15b8b"
/>

This PR:
<img width="1280" height="720" alt="pr"
src="https://github.com/user-attachments/assets/a160eb3d-1c94-4d14-b769-0a981c7dc3dd"
/>
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-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants