-
-
Notifications
You must be signed in to change notification settings - Fork 148
Add GGX multiscatter compensation with Cycles albedo method #697
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?
Add GGX multiscatter compensation with Cycles albedo method #697
Conversation
Implements physically-based multiscattering for rough surfaces by simulating a random walk on the microsurface structure, allowing rays to bounce multiple times within microfacets before escaping. Implementation details: - Added ggxMicrosurfaceScatter() function that performs random walk - For rough surfaces (roughness > 0.2), rays can bounce 2-4 times within microsurface - Each bounce samples a new microfacet normal using VNDF - Fresnel is accumulated at each bounce for proper colored metals - Russian roulette termination prevents infinite loops - Throughput is applied to the final scatter result This approach uses explicit microsurface scattering (Heitz et al. 2016, Xie & Hanrahan 2018) rather than analytical compensation methods, which is the correct approach for pathtracers. Unlike rasterizer-based compensation formulas (e.g., Kulla-Conty), this method works with the pathtracer's recursive ray tracing rather than against it. Visual impact: - Rough metals: Slightly brighter and more saturated at grazing angles - Rough dielectrics: Better energy conservation, less darkening at high roughness - Smooth surfaces: No change (falls back to single-scatter GGX) The implementation only activates for rough surfaces where multiscatter has visible impact, providing minimal performance overhead. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
27114fb to
e67d3bf
Compare
|
Thanks! I'll take a look at this more in depth when I have a chance. There has been some pretty bad energy loss for metallic materials, unfortunately. Do you mind doing a comparison of the furnace test, as well? See here. Lastly - I know this is from Claude but do you have a reference implementation for these new functions? |
|
Updated PR description. |
|
I just found this other PR: #349 How come you didn't merge that one back then? |
|
An update on this... Three.js PBR shaders now pass the furnace test: mrdoob/three.js#32190 |
|
Thanks - I'll have to take a deeper look at this next week. The reason #349 wasn't merged is because it was causing some models to render as too bright in some cases and it felt generally like a downgrade outside of cases like the furnace test. The extra brightness may have been coming from the overly strong fresnel term (which is still present in this fix). Getting that addressed would give me a bit more confidence about things, I think. At some point it would be good to go through and review or rewrite a lot of the BRDF code, though that may not happen until a WebGPU overhaul. Chasing down down all the intermittent breakage on the project from new browser releases and devices, etc. Hoping WebGPU smooths some of that out, at least 🤞
I think there's also part of me that has a hard time trusting the correctness of AI code especially when 3+ different versions of the same fix are made with varying degrees of success. It just makes me wonder if this new one is actually right or wrong in ways that make it look right (though admittedly there are parts of the project that are already a bit wrong), so I just want to make sure it's understood before being merged. |









I was working on improving three.js' PBR implementation and while I was using the pathtracer as reference I noticed rough materials were getting darker. I now know that that's because lack of multiscattering.
I asked Claude if it could implement multiscattering in the path tracer, and after a few tries this is what he did:
Description
Implements GGX multiscatter energy compensation to fix energy loss in rough surfaces. Uses Blender Cycles' albedo-based approach to add back missing energy as a diffuse-like multiscatter lobe.
Implementation
0.806495 * exp(-1.98712 * r²) + 0.199531to estimate single-scatter energy capture(1 - albedo) * Favg / πas a diffuse-like multiscatter termApproach
This implementation uses an analytical compensation method rather than explicit random-walk simulation. The approach estimates how much energy single-scatter GGX captures using a fitted albedo curve, then adds the missing energy back as a Lambertian-like lobe scaled by average Fresnel.
This is simpler and faster than full microsurface random-walk methods while providing good energy conservation. The fitted albedo values come from Blender Cycles' ground-truth precomputed data.
Visual Impact
References
intern/cycles/kernel/closure/bsdf_microfacet_multi.h