Repository navigation
Conversation
…dd GTSO example. The specular cone now uses GGX alpha as in the paper's Eq. 26, and the cone overlap is normalized by the part of the specular cone above the surface so unoccluded grazing reflections are no longer darkened. The getSpecularOcclusion() context hook now takes ( inputNode, normal, roughness, builder ) like getAO(). Adds webgpu_postprocessing_gtso with mode, normal and bent normal views, and restores webgpu_postprocessing_ao to dev.
…pu_postprocessing_gtso. The bust is now polished bronze with fine procedural bumps and stands on the central pedestal, so the specular occlusion is visible.
📦 Bundle sizeFull ESM build including core, minified and gzipped.
🌳 Bundle size after tree-shakingMinimal build including a renderer, camera, empty scene, and dependencies.
|
🖼️ E2E screenshot tests✅ All examples render correctly again (run). |
sunag
reviewed
Oct 17, 2026
| return inputNode !== null ? inputNode.mul( visibility ) : visibility; | ||
|
|
||
| }, | ||
| getSpecularOcclusion: ( inputNode, normal, roughness, { material, context } ) => { |
Collaborator
There was a problem hiding this comment.
Is there a chance we might need to add more parameters in the future? If so, I'd prefer to group them into an object and always keep the builder as the second parameter, so the function maintains a consistent signature.
getSpecularOcclusion( { node, normal, roughness }, builder )
What do you think?
Contributor
Author
There was a problem hiding this comment.
@sunag I've changed the interface as you've requested. I've also merged in the latest dev branch so it is ready for merge/review.
This comment was marked as spam.
This comment was marked as spam.
Mugen87
marked this pull request as draft
October 26, 2026 14:17
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds bent normals to
GTAONodeand uses them for directional specular occlusion (GTSO) of environment lighting. Today GTAO only outputs a scalar visibility, and materials turn it into specular occlusion with a heuristic that does not know which directions are blocked. Metal therefore keeps reflecting the sky inside folds and cavities. With a bent normal, a reflection that points into nearby geometry is occluded, and one that points out of the opening is not.Live Demo Link:
https://raw.githack.com/bhouston/three.js/5b3167255be351a5f59b99b2e7f092c69c24ea84/examples/webgpu_postprocessing_ao_source.html
webgpu_postprocessing_aogains aGTAO + GTSOAO type next toGTAOandSSAO, and its bust is now polished bronze so the specular occlusion is visible. Switch betweenGTAO + GTSOandGTAOand look at the bust's collar, beard and coat folds: with GTSO they stop reflecting environment they cannot see, which gives the bust noticeably more depth. The live demo loads a copy of the example that importssrc/directly, since the committedbuild/does not include the core change yet.Implements the specular occlusion half of the GTAO paper we already use, Jimenez et al., Practical Realtime Strategies for Accurate Indirect Occlusion (SIGGRAPH 2016 slides):
cos(αv) = sqrt(1 - AO), and the specular lobe is a cone around the reflection vector withcos(αs) = 2^(-3.32193 α²)(α is GGX alpha). Their overlap is the analytic spherical-cap intersection from Oat and Sander, Ambient Aperture Lighting (I3D 2007).API changes:
.r), so existing code keeps working.getBentNormalNode( uv, normal )andgetLightingContext( uv )onGTAONode, and an exportedspecularOcclusion()TSL function.PhysicalLightingModelgains an optionalgetSO( { node, normal, roughness }, builder )context hook, next to the existinggetAO( inputNode, builder )hook. It is used for the base layer and for clearcoat.Important points
getSOcontext hook is a small core change inPhysicalLightingModel. @sunag, is this the right shape for the hook, or would you prefer a different extension point?getLightingContext().Validation: changed-file lint, the addon unit suite, hardware WebGPU/WebGL bent-normal regression, and AO example mode/resize checks pass on Apple M3.