From 33c4370146cecf373f2b3e55432e14867dd2ecb2 Mon Sep 17 00:00:00 2001 From: AZhan Date: Mon, 15 Jul 2024 12:54:59 +0800 Subject: [PATCH] Camera `setReplacementShader` support `ReplacementFailureStrategy ` when failed (#2172) * feat: camera `setReplacementShader` support `ReplacementFailureStrategy ` when failed --- packages/core/src/Camera.ts | 22 ++++++++++++---- .../src/RenderPipeline/BasicRenderPipeline.ts | 3 +++ .../core/src/RenderPipeline/RenderContext.ts | 2 ++ .../src/enums/ReplacementFailureStrategy.ts | 9 +++++++ packages/core/src/index.ts | 1 + tests/src/core/Camera.test.ts | 25 ++++++++++++++++++- 6 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 packages/core/src/enums/ReplacementFailureStrategy.ts diff --git a/packages/core/src/Camera.ts b/packages/core/src/Camera.ts index 2d27892ee..d2ecd294b 100644 --- a/packages/core/src/Camera.ts +++ b/packages/core/src/Camera.ts @@ -15,6 +15,7 @@ import { CameraType } from "./enums/CameraType"; import { DepthTextureMode } from "./enums/DepthTextureMode"; import { Downsampling } from "./enums/Downsampling"; import { MSAASamples } from "./enums/MSAASamples"; +import { ReplacementFailureStrategy } from "./enums/ReplacementFailureStrategy"; import { Shader } from "./shader/Shader"; import { ShaderData } from "./shader/ShaderData"; import { ShaderMacroCollection } from "./shader/ShaderMacroCollection"; @@ -104,6 +105,8 @@ export class Camera extends Component { /** @internal */ _replacementSubShaderTag: ShaderTagKey = null; /** @internal */ + _replacementFailureStrategy: ReplacementFailureStrategy = null; + /** @internal */ @ignoreClone _cameraIndex: number = -1; @@ -610,6 +613,7 @@ export class Camera extends Component { context.virtualCamera = virtualCamera; context.replacementShader = this._replacementShader; context.replacementTag = this._replacementSubShaderTag; + context.replacementFailureStrategy = this._replacementFailureStrategy; // compute cull frustum. if (this.enableFrustumCulling && this._frustumChangeFlag.flag) { @@ -642,28 +646,35 @@ export class Camera extends Component { * Set the replacement shader. * @param shader - Replacement shader * @param replacementTagName - Sub shader tag name + * @param failureStrategy - Replacement failure strategy, @defaultValue `ReplacementFailureStrategy.KeepOriginalShader` * * @remarks * If replacementTagName is not specified, the first sub shader will be replaced. - * If replacementTagName is specified, the replacement shader will find the first sub shader which has the same tag value get by replacementTagKey. + * If replacementTagName is specified, the replacement shader will find the first sub shader which has the same tag value get by replacementTagKey. If failed to find the sub shader, the strategy will be determined by failureStrategy. */ - setReplacementShader(shader: Shader, replacementTagName?: string); + setReplacementShader(shader: Shader, replacementTagName?: string, failureStrategy?: ReplacementFailureStrategy); /** * Set the replacement shader. * @param shader - Replacement shader * @param replacementTag - Sub shader tag + * @param failureStrategy - Replacement failure strategy, @defaultValue `ReplacementFailureStrategy.KeepOriginalShader` * * @remarks * If replacementTag is not specified, the first sub shader will be replaced. - * If replacementTag is specified, the replacement shader will find the first sub shader which has the same tag value get by replacementTagKey. + * If replacementTag is specified, the replacement shader will find the first sub shader which has the same tag value get by replacementTagKey. If failed to find the sub shader, the strategy will be determined by failureStrategy. */ - setReplacementShader(shader: Shader, replacementTag?: ShaderTagKey); + setReplacementShader(shader: Shader, replacementTag?: ShaderTagKey, failureStrategy?: ReplacementFailureStrategy); - setReplacementShader(shader: Shader, replacementTag?: string | ShaderTagKey): void { + setReplacementShader( + shader: Shader, + replacementTag?: string | ShaderTagKey, + failureStrategy: ReplacementFailureStrategy = ReplacementFailureStrategy.KeepOriginalShader + ): void { this._replacementShader = shader; this._replacementSubShaderTag = typeof replacementTag === "string" ? ShaderTagKey.getByName(replacementTag) : replacementTag; + this._replacementFailureStrategy = failureStrategy; } /** @@ -672,6 +683,7 @@ export class Camera extends Component { resetReplacementShader(): void { this._replacementShader = null; this._replacementSubShaderTag = null; + this._replacementFailureStrategy = null; } /** diff --git a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts index 39d5d2742..76af38dc8 100644 --- a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts +++ b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts @@ -6,6 +6,7 @@ import { BackgroundMode } from "../enums/BackgroundMode"; import { BackgroundTextureFillMode } from "../enums/BackgroundTextureFillMode"; import { CameraClearFlags } from "../enums/CameraClearFlags"; import { DepthTextureMode } from "../enums/DepthTextureMode"; +import { ReplacementFailureStrategy } from "../enums/ReplacementFailureStrategy"; import { Shader } from "../shader/Shader"; import { ShaderPass } from "../shader/ShaderPass"; import { RenderQueueType } from "../shader/enums/RenderQueueType"; @@ -239,6 +240,8 @@ export class BasicRenderPipeline { break; } } + context.replacementFailureStrategy === ReplacementFailureStrategy.KeepOriginalShader && + this.pushRenderElementByType(renderElement, subRenderElement, materialSubShader.passes, renderStates); } else { this.pushRenderElementByType(renderElement, subRenderElement, replacementSubShaders[0].passes, renderStates); } diff --git a/packages/core/src/RenderPipeline/RenderContext.ts b/packages/core/src/RenderPipeline/RenderContext.ts index 32db399c4..90995ed49 100644 --- a/packages/core/src/RenderPipeline/RenderContext.ts +++ b/packages/core/src/RenderPipeline/RenderContext.ts @@ -1,6 +1,7 @@ import { Matrix, Vector4 } from "@galacean/engine-math"; import { Camera } from "../Camera"; import { VirtualCamera } from "../VirtualCamera"; +import { ReplacementFailureStrategy } from "../enums/ReplacementFailureStrategy"; import { Shader, ShaderProperty } from "../shader"; import { ShaderTagKey } from "../shader/ShaderTagKey"; @@ -27,6 +28,7 @@ export class RenderContext { replacementShader: Shader; replacementTag: ShaderTagKey; + replacementFailureStrategy: ReplacementFailureStrategy; flipProjection = false; viewMatrix: Matrix; diff --git a/packages/core/src/enums/ReplacementFailureStrategy.ts b/packages/core/src/enums/ReplacementFailureStrategy.ts new file mode 100644 index 000000000..d06d3c8f9 --- /dev/null +++ b/packages/core/src/enums/ReplacementFailureStrategy.ts @@ -0,0 +1,9 @@ +/** + * The strategy to use when a shader replacement fails. + */ +export enum ReplacementFailureStrategy { + /** Keep the original shader. */ + KeepOriginalShader, + /** Do not render. */ + DoNotRender +} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 650027e2d..01952de4e 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -36,6 +36,7 @@ export { FogMode } from "./enums/FogMode"; export { CameraClearFlags } from "./enums/CameraClearFlags"; export { CameraType } from "./enums/CameraType"; export { MSAASamples } from "./enums/MSAASamples"; +export { ReplacementFailureStrategy } from "./enums/ReplacementFailureStrategy"; export { Downsampling } from "./enums/Downsampling"; export { ColorSpace } from "./enums/ColorSpace"; export { BackgroundTextureFillMode } from "./enums/BackgroundTextureFillMode"; diff --git a/tests/src/core/Camera.test.ts b/tests/src/core/Camera.test.ts index 8a6959d5b..6c95f546e 100644 --- a/tests/src/core/Camera.test.ts +++ b/tests/src/core/Camera.test.ts @@ -1,4 +1,4 @@ -import { Camera, CameraClearFlags, Entity, Layer } from "@galacean/engine-core"; +import { Camera, CameraClearFlags, Entity, Layer, ReplacementFailureStrategy, Shader } from "@galacean/engine-core"; import { Matrix, Ray, Vector2, Vector3, Vector4 } from "@galacean/engine-math"; import { WebGLEngine } from "@galacean/engine-rhi-webgl"; import { expect } from "chai"; @@ -78,11 +78,34 @@ describe("camera test", function () { camera.orthographicSize = expectedOrthographicSize; expect(camera.orthographicSize).to.eq(expectedOrthographicSize); camera.orthographicSize = orthographicSize; + const testVS = ` + void main() { + gl_Position = vec4(1.0, 1.0, 1.0, 1.0); + }`; + + const testFS = ` + void main() { + gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); + } + `; + + const shader = Shader.create("TestReplaceShader", testVS, testFS); // Test ReplacementShader + camera.setReplacementShader(shader, "CanReplace"); + expect(camera["_replacementShader"]).to.eq(shader); + expect(camera["_replacementSubShaderTag"].name).to.eq("CanReplace"); + expect(camera["_replacementFailureStrategy"]).to.eq(ReplacementFailureStrategy.KeepOriginalShader); + + camera.setReplacementShader(shader, "CanReplace", ReplacementFailureStrategy.DoNotRender); + expect(camera["_replacementShader"]).to.eq(shader); + expect(camera["_replacementSubShaderTag"].name).to.eq("CanReplace"); + expect(camera["_replacementFailureStrategy"]).to.eq(ReplacementFailureStrategy.DoNotRender); + camera.resetReplacementShader(); expect(camera["_replacementShader"]).to.eq(null); expect(camera["_replacementSubShaderTag"]).to.eq(null); + expect(camera["_replacementFailureStrategy"]).to.eq(null); }); it("static void function", () => {