Conversation
📦 Bundle sizeFull ESM build, minified and gzipped.
🌳 Bundle size after tree-shakingMinimal build including a renderer, camera, empty scene, and dependencies.
|
| if ( this.stencilBackFail !== null ) data.stencilBackFail = this.stencilBackFail; | ||
| if ( this.stencilBackZFail !== null ) data.stencilBackZFail = this.stencilBackZFail; | ||
| if ( this.stencilBackZPass !== null ) data.stencilBackZPass = this.stencilBackZPass; | ||
|
|
There was a problem hiding this comment.
MaterialLoader also needs an update so the deserialization works:
three.js/src/loaders/MaterialLoader.js
Lines 177 to 183 in 75ae80b
| setStencilMask( stencilMask ) { | ||
|
|
||
| if ( this.currentStencilMask !== stencilMask ) { | ||
| if ( this.currentStencilSeparate === true || this.currentStencilMask !== stencilMask ) { |
There was a problem hiding this comment.
I'm not sure these checks are robust enough:
If you have used separate mask and then switch to a uniform mask, gl.stencilMask() might not be executed if this.currentStencilMask is equal to stencilMask. Meaning it would leave the back faces with a wrong value (the one from the separate call).
I think you must implement a check that reconginizes when currentStencilSeparate changes. If it does, it must invalidate the cached properties so the WebGL state is forced to update.
Func and Op are also affected by this issue.
|
|
||
| /** | ||
| * The stencil reference value for back faces, or `null` to use | ||
| * {@link Material#stencilRef} for both faces. |
There was a problem hiding this comment.
stencilBackRef is ignored in WebGPU. WebGPU only offers GPURenderPassEncoder.setStencilReference() that means you can only set a single stencil reference for front and back faces.
We could a) remove stencilBackRef or b) just document that it is WebGL 2 only. That might cause rendering issue though. A feature that works in WebGL 2 won't work in WebGPU.
I vote doing the same with masks and adhere to the WebGPU spec. What do you think?
Description
Add
stencilBackFunc,stencilBackRef,stencilBackFail,stencilBackZFail, andstencilBackZPassproperties toMaterial, enabling separate front/back stencil operations on a singleDoubleSidemesh.When any back-face property is non-null, the renderer uses per-face stencil state (
gl.stencilFuncSeparate/gl.stencilOpSeparateon WebGL;depthStencil.stencilBackon WebGPU). When all are null (default), behavior is unchanged - back faces mirror front, as established in #33002Masks (
stencilFuncMask,stencilWriteMask) remain shared across both faces, matching the WebGPU spec which does not support per-face masksMotivation
#33002 fixed
stencilBackto matchstencilFrontin the WebGPU pipeline. This follow-up exposes the back-face state as a user-facing API so front and back can intentionally differ. The primary use case is nonzero-winding stencil fills (e.g. for resolution-independent text rendering via Loop-Blinn, which I just added to three-text. Loop-Blinn achieves better AA than Slug, which is why I didn't go that route - interesting that Eric Lengyel open sourced Slug exactly one week before the Loop-Blinn patent expired, probably a coincidence 😉)Without per-face stencil ops, this requires two separate single-sided draw calls per stencil pass: one for front-face increment, one for back-face decrement. With this change, a single
DoubleSidedraw call handles bothChanges
src/materials/Material.js- 5 new properties (defaultnull),copy(),toJSON()src/renderers/webgl/WebGLState.js- cached separate-face stencil helperssrc/renderers/webgl-fallback/utils/WebGLState.js- samesrc/renderers/webgpu/utils/WebGPUPipelineUtils.js- populatestencilBackfrom back properties; refactored_getStencilCompare()to accept raw valuesrc/renderers/webgpu/WebGPUBackend.js- back properties in pipeline cache key andneedsUpdatetest/unit/src/materials/Material.tests.js- defaults, copy, serialization tests