-
-
Notifications
You must be signed in to change notification settings - Fork 36.3k
Material: Add per-face stencil properties #33313
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: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -296,6 +296,53 @@ class Material extends EventDispatcher { | |||||||||||||||
| */ | ||||||||||||||||
| this.stencilWrite = false; | ||||||||||||||||
|
|
||||||||||||||||
| /** | ||||||||||||||||
| * The stencil comparison function for back faces, or `null` to use | ||||||||||||||||
| * {@link Material#stencilFunc} for both faces. | ||||||||||||||||
| * | ||||||||||||||||
| * @type {?number} | ||||||||||||||||
| * @default null | ||||||||||||||||
| */ | ||||||||||||||||
| this.stencilBackFunc = null; | ||||||||||||||||
|
|
||||||||||||||||
| /** | ||||||||||||||||
| * The stencil reference value for back faces, or `null` to use | ||||||||||||||||
| * {@link Material#stencilRef} for both faces. | ||||||||||||||||
| * | ||||||||||||||||
| * @type {?number} | ||||||||||||||||
| * @default null | ||||||||||||||||
| */ | ||||||||||||||||
| this.stencilBackRef = null; | ||||||||||||||||
|
|
||||||||||||||||
| /** | ||||||||||||||||
| * Which stencil operation to perform on back faces when the comparison | ||||||||||||||||
| * function returns `false`, or `null` to use {@link Material#stencilFail}. | ||||||||||||||||
| * | ||||||||||||||||
| * @type {?number} | ||||||||||||||||
| * @default null | ||||||||||||||||
| */ | ||||||||||||||||
| this.stencilBackFail = null; | ||||||||||||||||
|
|
||||||||||||||||
| /** | ||||||||||||||||
| * Which stencil operation to perform on back faces when the comparison | ||||||||||||||||
| * function returns `true` but the depth test fails, or `null` to use | ||||||||||||||||
| * {@link Material#stencilZFail}. | ||||||||||||||||
| * | ||||||||||||||||
| * @type {?number} | ||||||||||||||||
| * @default null | ||||||||||||||||
| */ | ||||||||||||||||
| this.stencilBackZFail = null; | ||||||||||||||||
|
|
||||||||||||||||
| /** | ||||||||||||||||
| * Which stencil operation to perform on back faces when the comparison | ||||||||||||||||
| * function returns `true` and the depth test passes, or `null` to use | ||||||||||||||||
| * {@link Material#stencilZPass}. | ||||||||||||||||
| * | ||||||||||||||||
| * @type {?number} | ||||||||||||||||
| * @default null | ||||||||||||||||
| */ | ||||||||||||||||
| this.stencilBackZPass = null; | ||||||||||||||||
|
|
||||||||||||||||
| /** | ||||||||||||||||
| * User-defined clipping planes specified as THREE.Plane objects in world | ||||||||||||||||
| * space. These planes apply to the objects this material is attached to. | ||||||||||||||||
|
|
@@ -813,6 +860,12 @@ class Material extends EventDispatcher { | |||||||||||||||
| if ( this.stencilZPass !== KeepStencilOp ) data.stencilZPass = this.stencilZPass; | ||||||||||||||||
| if ( this.stencilWrite === true ) data.stencilWrite = this.stencilWrite; | ||||||||||||||||
|
|
||||||||||||||||
| if ( this.stencilBackFunc !== null ) data.stencilBackFunc = this.stencilBackFunc; | ||||||||||||||||
| if ( this.stencilBackRef !== null ) data.stencilBackRef = this.stencilBackRef; | ||||||||||||||||
| if ( this.stencilBackFail !== null ) data.stencilBackFail = this.stencilBackFail; | ||||||||||||||||
| if ( this.stencilBackZFail !== null ) data.stencilBackZFail = this.stencilBackZFail; | ||||||||||||||||
| if ( this.stencilBackZPass !== null ) data.stencilBackZPass = this.stencilBackZPass; | ||||||||||||||||
|
|
||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
three.js/src/loaders/MaterialLoader.js Lines 177 to 183 in 75ae80b
|
||||||||||||||||
| // rotation (SpriteMaterial) | ||||||||||||||||
| if ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation; | ||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -931,6 +984,12 @@ class Material extends EventDispatcher { | |||||||||||||||
| this.stencilZPass = source.stencilZPass; | ||||||||||||||||
| this.stencilWrite = source.stencilWrite; | ||||||||||||||||
|
|
||||||||||||||||
| this.stencilBackFunc = source.stencilBackFunc; | ||||||||||||||||
| this.stencilBackRef = source.stencilBackRef; | ||||||||||||||||
| this.stencilBackFail = source.stencilBackFail; | ||||||||||||||||
| this.stencilBackZFail = source.stencilBackZFail; | ||||||||||||||||
| this.stencilBackZPass = source.stencilBackZPass; | ||||||||||||||||
|
|
||||||||||||||||
| const srcPlanes = source.clippingPlanes; | ||||||||||||||||
| let dstPlanes = null; | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -67,13 +67,21 @@ class WebGLState { | |
| this.currentDepthReversed = false; | ||
| this.currentDepthFunc = null; | ||
| this.currentDepthMask = null; | ||
| this.currentStencilSeparate = false; | ||
| this.currentStencilFunc = null; | ||
| this.currentStencilRef = null; | ||
| this.currentStencilFuncMask = null; | ||
| this.currentStencilFuncBack = null; | ||
| this.currentStencilRefBack = null; | ||
| this.currentStencilFuncMaskBack = null; | ||
| this.currentStencilFail = null; | ||
| this.currentStencilZFail = null; | ||
| this.currentStencilZPass = null; | ||
| this.currentStencilFailBack = null; | ||
| this.currentStencilZFailBack = null; | ||
| this.currentStencilZPassBack = null; | ||
| this.currentStencilMask = null; | ||
| this.currentStencilMaskBack = null; | ||
| this.currentLineWidth = null; | ||
| this.currentClippingPlanes = 0; | ||
|
|
||
|
|
@@ -829,10 +837,30 @@ class WebGLState { | |
| */ | ||
| setStencilMask( stencilMask ) { | ||
|
|
||
| if ( this.currentStencilMask !== stencilMask ) { | ||
| if ( this.currentStencilSeparate === true || this.currentStencilMask !== stencilMask ) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure these checks are robust enough: If you have used separate mask and then switch to a uniform mask, I think you must implement a check that reconginizes when Func and Op are also affected by this issue. |
||
|
|
||
| this.gl.stencilMask( stencilMask ); | ||
| this.currentStencilMask = stencilMask; | ||
| this.currentStencilMaskBack = stencilMask; | ||
| this.currentStencilSeparate = false; | ||
|
|
||
| } | ||
|
|
||
| } | ||
|
|
||
| setStencilMaskSeparate( stencilMask, stencilMaskBack ) { | ||
|
|
||
| if ( | ||
| this.currentStencilSeparate === false || | ||
| this.currentStencilMask !== stencilMask || | ||
| this.currentStencilMaskBack !== stencilMaskBack | ||
| ) { | ||
|
|
||
| this.gl.stencilMaskSeparate( this.gl.FRONT, stencilMask ); | ||
| this.gl.stencilMaskSeparate( this.gl.BACK, stencilMaskBack ); | ||
| this.currentStencilMask = stencilMask; | ||
| this.currentStencilMaskBack = stencilMaskBack; | ||
| this.currentStencilSeparate = true; | ||
|
|
||
| } | ||
|
|
||
|
|
@@ -850,7 +878,8 @@ class WebGLState { | |
| */ | ||
| setStencilFunc( stencilFunc, stencilRef, stencilMask ) { | ||
|
|
||
| if ( this.currentStencilFunc !== stencilFunc || | ||
| if ( this.currentStencilSeparate === true || | ||
| this.currentStencilFunc !== stencilFunc || | ||
| this.currentStencilRef !== stencilRef || | ||
| this.currentStencilFuncMask !== stencilMask ) { | ||
|
|
||
|
|
@@ -859,6 +888,37 @@ class WebGLState { | |
| this.currentStencilFunc = stencilFunc; | ||
| this.currentStencilRef = stencilRef; | ||
| this.currentStencilFuncMask = stencilMask; | ||
| this.currentStencilFuncBack = stencilFunc; | ||
| this.currentStencilRefBack = stencilRef; | ||
| this.currentStencilFuncMaskBack = stencilMask; | ||
| this.currentStencilSeparate = false; | ||
|
|
||
| } | ||
|
|
||
| } | ||
|
|
||
| setStencilFuncSeparate( stencilFunc, stencilRef, stencilMask, stencilFuncBack, stencilRefBack, stencilMaskBack ) { | ||
|
|
||
| if ( | ||
| this.currentStencilSeparate === false || | ||
| this.currentStencilFunc !== stencilFunc || | ||
| this.currentStencilRef !== stencilRef || | ||
| this.currentStencilFuncMask !== stencilMask || | ||
| this.currentStencilFuncBack !== stencilFuncBack || | ||
| this.currentStencilRefBack !== stencilRefBack || | ||
| this.currentStencilFuncMaskBack !== stencilMaskBack | ||
| ) { | ||
|
|
||
| this.gl.stencilFuncSeparate( this.gl.FRONT, stencilFunc, stencilRef, stencilMask ); | ||
| this.gl.stencilFuncSeparate( this.gl.BACK, stencilFuncBack, stencilRefBack, stencilMaskBack ); | ||
|
|
||
| this.currentStencilFunc = stencilFunc; | ||
| this.currentStencilRef = stencilRef; | ||
| this.currentStencilFuncMask = stencilMask; | ||
| this.currentStencilFuncBack = stencilFuncBack; | ||
| this.currentStencilRefBack = stencilRefBack; | ||
| this.currentStencilFuncMaskBack = stencilMaskBack; | ||
| this.currentStencilSeparate = true; | ||
|
|
||
| } | ||
|
|
||
|
|
@@ -877,7 +937,8 @@ class WebGLState { | |
| */ | ||
| setStencilOp( stencilFail, stencilZFail, stencilZPass ) { | ||
|
|
||
| if ( this.currentStencilFail !== stencilFail || | ||
| if ( this.currentStencilSeparate === true || | ||
| this.currentStencilFail !== stencilFail || | ||
| this.currentStencilZFail !== stencilZFail || | ||
| this.currentStencilZPass !== stencilZPass ) { | ||
|
|
||
|
|
@@ -886,6 +947,37 @@ class WebGLState { | |
| this.currentStencilFail = stencilFail; | ||
| this.currentStencilZFail = stencilZFail; | ||
| this.currentStencilZPass = stencilZPass; | ||
| this.currentStencilFailBack = stencilFail; | ||
| this.currentStencilZFailBack = stencilZFail; | ||
| this.currentStencilZPassBack = stencilZPass; | ||
| this.currentStencilSeparate = false; | ||
|
|
||
| } | ||
|
|
||
| } | ||
|
|
||
| setStencilOpSeparate( stencilFail, stencilZFail, stencilZPass, stencilFailBack, stencilZFailBack, stencilZPassBack ) { | ||
|
|
||
| if ( | ||
| this.currentStencilSeparate === false || | ||
| this.currentStencilFail !== stencilFail || | ||
| this.currentStencilZFail !== stencilZFail || | ||
| this.currentStencilZPass !== stencilZPass || | ||
| this.currentStencilFailBack !== stencilFailBack || | ||
| this.currentStencilZFailBack !== stencilZFailBack || | ||
| this.currentStencilZPassBack !== stencilZPassBack | ||
| ) { | ||
|
|
||
| this.gl.stencilOpSeparate( this.gl.FRONT, stencilFail, stencilZFail, stencilZPass ); | ||
| this.gl.stencilOpSeparate( this.gl.BACK, stencilFailBack, stencilZFailBack, stencilZPassBack ); | ||
|
|
||
| this.currentStencilFail = stencilFail; | ||
| this.currentStencilZFail = stencilZFail; | ||
| this.currentStencilZPass = stencilZPass; | ||
| this.currentStencilFailBack = stencilFailBack; | ||
| this.currentStencilZFailBack = stencilZFailBack; | ||
| this.currentStencilZPassBack = stencilZPassBack; | ||
| this.currentStencilSeparate = true; | ||
|
|
||
| } | ||
|
|
||
|
|
@@ -924,9 +1016,38 @@ class WebGLState { | |
| this.setStencilTest( stencilWrite ); | ||
| if ( stencilWrite ) { | ||
|
|
||
| this.setStencilMask( material.stencilWriteMask ); | ||
| this.setStencilFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask ); | ||
| this.setStencilOp( material.stencilFail, material.stencilZFail, material.stencilZPass ); | ||
| const hasSeparateBack = | ||
| material.stencilBackFunc !== null || | ||
| material.stencilBackFail !== null || | ||
| material.stencilBackZFail !== null || | ||
| material.stencilBackZPass !== null || | ||
| material.stencilBackRef !== null; | ||
|
|
||
| if ( hasSeparateBack ) { | ||
|
|
||
| this.setStencilMaskSeparate( material.stencilWriteMask, material.stencilWriteMask ); | ||
|
|
||
| this.setStencilFuncSeparate( | ||
| material.stencilFunc, material.stencilRef, material.stencilFuncMask, | ||
| material.stencilBackFunc !== null ? material.stencilBackFunc : material.stencilFunc, | ||
| material.stencilBackRef !== null ? material.stencilBackRef : material.stencilRef, | ||
| material.stencilFuncMask | ||
| ); | ||
|
|
||
| this.setStencilOpSeparate( | ||
| material.stencilFail, material.stencilZFail, material.stencilZPass, | ||
| material.stencilBackFail !== null ? material.stencilBackFail : material.stencilFail, | ||
| material.stencilBackZFail !== null ? material.stencilBackZFail : material.stencilZFail, | ||
| material.stencilBackZPass !== null ? material.stencilBackZPass : material.stencilZPass | ||
| ); | ||
|
|
||
| } else { | ||
|
|
||
| this.setStencilMask( material.stencilWriteMask ); | ||
| this.setStencilFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask ); | ||
| this.setStencilOp( material.stencilFail, material.stencilZFail, material.stencilZPass ); | ||
|
|
||
| } | ||
|
|
||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stencilBackRefis ignored in WebGPU. WebGPU only offersGPURenderPassEncoder.setStencilReference()that means you can only set a single stencil reference for front and back faces.We could a) remove
stencilBackRefor 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?