Skip to content
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

Refactor mask #2369

Open
wants to merge 41 commits into
base: dev/1.4
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
3ff8a7b
refactor(mask): refactor mask
singlecoder Sep 2, 2024
4afe44b
refactor(mask): opt stencil state
singlecoder Sep 3, 2024
603ba2a
refactor(mask): move sprite mask layer to root
singlecoder Sep 3, 2024
0ae6484
refactor(mask): opt code
singlecoder Sep 5, 2024
1a89b5d
refactor(mask): clear stencil when shadow
singlecoder Sep 9, 2024
a5f1ab9
refactor(mask): fix test error
singlecoder Sep 9, 2024
7ad02b4
refactor(mask): delete render queue check in RenderQueue
singlecoder Sep 10, 2024
e97c4aa
refactor(mask): rename api _isCulledByCamera to _isFilteredByLayer
singlecoder Sep 11, 2024
2f2615b
refactor(mask): when need mask, not change stencil state, upload to g…
singlecoder Sep 11, 2024
47c9c7e
refactor(mask): delete unless code
singlecoder Sep 11, 2024
e52b60a
refactor(mask): mask should be filtered by camera culling mask
singlecoder Sep 12, 2024
8a48797
refactor(mask): opt code
singlecoder Sep 13, 2024
a311f2d
refactor(mask): clear stencil by mask when current render queue has done
singlecoder Sep 14, 2024
9a06859
refactor(mask): opt code
singlecoder Sep 18, 2024
f6f373b
refactor(mask): opt code
singlecoder Sep 18, 2024
f6b35a9
refactor(mask): opt code
singlecoder Sep 18, 2024
47d670a
refactor(mask): opt code
singlecoder Sep 18, 2024
8c0fc37
refactor(mask): opt code
singlecoder Sep 19, 2024
e71b5d6
refactor(mask): delete useless stencil clear
singlecoder Sep 19, 2024
5df85bc
refactor(mask): opt custom stencil states cache
singlecoder Sep 19, 2024
0a09fee
refactor(mask): opt code
singlecoder Sep 19, 2024
82f7f82
refactor(mask): fix conflicts from dev/1.4
singlecoder Sep 19, 2024
12d40f3
refactor(mask): opt custom stencil states
singlecoder Sep 19, 2024
028e4b0
refactor(mask): opt code
singlecoder Sep 19, 2024
2b92fe1
refactor(mask): opt code for clear mask
singlecoder Sep 19, 2024
3d10522
Refactor: extract some methods of the 2D renderers from the Engine (#15)
eyworldwide Sep 29, 2024
5f50e58
refactor(mask): fix perttier
singlecoder Sep 29, 2024
f96f891
refactor(mask): opt code for custom stencil states
singlecoder Oct 9, 2024
ea9e05c
Merge branch 'dev/1.4' into refactor/sprite-mask
singlecoder Oct 12, 2024
6e6eab5
refactor(mask): support developers to customize stencil
singlecoder Oct 12, 2024
ce3efed
refactor(mask): opt code for resume stencil
singlecoder Oct 13, 2024
bd38b58
refactor(mask): migrate 2d default material to basic resources
singlecoder Oct 14, 2024
18ea656
refactor(mask): opt code
singlecoder Oct 14, 2024
894dff9
refactor(mask): opt code
singlecoder Oct 14, 2024
f0c6d4b
refactor(mask): opt mask and stencil clear time
singlecoder Oct 15, 2024
4f4218d
refactor(mask): opt color write mask set
singlecoder Oct 15, 2024
397ac0e
refactor(mask): perttier code
singlecoder Oct 15, 2024
d29b823
refactor(mask): opt code
singlecoder Oct 17, 2024
8a34428
refactor(mask): opt code
singlecoder Oct 17, 2024
61558b1
refactor(mask): opt code
singlecoder Oct 17, 2024
3fd4e4f
refactor(mask): opt code
singlecoder Oct 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/core/src/2d/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export { SpriteMaskInteraction } from "./enums/SpriteMaskInteraction";
export { SpriteMaskLayer } from "./enums/SpriteMaskLayer";
export { TextHorizontalAlignment, TextVerticalAlignment } from "./enums/TextAlignment";
export { OverflowMode } from "./enums/TextOverflow";
export { FontStyle } from "./enums/FontStyle";
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/2d/sprite/SpriteMask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
import { SubRenderElement } from "../../RenderPipeline/SubRenderElement";
import { Renderer, RendererUpdateFlags } from "../../Renderer";
import { assignmentClone, ignoreClone } from "../../clone/CloneManager";
import { SpriteMaskLayer } from "../../enums/SpriteMaskLayer";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Residual old import paths detected

The script found an occurrence of the old import path in packages/core/src/RenderPipeline/MaskManager.ts. Please update this reference to ensure consistency across the codebase.

🔗 Analysis chain

Verify import path consistency across the codebase

The import path for SpriteMaskLayer has been updated. Ensure that this change is consistent across the entire codebase to prevent any import-related issues.

Run the following script to check for any remaining occurrences of the old import path:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining occurrences of the old import path for SpriteMaskLayer

# Test: Search for the old import path
rg --type typescript 'from "../enums/SpriteMaskLayer"'

Length of output: 178


Script:

#!/bin/bash
# Description: Check for any remaining occurrences of the old import path for SpriteMaskLayer

# Test: Search for the old import path
rg --type ts "from \"../enums/SpriteMaskLayer\""

Length of output: 156

import { ShaderProperty } from "../../shader/ShaderProperty";
import { SimpleSpriteAssembler } from "../assembler/SimpleSpriteAssembler";
import { SpriteMaskLayer } from "../enums/SpriteMaskLayer";
import { SpriteModifyFlags } from "../enums/SpriteModifyFlags";
import { Sprite } from "./Sprite";

Expand Down Expand Up @@ -177,7 +177,7 @@
constructor(entity: Entity) {
super(entity);
SimpleSpriteAssembler.resetData(this);
this.setMaterial(this._engine._spriteMaskDefaultMaterial);
this.setMaterial(this._engine._basicResources.spriteMaskDefaultMaterial);
this.shaderData.setFloat(SpriteMask._alphaCutoffProperty, this._alphaCutoff);
this._renderElement = new RenderElement();
this._renderElement.addSubRenderElement(new SubRenderElement());
Expand Down Expand Up @@ -261,7 +261,7 @@
const { _engine: engine } = this;
// @todo: This question needs to be raised rather than hidden.
if (material.destroyed) {
material = engine._spriteMaskDefaultMaterial;
material = engine._basicResources.spriteMaskDefaultMaterial;

Check warning on line 264 in packages/core/src/2d/sprite/SpriteMask.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/2d/sprite/SpriteMask.ts#L264

Added line #L264 was not covered by tests
}

// Update position
Expand Down
28 changes: 2 additions & 26 deletions packages/core/src/2d/sprite/SpriteRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import { Renderer, RendererUpdateFlags } from "../../Renderer";
import { assignmentClone, deepClone, ignoreClone } from "../../clone/CloneManager";
import { ShaderProperty } from "../../shader/ShaderProperty";
import { CompareFunction } from "../../shader/enums/CompareFunction";
import { ISpriteAssembler } from "../assembler/ISpriteAssembler";
import { SimpleSpriteAssembler } from "../assembler/SimpleSpriteAssembler";
import { SlicedSpriteAssembler } from "../assembler/SlicedSpriteAssembler";
Expand Down Expand Up @@ -257,7 +256,6 @@

set maskInteraction(value: SpriteMaskInteraction) {
if (this._maskInteraction !== value) {
this._updateStencilState(this._maskInteraction, value);
this._maskInteraction = value;
}
}
Expand All @@ -269,7 +267,7 @@
super(entity);
this.drawMode = SpriteDrawMode.Simple;
this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.Color;
this.setMaterial(this._engine._spriteDefaultMaterial);
this.setMaterial(this._engine._basicResources.spriteDefaultMaterial);
this._onSpriteChange = this._onSpriteChange.bind(this);
//@ts-ignore
this._color._onValueChanged = this._onColorChanged.bind(this);
Expand Down Expand Up @@ -334,7 +332,7 @@
}
// @todo: This question needs to be raised rather than hidden.
if (material.destroyed) {
material = this._engine._spriteDefaultMaterials[this._maskInteraction];
material = this._engine._basicResources.spriteDefaultMaterial;

Check warning on line 335 in packages/core/src/2d/sprite/SpriteRenderer.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/2d/sprite/SpriteRenderer.ts#L335

Added line #L335 was not covered by tests
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add test coverage for material fallback logic

The line material = this._engine._basicResources.spriteDefaultMaterial; introduces new logic to handle cases where the material has been destroyed. However, static analysis indicates that this line is not covered by existing tests.

Consider adding a unit test to cover this scenario to ensure that the fallback to the default material behaves as expected when the original material is destroyed.

Would you like assistance in creating a test case for this?

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 335-335: packages/core/src/2d/sprite/SpriteRenderer.ts#L335
Added line #L335 was not covered by tests

}

// Update position
Expand Down Expand Up @@ -395,28 +393,6 @@
this._dirtyUpdateFlag &= ~SpriteRendererUpdateFlags.AutomaticSize;
}

private _updateStencilState(from: SpriteMaskInteraction, to: SpriteMaskInteraction): void {
const material = this.getMaterial();
const { _spriteDefaultMaterials: spriteDefaultMaterials } = this._engine;
if (material === spriteDefaultMaterials[from]) {
this.setMaterial(spriteDefaultMaterials[to]);
} else {
const { stencilState } = material.renderState;
if (to === SpriteMaskInteraction.None) {
stencilState.enabled = false;
stencilState.writeMask = 0xff;
stencilState.referenceValue = 0;
stencilState.compareFunctionFront = stencilState.compareFunctionBack = CompareFunction.Always;
} else {
stencilState.enabled = true;
stencilState.writeMask = 0x00;
stencilState.referenceValue = 1;
stencilState.compareFunctionFront = stencilState.compareFunctionBack =
to === SpriteMaskInteraction.VisibleInsideMask ? CompareFunction.LessEqual : CompareFunction.Greater;
}
}
}

@ignoreClone
private _onSpriteChange(type: SpriteModifyFlags): void {
switch (type) {
Expand Down
35 changes: 2 additions & 33 deletions packages/core/src/2d/text/TextRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { Renderer } from "../../Renderer";
import { TransformModifyFlags } from "../../Transform";
import { assignmentClone, deepClone, ignoreClone } from "../../clone/CloneManager";
import { ShaderData, ShaderProperty } from "../../shader";
import { CompareFunction } from "../../shader/enums/CompareFunction";
import { ShaderDataGroup } from "../../shader/enums/ShaderDataGroup";
import { Texture2D } from "../../texture";
import { FontStyle } from "../enums/FontStyle";
Expand Down Expand Up @@ -250,7 +249,6 @@ export class TextRenderer extends Renderer {
set maskInteraction(value: SpriteMaskInteraction) {
if (this._maskInteraction !== value) {
this._maskInteraction = value;
this._setDirtyFlagTrue(DirtyFlag.MaskInteraction);
}
}

Expand Down Expand Up @@ -294,7 +292,7 @@ export class TextRenderer extends Renderer {
const { engine } = this;
this._font = engine._textDefaultFont;
this._addResourceReferCount(this._font, 1);
this.setMaterial(engine._textDefaultMaterial);
this.setMaterial(engine._basicResources.textDefaultMaterial);
//@ts-ignore
this._color._onValueChanged = this._onColorChanged.bind(this);
}
Expand Down Expand Up @@ -394,11 +392,6 @@ export class TextRenderer extends Renderer {
return;
}

if (this._isContainDirtyFlag(DirtyFlag.MaskInteraction)) {
this._updateStencilState();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before implement is different!

this._setDirtyFlagFalse(DirtyFlag.MaskInteraction);
}

if (this._isContainDirtyFlag(DirtyFlag.SubFont)) {
this._resetSubFont();
this._setDirtyFlagFalse(DirtyFlag.SubFont);
Expand Down Expand Up @@ -437,29 +430,6 @@ export class TextRenderer extends Renderer {
camera._renderPipeline.pushRenderElement(context, renderElement);
}

private _updateStencilState(): void {
const material = this.getInstanceMaterial();
const stencilState = material.renderState.stencilState;
const maskInteraction = this._maskInteraction;

if (maskInteraction === SpriteMaskInteraction.None) {
stencilState.enabled = false;
stencilState.writeMask = 0xff;
stencilState.referenceValue = 0;
stencilState.compareFunctionFront = stencilState.compareFunctionBack = CompareFunction.Always;
} else {
stencilState.enabled = true;
stencilState.writeMask = 0x00;
stencilState.referenceValue = 1;
const compare =
maskInteraction === SpriteMaskInteraction.VisibleInsideMask
? CompareFunction.LessEqual
: CompareFunction.Greater;
stencilState.compareFunctionFront = compare;
stencilState.compareFunctionBack = compare;
}
}

private _resetSubFont(): void {
const font = this._font;
this._subFont = font._getSubFont(this.fontSize, this.fontStyle);
Expand Down Expand Up @@ -762,8 +732,7 @@ enum DirtyFlag {
LocalPositionBounds = 0x2,
WorldPosition = 0x4,
WorldBounds = 0x8,
MaskInteraction = 0x10,
Color = 0x20,
Color = 0x10,

Position = LocalPositionBounds | WorldPosition | WorldBounds,
Font = SubFont | Position
Comment on lines +735 to 738
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Incomplete Removal of DirtyFlag.MaskInteraction References

The search revealed multiple remaining references to DirtyFlag.MaskInteraction across various test and source files. This indicates that the removal of the MaskInteraction flag was not fully completed and may lead to potential issues.

  • Affected Files:
    • tests/src/core/SpriteRenderer.test.ts
    • packages/core/src/RenderPipeline/RenderQueue.ts
    • packages/core/src/Renderer.ts
    • packages/core/src/2d/text/TextRenderer.ts
    • And others as listed in the search results.

Please address these remaining references to ensure the DirtyFlag enum changes are fully integrated and do not cause inconsistencies or errors in the codebase.

🔗 Analysis chain

Verify the impact of DirtyFlag enum changes.

The DirtyFlag enum has been updated: the MaskInteraction flag has been removed, and the Color flag now occupies its previous position (0x10). This change suggests that mask interaction functionality has been removed or significantly altered.

Please ensure that:

  1. All references to DirtyFlag.MaskInteraction have been removed or updated throughout the codebase.
  2. The removal of mask interaction doesn't negatively impact existing functionality.
  3. Color-related operations now correctly use the DirtyFlag.Color flag.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining references to DirtyFlag.MaskInteraction
echo "Searching for DirtyFlag.MaskInteraction references:"
rg "DirtyFlag\.MaskInteraction" --type ts

# Search for uses of DirtyFlag.Color to ensure it's being used correctly
echo "Searching for DirtyFlag.Color usage:"
rg "DirtyFlag\.Color" --type ts

Length of output: 41441

Expand Down
37 changes: 37 additions & 0 deletions packages/core/src/BasicResources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { MeshTopology } from "./graphic/enums/MeshTopology";
import { VertexElementFormat } from "./graphic/enums/VertexElementFormat";
import { Material } from "./material";
import { ModelMesh } from "./mesh";
import { BlendFactor, BlendOperation, ColorWriteMask, CullMode, RenderQueueType } from "./shader";
import { Shader } from "./shader/Shader";
import { Texture, Texture2D, TextureCube, TextureCubeFace } from "./texture";
import { Texture2DArray } from "./texture/Texture2DArray";
Expand All @@ -29,6 +30,10 @@ export class BasicResources {
readonly whiteTexture2DArray: Texture2DArray;
readonly uintWhiteTexture2D: Texture2D;

readonly spriteDefaultMaterial: Material;
readonly textDefaultMaterial: Material;
readonly spriteMaskDefaultMaterial: Material;

constructor(engine: Engine) {
// prettier-ignore
const vertices = new Float32Array([
Expand Down Expand Up @@ -74,6 +79,10 @@ export class BasicResources {
whitePixel32
);
}

this.spriteDefaultMaterial = this._create2DMaterial(engine, Shader.find("Sprite"));
this.textDefaultMaterial = this._create2DMaterial(engine, Shader.find("Text"));
this.spriteMaskDefaultMaterial = this._createSpriteMaskMaterial(engine);
}

private _createBlitMesh(engine: Engine, vertices: Float32Array): ModelMesh {
Expand Down Expand Up @@ -140,6 +149,34 @@ export class BasicResources {
);
return texture as T;
}

private _create2DMaterial(engine: Engine, shader: Shader): Material {
const material = new Material(engine, shader);
const renderState = material.renderState;
const target = renderState.blendState.targetBlendState;
target.enabled = true;
target.sourceColorBlendFactor = BlendFactor.SourceAlpha;
target.destinationColorBlendFactor = BlendFactor.OneMinusSourceAlpha;
target.sourceAlphaBlendFactor = BlendFactor.One;
target.destinationAlphaBlendFactor = BlendFactor.OneMinusSourceAlpha;
target.colorBlendOperation = target.alphaBlendOperation = BlendOperation.Add;
renderState.depthState.writeEnabled = false;
renderState.rasterState.cullMode = CullMode.Off;
renderState.renderQueueType = RenderQueueType.Transparent;
material.isGCIgnored = true;
return material;
}

private _createSpriteMaskMaterial(engine: Engine): Material {
const material = new Material(engine, Shader.find("SpriteMask"));
const renderState = material.renderState;
renderState.blendState.targetBlendState.colorWriteMask = ColorWriteMask.None;
renderState.rasterState.cullMode = CullMode.Off;
renderState.stencilState.enabled = true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe don't need

renderState.depthState.enabled = false;
material.isGCIgnored = true;
return material;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

⚠️ Potential issue

Stencil state configuration is incomplete in _createSpriteMaskMaterial

  • The stencil state is enabled (renderState.stencilState.enabled = true) but lacks additional configurations such as stencil function, reference value, mask, and operations. This may lead to unintended interactions with other materials using the stencil buffer.
🔗 Analysis chain

Verify stencil state configuration for sprite masking

In the _createSpriteMaskMaterial method, the stencil state is enabled (renderState.stencilState.enabled = true), but additional stencil configurations (e.g., stencil function, reference value, mask, operations) are not specified. This may lead to unintended interactions with other materials using the stencil buffer. Ensure that the stencil state is fully configured to achieve the desired masking effect and to prevent conflicts.

Run the following script to verify stencil state configurations in other materials:

This script searches for instances where renderState.stencilState.enabled is set to true and displays the following 10 lines to examine how stencil states are typically configured elsewhere in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for full stencil state configurations in the codebase.

# Expected: Find examples where stencil state is fully configured after being enabled.
rg --type typescript -A 10 'renderState\.stencilState\.enabled\s*=\s*true'

Length of output: 111


Script:

#!/bin/bash
# Description: Search for full stencil state configurations in TypeScript files.

# Expected: Find examples where stencil state is fully configured after being enabled.
rg -g "*.ts" -g "*.tsx" -A 10 'renderState\.stencilState\.enabled\s*=\s*true'

Length of output: 689

}

enum TextureType {
Expand Down
85 changes: 0 additions & 85 deletions packages/core/src/Engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
IXRDevice
} from "@galacean/engine-design";
import { Color } from "@galacean/engine-math";
import { SpriteMaskInteraction } from "./2d";
import { CharRenderInfo } from "./2d/text/CharRenderInfo";
import { Font } from "./2d/text/Font";
import { BasicResources } from "./BasicResources";
Expand All @@ -30,18 +29,12 @@ import { Material } from "./material/Material";
import { ParticleBufferUtils } from "./particle/ParticleBufferUtils";
import { PhysicsScene } from "./physics/PhysicsScene";
import { ColliderShape } from "./physics/shape/ColliderShape";
import { CompareFunction } from "./shader";
import { Shader } from "./shader/Shader";
import { ShaderMacro } from "./shader/ShaderMacro";
import { ShaderMacroCollection } from "./shader/ShaderMacroCollection";
import { ShaderPass } from "./shader/ShaderPass";
import { ShaderPool } from "./shader/ShaderPool";
import { ShaderProgramPool } from "./shader/ShaderProgramPool";
import { BlendFactor } from "./shader/enums/BlendFactor";
import { BlendOperation } from "./shader/enums/BlendOperation";
import { ColorWriteMask } from "./shader/enums/ColorWriteMask";
import { CullMode } from "./shader/enums/CullMode";
import { RenderQueueType } from "./shader/enums/RenderQueueType";
import { RenderState } from "./shader/state/RenderState";
import { Texture2D, TextureFormat } from "./texture";
import { ClearableObjectPool } from "./utils/ClearableObjectPool";
Expand Down Expand Up @@ -93,14 +86,6 @@ export class Engine extends EventDispatcher {
/* @internal */
_basicResources: BasicResources;
/* @internal */
_spriteDefaultMaterial: Material;
/** @internal */
_spriteDefaultMaterials: Material[] = [];
/* @internal */
_textDefaultMaterial: Material;
/* @internal */
_spriteMaskDefaultMaterial: Material;
/* @internal */
_textDefaultFont: Font;
/* @internal */
_renderContext: RenderContext = new RenderContext();
Expand Down Expand Up @@ -239,18 +224,6 @@ export class Engine extends EventDispatcher {

this._canvas = canvas;

const { _spriteDefaultMaterials: spriteDefaultMaterials } = this;
this._spriteDefaultMaterial = spriteDefaultMaterials[SpriteMaskInteraction.None] = this._createSpriteMaterial(
SpriteMaskInteraction.None
);
spriteDefaultMaterials[SpriteMaskInteraction.VisibleInsideMask] = this._createSpriteMaterial(
SpriteMaskInteraction.VisibleInsideMask
);
spriteDefaultMaterials[SpriteMaskInteraction.VisibleOutsideMask] = this._createSpriteMaterial(
SpriteMaskInteraction.VisibleOutsideMask
);
this._textDefaultMaterial = this._createTextMaterial();
this._spriteMaskDefaultMaterial = this._createSpriteMaskMaterial();
this._textDefaultFont = Font.createFromOS(this, "Arial");
this._textDefaultFont.isGCIgnored = true;

Expand Down Expand Up @@ -581,64 +554,6 @@ export class Engine extends EventDispatcher {
return Promise.all(initializePromises).then(() => this);
}

private _createSpriteMaterial(maskInteraction: SpriteMaskInteraction): Material {
const material = new Material(this, Shader.find("Sprite"));
const renderState = material.renderState;
const target = renderState.blendState.targetBlendState;
target.enabled = true;
target.sourceColorBlendFactor = BlendFactor.SourceAlpha;
target.destinationColorBlendFactor = BlendFactor.OneMinusSourceAlpha;
target.sourceAlphaBlendFactor = BlendFactor.One;
target.destinationAlphaBlendFactor = BlendFactor.OneMinusSourceAlpha;
target.colorBlendOperation = target.alphaBlendOperation = BlendOperation.Add;
if (maskInteraction !== SpriteMaskInteraction.None) {
const stencilState = renderState.stencilState;
stencilState.enabled = true;
stencilState.writeMask = 0x00;
stencilState.referenceValue = 1;
const compare =
maskInteraction === SpriteMaskInteraction.VisibleInsideMask
? CompareFunction.LessEqual
: CompareFunction.Greater;
stencilState.compareFunctionFront = compare;
stencilState.compareFunctionBack = compare;
}
renderState.depthState.writeEnabled = false;
renderState.rasterState.cullMode = CullMode.Off;
renderState.renderQueueType = RenderQueueType.Transparent;
material.isGCIgnored = true;
return material;
}

private _createSpriteMaskMaterial(): Material {
const material = new Material(this, Shader.find("SpriteMask"));
const renderState = material.renderState;
renderState.blendState.targetBlendState.colorWriteMask = ColorWriteMask.None;
renderState.rasterState.cullMode = CullMode.Off;
renderState.stencilState.enabled = true;
renderState.depthState.enabled = false;
renderState.renderQueueType = RenderQueueType.Transparent;
material.isGCIgnored = true;
return material;
}

private _createTextMaterial(): Material {
const material = new Material(this, Shader.find("Text"));
const renderState = material.renderState;
const target = renderState.blendState.targetBlendState;
target.enabled = true;
target.sourceColorBlendFactor = BlendFactor.SourceAlpha;
target.destinationColorBlendFactor = BlendFactor.OneMinusSourceAlpha;
target.sourceAlphaBlendFactor = BlendFactor.One;
target.destinationAlphaBlendFactor = BlendFactor.OneMinusSourceAlpha;
target.colorBlendOperation = target.alphaBlendOperation = BlendOperation.Add;
renderState.depthState.writeEnabled = false;
renderState.rasterState.cullMode = CullMode.Off;
renderState.renderQueueType = RenderQueueType.Transparent;
material.isGCIgnored = true;
return material;
}

private _onDeviceLost(): void {
this._isDeviceLost = true;
// Lose graphic resources
Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/RenderPipeline/BasicRenderPipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ export class BasicRenderPipeline {
const clearFlags = camera.clearFlags & ~(ignoreClear ?? CameraClearFlags.None);
const color = background.solidColor;
if (clearFlags !== CameraClearFlags.None) {
rhi.clearRenderTarget(camera.engine, clearFlags, color);
rhi.clearRenderTarget(engine, clearFlags, color);
}

opaqueQueue.render(context, PipelineStage.Forward);
Expand Down Expand Up @@ -195,6 +195,9 @@ export class BasicRenderPipeline {
}

transparentQueue.render(context, PipelineStage.Forward);
// Reset stencil
scene._maskManager.clearMask(context, PipelineStage.Forward);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why clear here?

scene._stencilManager.clearStencil();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Stencil state manipulations found outside of StencilManager

The verification process revealed several instances where stencil state operations are performed outside of the StencilManager. This breaks the centralized management of stencil states and could lead to inconsistent rendering behaviors.

Please refactor these instances to ensure all stencil operations are handled through StencilManager.

🔗 Analysis chain

Verify stencil reset and mask clearing

The addition of stencil reset and mask clearing after rendering the transparent queue is a good step towards addressing the concerns raised in the PR comments. This change should help manage stencil states more effectively.

To ensure this change resolves the issues mentioned in the PR comments, please run the following verification:

These tests will help ensure that the stencil and mask management is now centralized and consistent across the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining stencil or mask-related issues after these changes

# Test 1: Search for any remaining stencil-related TODOs or FIXMEs
echo "Searching for stencil-related TODOs or FIXMEs:"
rg -i "TODO|FIXME" -g "*.ts" | rg -i "stencil"

# Test 2: Search for any remaining mask-related TODOs or FIXMEs
echo "Searching for mask-related TODOs or FIXMEs:"
rg -i "TODO|FIXME" -g "*.ts" | rg -i "mask"

# Test 3: Check for any direct stencil state manipulations outside of StencilManager
echo "Checking for direct stencil state manipulations:"
rg "stencil" -g "*.ts" | rg -v "StencilManager"

# Test 4: Verify that MaskManager is used consistently
echo "Verifying consistent use of MaskManager:"
rg "MaskManager" -g "*.ts"

Length of output: 17524


const postProcessManager = scene._postProcessManager;
const cameraRenderTarget = camera.renderTarget;
Expand Down
Loading
Loading