Skip to content

fix: restore stencil compare value for nested masks#257

Open
secant666 wants to merge 1 commit into
fairygui:masterfrom
secant666:fix-nested-mask-stencil-context
Open

fix: restore stencil compare value for nested masks#257
secant666 wants to merge 1 commit into
fairygui:masterfrom
secant666:fix-nested-mask-stencil-context

Conversation

@secant666

Copy link
Copy Markdown

Problem

When using nested alpha masks, wrapped renderers such as Spine objects in GLoader3D can inherit a stale stencil compare value after an inner mask exits.
Example hierarchy:

component1
  mask1
  spine11
  component12
    mask2
    spine21
    component22
      mask3
      spine31
      component32
        mask4
        spine41
      spine33
    spine23
  spine13
spine41 should be clipped by mask1 + mask2 + mask3 + mask4.

After leaving mask4, spine33 should only be clipped by mask1 + mask2 + mask3. However, UpdateContext.LeaveClipping() restores stencilReferenceValue but does not restore stencilCompareValue, so later sibling objects may still use the compare value from the inner mask.

This can make active and visible Spine objects fail stencil test and disappear.

### Cause
EnterClipping(uint clipId, bool reversedMask) updates both:

stencilReferenceValue
stencilCompareValue
But ClipInfo only stores referenceValue, so LeaveClipping() cannot restore the previous compare value.

GoWrapper objects apply the current clipping state directly to renderer materials through ApplyClippingProperties(), which makes this stale state visible on wrapped renderers such as Spine.

### Fix
Store stencilCompareValue in ClipInfo.
Restore it in LeaveClipping() and LeavePaintingMode().
Reset active stencil state in EnterPaintingMode() so it matches the existing Reset clipping behavior.

### Test
Tested in a Unity project with nested FairyGUI masks and Spine objects. After the fix, sibling Spine objects outside an inner mask no longer inherit the inner mask stencil compare value.

@secant666

Copy link
Copy Markdown
Author

问题

在使用嵌套 alpha mask 时,GLoader3D 中的 Spine 等 wrapped renderer 可能会在内层 mask 结束后继承错误的 stencil compare value。

示例层级:

component1
  mask1
  spine11
  component12
    mask2
    spine21
    component22
      mask3
      spine31
      component32
        mask4
        spine41
      spine33
    spine23
  spine13

spine41 应该受到 mask1 + mask2 + mask3 + mask4 的共同裁剪。

当退出 mask4 后,spine33 应该只受到 mask1 + mask2 + mask3 的裁剪。但是当前 UpdateContext.LeaveClipping() 只恢复了 stencilReferenceValue,没有恢复 stencilCompareValue,导致后续兄弟节点可能继续使用内层 mask 的 compare value。

这会导致 active 且 visible 的 Spine 对象因为 stencil test 不通过而不被渲染,看起来像是消失了。

原因

EnterClipping(uint clipId, bool reversedMask) 会同时更新:

  • stencilReferenceValue
  • stencilCompareValue

但是 ClipInfo 当前只保存了 referenceValue,所以 LeaveClipping() 无法恢复上一层的 compare value。

对于 GoWrapper 对象,当前裁剪状态会通过 ApplyClippingProperties() 直接写入 renderer 的材质,因此这个残留状态会影响 Spine 等 wrapped renderer 的实际渲染。

修复

  • ClipInfo 中保存 stencilCompareValue
  • LeaveClipping()LeavePaintingMode() 中恢复 stencilCompareValue
  • EnterPaintingMode() 中重置当前 active stencil 状态,使其行为与已有注释 Reset clipping 一致。

测试

已在 Unity 项目中使用 FairyGUI 嵌套 mask 和 Spine 对象进行验证。修复后,位于内层 mask 外部的兄弟 Spine 对象不会再继承内层 mask 的 stencil compare value。

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