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 25 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
2 changes: 1 addition & 1 deletion packages/core/src/2d/sprite/SpriteMask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import { SubPrimitiveChunk } from "../../RenderPipeline/SubPrimitiveChunk";
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
26 changes: 1 addition & 25 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 { SubRenderElement } from "../../RenderPipeline/SubRenderElement";
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 @@ export class SpriteRenderer extends Renderer {

set maskInteraction(value: SpriteMaskInteraction) {
if (this._maskInteraction !== value) {
this._updateStencilState(this._maskInteraction, value);
this._maskInteraction = value;
}
}
Expand Down Expand Up @@ -334,7 +332,7 @@ export class SpriteRenderer extends Renderer {
}
// @todo: This question needs to be raised rather than hidden.
if (material.destroyed) {
material = this._engine._spriteDefaultMaterials[this._maskInteraction];
material = this._engine._spriteDefaultMaterial;
}

// Update position
Expand Down Expand Up @@ -395,28 +393,6 @@ export class SpriteRenderer extends Renderer {
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
33 changes: 1 addition & 32 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 @@ -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
30 changes: 2 additions & 28 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,7 +29,6 @@ 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";
Expand Down Expand Up @@ -94,8 +92,6 @@ export class Engine extends EventDispatcher {
_basicResources: BasicResources;
/* @internal */
_spriteDefaultMaterial: Material;
/** @internal */
_spriteDefaultMaterials: Material[] = [];
/* @internal */
_textDefaultMaterial: Material;
/* @internal */
Expand Down Expand Up @@ -239,16 +235,7 @@ 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._spriteDefaultMaterial = this._createSpriteMaterial();
this._textDefaultMaterial = this._createTextMaterial();
this._spriteMaskDefaultMaterial = this._createSpriteMaskMaterial();
this._textDefaultFont = Font.createFromOS(this, "Arial");
Expand Down Expand Up @@ -581,7 +568,7 @@ export class Engine extends EventDispatcher {
return Promise.all(initializePromises).then(() => this);
}

private _createSpriteMaterial(maskInteraction: SpriteMaskInteraction): Material {
private _createSpriteMaterial(): Material {
const material = new Material(this, Shader.find("Sprite"));
const renderState = material.renderState;
const target = renderState.blendState.targetBlendState;
Expand All @@ -591,18 +578,6 @@ export class Engine extends EventDispatcher {
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;
Expand All @@ -617,7 +592,6 @@ export class Engine extends EventDispatcher {
renderState.rasterState.cullMode = CullMode.Off;
renderState.stencilState.enabled = true;
renderState.depthState.enabled = false;
renderState.renderQueueType = RenderQueueType.Transparent;
material.isGCIgnored = true;
return material;
}
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/RenderPipeline/BasicRenderPipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ 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?


const postProcessManager = scene._postProcessManager;
const cameraRenderTarget = camera.renderTarget;
Expand Down
75 changes: 59 additions & 16 deletions packages/core/src/RenderPipeline/MaskManager.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { SpriteMask } from "../2d";
import { SpriteMaskLayer } from "../enums/SpriteMaskLayer";
import { RenderQueueType } from "../shader";
import { DisorderedArray } from "../utils/DisorderedArray";
import { RenderContext } from "./RenderContext";
import { RenderQueue } from "./RenderQueue";
import { SubRenderElement } from "./SubRenderElement";
import { RenderQueueMaskType } from "./enums/RenderQueueMaskType";

/**
* @internal
Expand All @@ -19,29 +21,74 @@ export class MaskManager {
return (MaskManager._maskDecrementRenderQueue ||= new RenderQueue(RenderQueueType.Transparent));
}

allSpriteMasks = new DisorderedArray<SpriteMask>();
preMaskLayer = 0;
private _allSpriteMasks = new DisorderedArray<SpriteMask>();
private _preMaskLayer = SpriteMaskLayer.Nothing;

addSpriteMask(mask: SpriteMask): void {
mask._maskIndex = this.allSpriteMasks.length;
this.allSpriteMasks.add(mask);
mask._maskIndex = this._allSpriteMasks.length;
this._allSpriteMasks.add(mask);
}

removeSpriteMask(mask: SpriteMask): void {
const replaced = this.allSpriteMasks.deleteByIndex(mask._maskIndex);
const replaced = this._allSpriteMasks.deleteByIndex(mask._maskIndex);
replaced && (replaced._maskIndex = mask._maskIndex);
mask._maskIndex = -1;
}
GuoLei1990 marked this conversation as resolved.
Show resolved Hide resolved

buildMaskRenderElement(
element: SubRenderElement,
drawMask(context: RenderContext, pipelineStageTagValue: string, maskLayer: SpriteMaskLayer): void {
const incrementMaskQueue = MaskManager.getMaskIncrementRenderQueue();
incrementMaskQueue.clear();
const decrementMaskQueue = MaskManager.getMaskDecrementRenderQueue();
decrementMaskQueue.clear();

this._buildMaskRenderElement(maskLayer, incrementMaskQueue, decrementMaskQueue);

const engine = context.camera.engine;
const batcherManager = engine._batcherManager;
Copy link
Member

Choose a reason for hiding this comment

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

const batcherManager = context.camera.engine._batcherManager;

incrementMaskQueue.batch(batcherManager);
batcherManager.uploadBuffer();
incrementMaskQueue.render(context, pipelineStageTagValue, RenderQueueMaskType.Increment);
decrementMaskQueue.batch(batcherManager);
batcherManager.uploadBuffer();
decrementMaskQueue.render(context, pipelineStageTagValue, RenderQueueMaskType.Decrement);
}

clearMask(context: RenderContext, pipelineStageTagValue: string): void {
const preMaskLayer = this._preMaskLayer;
if (preMaskLayer !== SpriteMaskLayer.Nothing) {
const decrementMaskQueue = MaskManager.getMaskDecrementRenderQueue();
decrementMaskQueue.clear();

const masks = this._allSpriteMasks;
const maskElements = masks._elements;
for (let i = 0, n = masks.length; i < n; i++) {
const mask = maskElements[i];
mask.influenceLayers & preMaskLayer && decrementMaskQueue.pushRenderElement(mask._renderElement);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve readability by using an explicit if statement

Using logical operators like && for control flow can reduce code readability. Consider refactoring to use an explicit if statement.

Apply this change:

-    mask.influenceLayers & preMaskLayer && decrementMaskQueue.pushRenderElement(mask._renderElement);
+    if (mask.influenceLayers & preMaskLayer) {
+      decrementMaskQueue.pushRenderElement(mask._renderElement);
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
mask.influenceLayers & preMaskLayer && decrementMaskQueue.pushRenderElement(mask._renderElement);
if (mask.influenceLayers & preMaskLayer) {
decrementMaskQueue.pushRenderElement(mask._renderElement);
}

}

const batcherManager = context.camera.engine._batcherManager;
decrementMaskQueue.batch(batcherManager);
batcherManager.uploadBuffer();
decrementMaskQueue.render(context, pipelineStageTagValue, RenderQueueMaskType.Decrement);

this._preMaskLayer = SpriteMaskLayer.Nothing;
}
}

destroy(): void {
const allSpriteMasks = this._allSpriteMasks;
allSpriteMasks.length = 0;
allSpriteMasks.garbageCollection();
}

private _buildMaskRenderElement(
curMaskLayer: SpriteMaskLayer,
incrementMaskQueue: RenderQueue,
decrementMaskQueue: RenderQueue
): void {
const preMaskLayer = this.preMaskLayer;
const curMaskLayer = element.component._maskLayer;
const preMaskLayer = this._preMaskLayer;
if (preMaskLayer !== curMaskLayer) {
const masks = this.allSpriteMasks;
const masks = this._allSpriteMasks;
const commonLayer = preMaskLayer & curMaskLayer;
const reduceLayer = preMaskLayer & ~curMaskLayer;
const maskElements = masks._elements;
Expand All @@ -59,11 +106,7 @@ export class MaskManager {
decrementMaskQueue.pushRenderElement(mask._renderElement);
}
}
this.preMaskLayer = curMaskLayer;
this._preMaskLayer = curMaskLayer;
}
}

destroy(): void {
this.allSpriteMasks.length = 0;
}
}
Loading
Loading