Skip to content

fix(MeshTransmissionMaterial): support stencil buffer in render targets#2748

Open
fremorie wants to merge 4 commits into
pmndrs:masterfrom
fremorie:fix/account-for-stencil-buffer-in-mesh-transmission-material
Open

fix(MeshTransmissionMaterial): support stencil buffer in render targets#2748
fremorie wants to merge 4 commits into
pmndrs:masterfrom
fremorie:fix/account-for-stencil-buffer-in-mesh-transmission-material

Conversation

@fremorie

@fremorie fremorie commented Jun 20, 2026

Copy link
Copy Markdown

Why

MeshTransmissionMaterial samples its refraction from an offscreen buffer that it fills by re-rendering the scene every frame into an FBO created with useFBO. That render target is created without a stencil attachment, so any stencil-based masking (useMask / <Mask>) is silently ignored during the transmission pass - masked-out geometry that's correctly hidden in the main render still leaks through the transmissive surface. This makes MeshTransmissionMaterial incompatible with stencil masks, with no way to opt in.

This PR adds an optional stencilBuffer prop to enable a stencil attachment on the internal buffer(s), so masks are respected inside the refraction.

Minimal reproducible example of the bug Same example with meshPhysicalMaterial (works as expected)
https://fremorie.github.io/shaders/terrarium-transmission-material https://fremorie.github.io/shaders/terrarium-physical-material
Code Code
Screenshot from 2026-06-20 13-48-09 Screenshot from 2026-06-20 13-48-41
The mask has no effect: the material's internal render targets have no stencil buffer to honor it. The stencil mask clips the geometry correctly, because the material renders directly to the default framebuffer (which has a stencil buffer when gl={{ stencil: true }})

What

  • Added an optional stencilBuffer?: boolean prop to MeshTransmissionMaterial.
  • Forwarded it to the useFBO settings for both the main buffer (fboMain) and the backside buffer (fboBack), so masking works in both backside and non-backside modes.
  • Handled useFBO's argument overloading so the setting is applied whether or not a numeric resolution is provided (when resolution is omitted, settings must be passed as the first argument, otherwise the third argument is dropped).
  • Default false preserves the current behavior exactly - this is fully backward compatible and opt-in.

Usage:

<MeshTransmissionMaterial stencilBuffer transmission={1} />

Screenshots

Before After (with stencilBuffer={true})
Screenshot from 2026-06-20 13-55-26 Screenshot from 2026-06-20 13-55-54

Checklist

  • Documentation updated (example)
  • Storybook entry added (example)
  • Ready to be merged

@vercel

vercel Bot commented Jun 20, 2026

Copy link
Copy Markdown

@fremorie is attempting to deploy a commit to the Poimandres Team on Vercel.

A member of the Team first needs to authorize it.

@codesandbox-ci

Copy link
Copy Markdown

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant