From 7791c4f6a27a015c818952f24bece3118790236b Mon Sep 17 00:00:00 2001 From: Ryan Tremblay Date: Fri, 11 Jul 2025 16:01:02 -0700 Subject: [PATCH 1/3] Add missing add/remove observables and functions for effect layers Add uniqueId to EffectLayer Add initial impl of effect layer explorer --- packages/dev/core/src/Layers/effectLayer.ts | 6 ++ .../src/Layers/effectLayerSceneComponent.ts | 21 +------ packages/dev/core/src/scene.ts | 49 +++++++++++++-- packages/dev/inspector-v2/src/inspector.tsx | 2 + .../panes/scene/defaultSectionsMetadata.ts | 11 ++-- .../scene/effectLayersExplorerService.tsx | 59 +++++++++++++++++++ 6 files changed, 120 insertions(+), 28 deletions(-) create mode 100644 packages/dev/inspector-v2/src/services/panes/scene/effectLayersExplorerService.tsx diff --git a/packages/dev/core/src/Layers/effectLayer.ts b/packages/dev/core/src/Layers/effectLayer.ts index 8f939da56d7..00bf4818f97 100644 --- a/packages/dev/core/src/Layers/effectLayer.ts +++ b/packages/dev/core/src/Layers/effectLayer.ts @@ -23,6 +23,7 @@ import { _WarnImport } from "../Misc/devTools"; import { GetExponentOfTwo } from "../Misc/tools.functions"; import type { ShaderLanguage } from "core/Materials/shaderLanguage"; import { ThinEffectLayer } from "./thinEffectLayer"; +import { UniqueIdGenerator } from "core/Misc/uniqueIdGenerator"; /** * Effect layer options. This helps customizing the behaviour @@ -117,6 +118,11 @@ export abstract class EffectLayer { ThinEffectLayer.ForceGLSL = value; } + /** + * The unique id of the layer + */ + public readonly uniqueId = UniqueIdGenerator.UniqueId; + /** * The name of the layer */ diff --git a/packages/dev/core/src/Layers/effectLayerSceneComponent.ts b/packages/dev/core/src/Layers/effectLayerSceneComponent.ts index d499f6a77bf..7411d524e0f 100644 --- a/packages/dev/core/src/Layers/effectLayerSceneComponent.ts +++ b/packages/dev/core/src/Layers/effectLayerSceneComponent.ts @@ -28,32 +28,17 @@ AddParser(SceneComponentConstants.NAME_EFFECTLAYER, (parsedData: any, scene: Sce declare module "../scene" { // eslint-disable-next-line @typescript-eslint/naming-convention export interface Scene { - /** - * Removes the given effect layer from this scene. - * @param toRemove defines the effect layer to remove - * @returns the index of the removed effect layer - */ - removeEffectLayer(toRemove: EffectLayer): number; - /** * Adds the given effect layer to this scene * @param newEffectLayer defines the effect layer to add + * @deprecated Please use addNewEffectLayer instead. */ addEffectLayer(newEffectLayer: EffectLayer): void; } } -Scene.prototype.removeEffectLayer = function (toRemove: EffectLayer): number { - const index = this.effectLayers.indexOf(toRemove); - if (index !== -1) { - this.effectLayers.splice(index, 1); - } - - return index; -}; - Scene.prototype.addEffectLayer = function (newEffectLayer: EffectLayer): void { - this.effectLayers.push(newEffectLayer); + this.addNewEffectLayer(newEffectLayer); }; /** @@ -140,7 +125,7 @@ export class EffectLayerSceneComponent implements ISceneSerializableComponent { return; } for (const o of container.effectLayers) { - this.scene.addEffectLayer(o); + this.scene.addNewEffectLayer(o); } } diff --git a/packages/dev/core/src/scene.ts b/packages/dev/core/src/scene.ts index efec6e46020..17e186d391b 100644 --- a/packages/dev/core/src/scene.ts +++ b/packages/dev/core/src/scene.ts @@ -876,11 +876,6 @@ export class Scene implements IAnimatable, IClipPlanesHolder, IAssetContainer { */ public onNewMultiMaterialAddedObservable = new Observable(); - /** - * An event triggered when a post process is created - */ - public onNewPostProcessAddedObservable = new Observable(); - /** * An event triggered when a material is removed */ @@ -911,11 +906,26 @@ export class Scene implements IAnimatable, IClipPlanesHolder, IAssetContainer { */ public onFrameGraphRemovedObservable = new Observable(); + /** + * An event triggered when a post process is created + */ + public onNewPostProcessAddedObservable = new Observable(); + /** * An event triggered when a post process is removed */ public onPostProcessRemovedObservable = new Observable(); + /** + * An event triggered when an effect layer is created + */ + public onNewEffectLayerAddedObservable = new Observable(); + + /** + * An event triggered when an effect layer is removed + */ + public onEffectLayerRemovedObservable = new Observable(); + /** * An event triggered when render targets are about to be rendered * Can happen multiple times per frame. @@ -3087,6 +3097,21 @@ export class Scene implements IAnimatable, IClipPlanesHolder, IAssetContainer { return index; } + /** + * Removes the given layer from this scene. + * @param toRemove The layer to remove + * @returns The index of the removed layer + */ + public removeEffectLayer(toRemove: EffectLayer): number { + const index = this.effectLayers.indexOf(toRemove); + if (index !== -1) { + this.effectLayers.splice(index, 1); + } + this.onEffectLayerRemovedObservable.notifyObservers(toRemove); + + return index; + } + /** * Adds the given light to this scene * @param newLight The light to add @@ -3307,6 +3332,20 @@ export class Scene implements IAnimatable, IClipPlanesHolder, IAssetContainer { }); } + /** + * Adds the given effect layer to this scene. + * @param newEffectLayer The effect layer to add + */ + public addNewEffectLayer(newEffectLayer: EffectLayer): void { + if (this._blockEntityCollection) { + return; + } + this.effectLayers.push(newEffectLayer); + Tools.SetImmediate(() => { + this.onNewEffectLayerAddedObservable.notifyObservers(newEffectLayer); + }); + } + /** * Switch active camera * @param newCamera defines the new active camera diff --git a/packages/dev/inspector-v2/src/inspector.tsx b/packages/dev/inspector-v2/src/inspector.tsx index e75f9dad5b3..cd6e644d757 100644 --- a/packages/dev/inspector-v2/src/inspector.tsx +++ b/packages/dev/inspector-v2/src/inspector.tsx @@ -28,6 +28,7 @@ import { SkeletonPropertiesServiceDefinition } from "./services/panes/properties import { SpritePropertiesServiceDefinition } from "./services/panes/properties/spritePropertiesService"; import { TransformPropertiesServiceDefinition } from "./services/panes/properties/transformPropertiesService"; import { AnimationGroupExplorerServiceDefinition } from "./services/panes/scene/animationGroupExplorerService"; +import { EffectLayerExplorerServiceDefinition } from "./services/panes/scene/effectLayersExplorerService"; import { FrameGraphExplorerServiceDefinition } from "./services/panes/scene/frameGraphExplorerService"; import { GuiExplorerServiceDefinition } from "./services/panes/scene/guiExplorerService"; import { MaterialExplorerServiceDefinition } from "./services/panes/scene/materialExplorerService"; @@ -191,6 +192,7 @@ function _ShowInspector(scene: Nullable, options: Partial = { + friendlyName: "Effect Layer Explorer", + consumes: [SceneExplorerServiceIdentity, SceneContextIdentity], + factory: (sceneExplorerService, sceneContext) => { + const scene = sceneContext.currentScene; + if (!scene) { + return undefined; + } + + const sectionRegistration = sceneExplorerService.addSection({ + displayName: "Effect Layers", + order: DefaultSectionsOrder.EffectLayers, + predicate: (entity) => entity instanceof EffectLayer, + getRootEntities: () => scene.effectLayers, + getEntityDisplayInfo: (effectLayer) => { + const onChangeObservable = new Observable(); + + const nameHookToken = InterceptProperty(effectLayer, "name", { + afterSet: () => { + onChangeObservable.notifyObservers(); + }, + }); + + return { + get name() { + return effectLayer.name; + }, + onChange: onChangeObservable, + dispose: () => { + nameHookToken.dispose(); + onChangeObservable.clear(); + }, + }; + }, + entityIcon: () => , + getEntityAddedObservables: () => [scene.onNewEffectLayerAddedObservable], + getEntityRemovedObservables: () => [scene.onEffectLayerRemovedObservable], + }); + + return { + dispose: () => { + sectionRegistration.dispose(); + }, + }; + }, +}; From ceebf20a61187182c2837e3755a5173d6e6b8841 Mon Sep 17 00:00:00 2001 From: Ryan Tremblay Date: Fri, 11 Jul 2025 16:09:50 -0700 Subject: [PATCH 2/3] Fix wonk --- .../src/Layers/effectLayerSceneComponent.ts | 20 ++----------------- packages/dev/core/src/scene.ts | 2 +- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/packages/dev/core/src/Layers/effectLayerSceneComponent.ts b/packages/dev/core/src/Layers/effectLayerSceneComponent.ts index 7411d524e0f..48ac89e7d74 100644 --- a/packages/dev/core/src/Layers/effectLayerSceneComponent.ts +++ b/packages/dev/core/src/Layers/effectLayerSceneComponent.ts @@ -1,5 +1,5 @@ import { Camera } from "../Cameras/camera"; -import { Scene } from "../scene"; +import type { Scene } from "../scene"; import type { AbstractEngine } from "../Engines/abstractEngine"; import type { AbstractMesh } from "../Meshes/abstractMesh"; import type { RenderTargetTexture } from "../Materials/Textures/renderTargetTexture"; @@ -25,22 +25,6 @@ AddParser(SceneComponentConstants.NAME_EFFECTLAYER, (parsedData: any, scene: Sce } }); -declare module "../scene" { - // eslint-disable-next-line @typescript-eslint/naming-convention - export interface Scene { - /** - * Adds the given effect layer to this scene - * @param newEffectLayer defines the effect layer to add - * @deprecated Please use addNewEffectLayer instead. - */ - addEffectLayer(newEffectLayer: EffectLayer): void; - } -} - -Scene.prototype.addEffectLayer = function (newEffectLayer: EffectLayer): void { - this.addNewEffectLayer(newEffectLayer); -}; - /** * Defines the layer scene component responsible to manage any effect layers * in a given scene. @@ -125,7 +109,7 @@ export class EffectLayerSceneComponent implements ISceneSerializableComponent { return; } for (const o of container.effectLayers) { - this.scene.addNewEffectLayer(o); + this.scene.addEffectLayer(o); } } diff --git a/packages/dev/core/src/scene.ts b/packages/dev/core/src/scene.ts index 17e186d391b..10d8d5af169 100644 --- a/packages/dev/core/src/scene.ts +++ b/packages/dev/core/src/scene.ts @@ -3336,7 +3336,7 @@ export class Scene implements IAnimatable, IClipPlanesHolder, IAssetContainer { * Adds the given effect layer to this scene. * @param newEffectLayer The effect layer to add */ - public addNewEffectLayer(newEffectLayer: EffectLayer): void { + public addEffectLayer(newEffectLayer: EffectLayer): void { if (this._blockEntityCollection) { return; } From 1573682ef27556d506dd4e193ff0a4add905cd68 Mon Sep 17 00:00:00 2001 From: Ryan Tremblay Date: Fri, 11 Jul 2025 16:16:21 -0700 Subject: [PATCH 3/3] Add mising calls to add/remove --- packages/dev/core/src/Layers/effectLayer.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/dev/core/src/Layers/effectLayer.ts b/packages/dev/core/src/Layers/effectLayer.ts index 00bf4818f97..705d69aa0d2 100644 --- a/packages/dev/core/src/Layers/effectLayer.ts +++ b/packages/dev/core/src/Layers/effectLayer.ts @@ -316,7 +316,7 @@ export abstract class EffectLayer { this._engine = this._scene.getEngine(); this._maxSize = this._engine.getCaps().maxTextureSize; - this._scene.effectLayers.push(this); + this._scene.addEffectLayer(this); this._thinEffectLayer.onDisposeObservable.add(() => { this.onDisposeObservable.notifyObservers(this); @@ -648,10 +648,7 @@ export abstract class EffectLayer { this._disposeTextureAndPostProcesses(); // Remove from scene - const index = this._scene.effectLayers.indexOf(this, 0); - if (index > -1) { - this._scene.effectLayers.splice(index, 1); - } + this._scene.removeEffectLayer(this); // Callback this.onDisposeObservable.clear();