From 7fae92c8d3bcaf0efcec55eedcddfea73725c965 Mon Sep 17 00:00:00 2001 From: zhuxudong Date: Mon, 6 Jan 2025 16:59:31 +0800 Subject: [PATCH] Refactor `PostProcessParameter` to strong type (#2487) * refactor: `PostProcessParameter` to strong type --- e2e/case/postProcess-customPass.ts | 5 +- packages/core/src/postProcess/PostProcess.ts | 8 + .../postProcess/PostProcessEffectParameter.ts | 240 +++++++++++++----- .../src/postProcess/effects/BloomEffect.ts | 25 +- .../postProcess/effects/TonemappingEffect.ts | 4 +- packages/core/src/postProcess/index.ts | 12 +- .../src/core/postProcess/PostProcess.test.ts | 23 +- 7 files changed, 228 insertions(+), 89 deletions(-) diff --git a/e2e/case/postProcess-customPass.ts b/e2e/case/postProcess-customPass.ts index 102142159..9799fe784 100644 --- a/e2e/case/postProcess-customPass.ts +++ b/e2e/case/postProcess-customPass.ts @@ -9,6 +9,7 @@ import { Engine, Material, PostProcess, + PostProcessEffectFloatParameter, PostProcessPass, PostProcessPassEvent, RenderTarget, @@ -43,9 +44,7 @@ void main() { class CustomPass extends PostProcessPass { private _blitMaterial: Material; - set intensity(value) { - this._blitMaterial.shaderData.setFloat("intensity", value); - } + intensity = new PostProcessEffectFloatParameter(0.7, 0, 1); constructor(engine: Engine) { super(engine); diff --git a/packages/core/src/postProcess/PostProcess.ts b/packages/core/src/postProcess/PostProcess.ts index d385c7bb5..66521a02f 100644 --- a/packages/core/src/postProcess/PostProcess.ts +++ b/packages/core/src/postProcess/PostProcess.ts @@ -127,4 +127,12 @@ export class PostProcess extends Component { override _onDisableInScene() { this.scene.postProcessManager._removePostProcess(this); } + + /** + * @inheritdoc + */ + override _onDestroy(): void { + super._onDestroy(); + this._effects.length = 0; + } } diff --git a/packages/core/src/postProcess/PostProcessEffectParameter.ts b/packages/core/src/postProcess/PostProcessEffectParameter.ts index 5f13d6075..899860ba7 100644 --- a/packages/core/src/postProcess/PostProcessEffectParameter.ts +++ b/packages/core/src/postProcess/PostProcessEffectParameter.ts @@ -1,21 +1,19 @@ import { Color, MathUtil, Vector2, Vector3, Vector4 } from "@galacean/engine-math"; -import { Texture } from "../texture/Texture"; +import { Texture } from "../texture"; /** * Represents a parameter of a post process effect. * @remarks * The parameter will be mixed to a final value and be used in post process manager. */ -export class PostProcessEffectParameter { +export abstract class PostProcessEffectParameter { /** * Whether the parameter is enabled. */ enabled = true; - private _value: T; - private _needLerp = false; - private _min?: number; - private _max?: number; + protected _needLerp = false; + protected _value: T; /** * The value of the parameter. @@ -25,71 +23,189 @@ export class PostProcessEffectParameter(MathUtil.clamp(value, this._min, this._max)); - } else { - this._value = value; - } + this._value = value; } - constructor(value: Exclude, needLerp?: boolean); - constructor(value: Exclude, needLerp?: boolean); - constructor( - value: Exclude, - min?: number, - max?: number, - needLerp?: boolean - ); - - constructor(value: T, needLerpOrMin?: boolean | number, max?: number, needLerp?: boolean) { - if (typeof value === "number") { - if (typeof needLerpOrMin === "boolean") { - this._needLerp = needLerpOrMin; - this._min = Number.NEGATIVE_INFINITY; - this._max = Number.POSITIVE_INFINITY; - } else if (typeof needLerpOrMin === "number") { - this._min = needLerpOrMin; - this._max = max ?? Number.POSITIVE_INFINITY; - this._needLerp = needLerp ?? false; - } else if (needLerpOrMin == undefined) { - this._min = Number.NEGATIVE_INFINITY; - this._max = Number.POSITIVE_INFINITY; - } - } else { - this._needLerp = needLerpOrMin ?? false; - } - - this.value = value; + constructor(value: T, needLerp = false) { + this._needLerp = needLerp; + this._value = value; } /** * @internal */ _lerp(to: T, factor: number) { - if (this._needLerp) { - switch (this.value?.constructor) { - case Number: - this.value = (MathUtil.lerp(this.value, to, factor)); - break; - case Color: - Color.lerp(this.value, to, factor, this.value); - break; - case Vector2: - Vector2.lerp(this.value, to, factor, this.value); - break; - case Vector3: - Vector3.lerp(this.value, to, factor, this.value); - break; - case Vector4: - Vector4.lerp(this.value, to, factor, this.value); - break; - default: - if (factor > 0) { - this.value = to; - } - } - } else if (factor > 0) { + if (factor > 0) { this.value = to; } } } + +/** + * Represents a float parameter of a post process effect. + */ +export class PostProcessEffectFloatParameter extends PostProcessEffectParameter { + override get value(): number { + return this._value; + } + + override set value(v: number) { + this._value = MathUtil.clamp(v, this.min, this.max); + } + + /** + * Create a new float parameter. + * @param value - The default value of the parameter + * @param _min - The minimum value of the parameter, default is Number.NEGATIVE_INFINITY + * @param _max - The maximum value of the parameter, default is Number.POSITIVE_INFINITY + * @param needLerp - Whether the parameter needs to be lerp, default is true + */ + constructor( + value: number, + readonly min = Number.NEGATIVE_INFINITY, + readonly max = Number.POSITIVE_INFINITY, + needLerp = true + ) { + super(value, needLerp); + this.value = value; + } + + override _lerp(to: number, factor: number) { + if (this._needLerp) { + this.value = MathUtil.lerp(this.value, to, factor); + } else { + super._lerp(to, factor); + } + } +} + +/** + * Represents a boolean parameter of a post process effect. + */ +export class PostProcessEffectBoolParameter extends PostProcessEffectParameter { + /** + * Create a new boolean parameter. + * @param value - The default value of the parameter + */ + constructor(value: boolean) { + super(value, false); + } +} + +/** + * Represents a texture parameter of a post process effect. + */ +export class PostProcessEffectTextureParameter extends PostProcessEffectParameter { + /** + * Create a new texture parameter. + * @param value - The default texture of the parameter + */ + constructor(value: Texture) { + super(value, false); + } +} + +/** + * Represents a color parameter of a post process effect. + */ +export class PostProcessEffectColorParameter extends PostProcessEffectParameter { + /** + * Create a new color parameter. + * @param value - The default color of the parameter + * @param needLerp - Whether the parameter needs to be lerp, default is true + */ + constructor(value: Color, needLerp = true) { + super(value, needLerp); + } + + override _lerp(to: Color, factor: number) { + if (this._needLerp) { + Color.lerp(this.value, to, factor, this.value); + } else { + super._lerp(to, factor); + } + } +} + +/** + * Represents a vector2 parameter of a post process effect. + */ +export class PostProcessEffectVector2Parameter extends PostProcessEffectParameter { + /** + * Create a new vector2 parameter. + * @param value - The default vector2 of the parameter + * @param needLerp - Whether the parameter needs to be lerp, default is true + */ + constructor(value: Vector2, needLerp = true) { + super(value, needLerp); + } + + override _lerp(to: Vector2, factor: number) { + if (this._needLerp) { + Vector2.lerp(this.value, to, factor, this.value); + } else { + super._lerp(to, factor); + } + } +} + +/** + * Represents a vector3 parameter of a post process effect. + */ +export class PostProcessEffectVector3Parameter extends PostProcessEffectParameter { + /** + * Create a new vector3 parameter. + * @param value - The default vector3 of the parameter + * @param needLerp - Whether the parameter needs to be lerp, default is true + */ + constructor(value: Vector3, needLerp = true) { + super(value, needLerp); + } + + override _lerp(to: Vector3, factor: number) { + if (this._needLerp) { + Vector3.lerp(this.value, to, factor, this.value); + } else { + super._lerp(to, factor); + } + } +} + +/** + * Represents a vector4 parameter of a post process effect. + */ +export class PostProcessEffectVector4Parameter extends PostProcessEffectParameter { + /** + * Create a new vector4 parameter. + * @param value - The default vector4 of the parameter + * @param needLerp - Whether the parameter needs to be lerp, default is true + */ + constructor(value: Vector4, needLerp = true) { + super(value, needLerp); + } + + override _lerp(to: Vector4, factor: number) { + if (this._needLerp) { + Vector4.lerp(this.value, to, factor, this.value); + } else { + super._lerp(to, factor); + } + } +} + +/** + * Represents a enum parameter of a post process effect. + */ +export class PostProcessEffectEnumParameter extends PostProcessEffectParameter { + /** + * Create a new enum parameter. + * @param enumType - The type of the enum + * @param value - The default enum value of the parameter + */ + constructor( + readonly enumType: Record, + value: T + ) { + super(value as T, false); + } +} diff --git a/packages/core/src/postProcess/effects/BloomEffect.ts b/packages/core/src/postProcess/effects/BloomEffect.ts index 8c764b9c6..b98a92872 100644 --- a/packages/core/src/postProcess/effects/BloomEffect.ts +++ b/packages/core/src/postProcess/effects/BloomEffect.ts @@ -2,9 +2,14 @@ import { Color } from "@galacean/engine-math"; import { Shader, ShaderMacro, ShaderPass, ShaderProperty } from "../../shader"; import blitVs from "../../shaderlib/extra/Blit.vs.glsl"; -import { Texture2D } from "../../texture"; import { PostProcessEffect } from "../PostProcessEffect"; -import { PostProcessEffectParameter } from "../PostProcessEffectParameter"; +import { + PostProcessEffectBoolParameter, + PostProcessEffectColorParameter, + PostProcessEffectEnumParameter, + PostProcessEffectFloatParameter, + PostProcessEffectTextureParameter +} from "../PostProcessEffectParameter"; import fragBlurH from "../shaders/Bloom/BloomBlurH.glsl"; import fragBlurV from "../shaders/Bloom/BloomBlurV.glsl"; import fragPrefilter from "../shaders/Bloom/BloomPrefilter.glsl"; @@ -55,43 +60,43 @@ export class BloomEffect extends PostProcessEffect { * Controls whether to use bicubic sampling instead of bilinear sampling for the upSampling passes. * @remarks This is slightly more expensive but helps getting smoother visuals. */ - highQualityFiltering = new PostProcessEffectParameter(false); + highQualityFiltering = new PostProcessEffectBoolParameter(false); /** * Controls the starting resolution that this effect begins processing. */ - downScale = new PostProcessEffectParameter(BloomDownScaleMode.Half); + downScale = new PostProcessEffectEnumParameter(BloomDownScaleMode, BloomDownScaleMode.Half); /** * Specifies a Texture to add smudges or dust to the bloom effect. */ - dirtTexture = new PostProcessEffectParameter(null); + dirtTexture = new PostProcessEffectTextureParameter(null); /** * Set the level of brightness to filter out pixels under this level. * @remarks This value is expressed in gamma-space. */ - threshold = new PostProcessEffectParameter(0.9, 0, Number.POSITIVE_INFINITY, true); + threshold = new PostProcessEffectFloatParameter(0.9, 0); /** * Controls the radius of the bloom effect. */ - scatter = new PostProcessEffectParameter(0.7, 0, 1, true); + scatter = new PostProcessEffectFloatParameter(0.7, 0, 1); /** * Controls the strength of the bloom effect. */ - intensity = new PostProcessEffectParameter(0, 0, Number.POSITIVE_INFINITY, true); + intensity = new PostProcessEffectFloatParameter(0, 0); /** * Controls the strength of the lens dirt. */ - dirtIntensity = new PostProcessEffectParameter(0, 0, Number.POSITIVE_INFINITY, true); + dirtIntensity = new PostProcessEffectFloatParameter(0, 0); /** * Specifies the tint of the bloom effect. */ - tint = new PostProcessEffectParameter(new Color(1, 1, 1, 1), true); + tint = new PostProcessEffectColorParameter(new Color(1, 1, 1, 1)); /** @inheritdoc */ override isValid(): boolean { diff --git a/packages/core/src/postProcess/effects/TonemappingEffect.ts b/packages/core/src/postProcess/effects/TonemappingEffect.ts index e66d18d3c..c6e3e0f9a 100644 --- a/packages/core/src/postProcess/effects/TonemappingEffect.ts +++ b/packages/core/src/postProcess/effects/TonemappingEffect.ts @@ -1,6 +1,6 @@ import { ShaderMacro } from "../../shader"; import { PostProcessEffect } from "../PostProcessEffect"; -import { PostProcessEffectParameter } from "../PostProcessEffectParameter"; +import { PostProcessEffectEnumParameter } from "../PostProcessEffectParameter"; /** * Options to select a tonemapping algorithm to use. @@ -28,5 +28,5 @@ export class TonemappingEffect extends PostProcessEffect { /** * Use this to select a tonemapping algorithm to use. */ - mode = new PostProcessEffectParameter(TonemappingMode.Neutral, false); + mode = new PostProcessEffectEnumParameter(TonemappingMode, TonemappingMode.Neutral); } diff --git a/packages/core/src/postProcess/index.ts b/packages/core/src/postProcess/index.ts index 4882605f9..a0bec154a 100644 --- a/packages/core/src/postProcess/index.ts +++ b/packages/core/src/postProcess/index.ts @@ -2,7 +2,17 @@ export * from "./effects"; export { PostProcess } from "./PostProcess"; export { PostProcessEffect } from "./PostProcessEffect"; -export { PostProcessEffectParameter } from "./PostProcessEffectParameter"; +export { + PostProcessEffectBoolParameter, + PostProcessEffectColorParameter, + PostProcessEffectEnumParameter, + PostProcessEffectFloatParameter, + PostProcessEffectParameter, + PostProcessEffectTextureParameter, + PostProcessEffectVector2Parameter, + PostProcessEffectVector3Parameter, + PostProcessEffectVector4Parameter +} from "./PostProcessEffectParameter"; export { PostProcessManager } from "./PostProcessManager"; export { PostProcessPass, PostProcessPassEvent } from "./PostProcessPass"; export { PostProcessUberPass } from "./PostProcessUberPass"; diff --git a/tests/src/core/postProcess/PostProcess.test.ts b/tests/src/core/postProcess/PostProcess.test.ts index ab45e2445..a17432823 100644 --- a/tests/src/core/postProcess/PostProcess.test.ts +++ b/tests/src/core/postProcess/PostProcess.test.ts @@ -7,7 +7,8 @@ import { Entity, PostProcess, PostProcessEffect, - PostProcessEffectParameter, + PostProcessEffectBoolParameter, + PostProcessEffectFloatParameter, PostProcessPass, RenderTarget, Scene, @@ -26,7 +27,7 @@ class CustomPass extends PostProcessPass { } export class CustomEffect extends PostProcessEffect { - intensity = new PostProcessEffectParameter(0, 0, 1, true); + intensity = new PostProcessEffectFloatParameter(0, 0, 1); } describe("PostProcess", () => { @@ -222,12 +223,12 @@ describe("PostProcess", () => { it("Post process effect parameter", () => { { - const p1 = new PostProcessEffectParameter(1); - const p2 = new PostProcessEffectParameter(2, 0, 1); - const p3 = new PostProcessEffectParameter(-2, 0, 1); - const p4 = new PostProcessEffectParameter(10, 0); - const p5 = new PostProcessEffectParameter(-10, 0); - const p6 = new PostProcessEffectParameter(0.5, 0, 1, true); + const p1 = new PostProcessEffectFloatParameter(1); + const p2 = new PostProcessEffectFloatParameter(2, 0, 1); + const p3 = new PostProcessEffectFloatParameter(-2, 0, 1); + const p4 = new PostProcessEffectFloatParameter(10, 0); + const p5 = new PostProcessEffectFloatParameter(-10, 0); + const p6 = new PostProcessEffectFloatParameter(0.5, 0, 1, true); expect(p1.value).to.equal(1); expect(p2.value).to.equal(1); @@ -238,9 +239,9 @@ describe("PostProcess", () => { } { - const p1 = new PostProcessEffectParameter(false); - const p2 = new PostProcessEffectParameter(true); - const p3 = new PostProcessEffectParameter(true, true); + const p1 = new PostProcessEffectBoolParameter(false); + const p2 = new PostProcessEffectBoolParameter(true); + const p3 = new PostProcessEffectBoolParameter(true); expect(p1.value).to.equal(false); expect(p2.value).to.equal(true);