-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
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
Updated Stencil Test Case to prevent it from disable after every draw #7578
base: dev-2.0
Are you sure you want to change the base?
Conversation
src/webgl/p5.RendererGL.js
Outdated
// When pop() disables the stencil test after clip(), | ||
// restore the user's stencil test setting | ||
if (this._clipDepth === this._pushPopDepth) { | ||
this.isStencilTestOn = this._userEnabledStencil; |
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.
It's a little unintuitive that calling disable()
elsewhere in the code might not actually disable. How do you feel about making enable
/disable
only record the last value so that getEnabled
is fast, and then place this logic of what value to revert to elsewhere?
The idea would be, write the code so that the behaviour would be the same even if we haven't overridden enable
and disable
: e.g. when we begin clipping, we can record this.isStencilTestOn = this.drawingContext.getEnabled(this.drawingContext.STENCIL_TEST)
, and then in pop
where we turn off stencil testing currently, we would either turn it on or off based on the value of this.isStencilTestOn
.
Then, this overriding of enable
/disable
just makes the getEnabled
call run faster, without changing what it does or its side effects.
Thanks for taking this task on, it's looking good! I have some comments on how we might rearrange the implementation to make the code easier for other contributors to read. |
One other thought: if stencil testing was on, after we finish clipping in |
So, right now, I'm clearing the stencil buffer at the beginning of beginClip() but not when exiting the clip context in pop(). |
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.
Some thoughts on the overall logic
Just looking again at the if statements in the drawingContext.enable
override: Is the if statement in here trying to detect if the user is manually calling drawingContext.disable
vs if p5 itself is doing it?
One idea to try to simplify this: Maybe we should take those prevEnable
and prevDisable
variable we have, and store it on the renderer with names like internalEnable
and internalDisable
. Calling those just enable/disable; and then we're free to make our overrides a lot simpler, just:
this.drawingContext.enable = (key) => {
if (key === this.drawingContext.STENCIL_TEST) {
this._userEnabledStencil = true
}
return prevEnable.call(key)
Then:
- wherever we internally call
GL.enable(GL.STENCIL_TEST)
, we'd callinternalEnable(GL.STENCIL_TEST)
instead so that it keeps_userEnabledStencil
the same - in all the places where we currently just disable stencil testing, we'd only actually disable it if
_userEnabledStencil
is false too, and otherwise leave it on.
This way we also don't need to record what the value is right before we enable stencil testing, since we don't really need to know what it was right before if we've recorded what the user has set it to.
I think that would mean we don't need the isStencilTestOn
check as well, and might simplify some of our logic. Do you think that would work?
Clearing the buffer on pop
Thinking a little more about the use case here, clearing the stencil buffer in pop
would only make a difference if the user already manually enabled the stencil buffer, and additionally is using p5 clipping. I think that's actually not a combination we need to worry about, since the stencil buffer does clipping, if you're turning it on manually, the user won't be using p5's clipping. So maybe we take the simpler approach and don't do anything additional here.
Testing
Sorry for all the back-and-forth on this, it turns out the logic is complicated haha. That's maybe a good sign that we should make some unit tests involving manual calls to enable/disable the stencil test?
src/webgl/p5.RendererGL.js
Outdated
@@ -1750,7 +1809,9 @@ class RendererGL extends Renderer { | |||
this.GL.enable(this.GL.STENCIL_TEST); | |||
this._stencilTestOn = true; | |||
} else { | |||
this.GL.disable(this.GL.STENCIL_TEST); | |||
if (!this.isStencilTestOn) { |
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.
Should this only disable if the user has not manually called disable
? If so, maybe we need to be using the _userEnabledStencil
for the if condition?
Sure, got it. |
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.
The updates are looking good! I think the general approach looks almost complete. There are a few cases being handled that I think we may not need to handle any more and can be omitted. But in general this looks almost done, feel free to start adding tests!
src/webgl/p5.RendererGL.js
Outdated
@@ -1387,7 +1423,7 @@ class RendererGL extends Renderer { | |||
this.drawTarget()._isClipApplied = true; | |||
|
|||
const gl = this.GL; | |||
gl.clearStencil(0); | |||
gl.clearStencil(0); |
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.
I think there's a trailing space at the end here that we can take out.
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.
Sure
src/webgl/p5.RendererGL.js
Outdated
if (key === this.drawingContext.STENCIL_TEST) { | ||
// When pop() disables the stencil test after clip(), | ||
// preserve the user's stencil test setting | ||
if (this._clipDepth === this._pushPopDepth) { |
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.
Do we need this condition here, since we're calling _internalDisable
in pop
? I think maybe this is only called now when users manually call disable
, so we can set this._userEnabledStencil = true
. The same may be true in enable
as well if we update the spots where we turn on stencil testing to use _internalEnable
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.
Right! I'll do this for enable as well.
src/webgl/p5.RendererGL.js
Outdated
@@ -427,6 +427,39 @@ class RendererGL extends Renderer { | |||
this.drawShapeCount = 1; | |||
|
|||
this.scratchMat3 = new Matrix(3); | |||
|
|||
this._userEnabledStencil = false; | |||
this.isStencilTestOn = false; |
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.
Do we use this any more?
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.
Right, we don't.
So, I have added the tests for stencil testing which I thought were appropriate. Let me know to add or remove some cases. Also replaced the internalEnable for enable in the file. |
Resolves #7554
Changes:
Screenshots of the change:
Used this snippet in preview/index.html,
SCREENSHOT:

PR Checklist
npm run lint
passes