Skip to content

Inspector v2: Add Effect Layers to Scene Explorer #16877

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

Merged
merged 3 commits into from
Jul 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 8 additions & 5 deletions packages/dev/core/src/Layers/effectLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
*/
Expand Down Expand Up @@ -310,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);
Expand Down Expand Up @@ -642,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();
Expand Down
33 changes: 1 addition & 32 deletions packages/dev/core/src/Layers/effectLayerSceneComponent.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -25,37 +25,6 @@ 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
*/
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);
};

/**
* Defines the layer scene component responsible to manage any effect layers
* in a given scene.
Expand Down
49 changes: 44 additions & 5 deletions packages/dev/core/src/scene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -876,11 +876,6 @@ export class Scene implements IAnimatable, IClipPlanesHolder, IAssetContainer {
*/
public onNewMultiMaterialAddedObservable = new Observable<MultiMaterial>();

/**
* An event triggered when a post process is created
*/
public onNewPostProcessAddedObservable = new Observable<PostProcess>();

/**
* An event triggered when a material is removed
*/
Expand Down Expand Up @@ -911,11 +906,26 @@ export class Scene implements IAnimatable, IClipPlanesHolder, IAssetContainer {
*/
public onFrameGraphRemovedObservable = new Observable<FrameGraph>();

/**
* An event triggered when a post process is created
*/
public onNewPostProcessAddedObservable = new Observable<PostProcess>();

/**
* An event triggered when a post process is removed
*/
public onPostProcessRemovedObservable = new Observable<PostProcess>();

/**
* An event triggered when an effect layer is created
*/
public onNewEffectLayerAddedObservable = new Observable<EffectLayer>();

/**
* An event triggered when an effect layer is removed
*/
public onEffectLayerRemovedObservable = new Observable<EffectLayer>();

/**
* An event triggered when render targets are about to be rendered
* Can happen multiple times per frame.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 addEffectLayer(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
Expand Down
2 changes: 2 additions & 0 deletions packages/dev/inspector-v2/src/inspector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -191,6 +192,7 @@ function _ShowInspector(scene: Nullable<Scene>, options: Partial<IInspectorOptio
TextureExplorerServiceDefinition,
PostProcessExplorerServiceDefinition,
RenderingPipelineExplorerServiceDefinition,
EffectLayerExplorerServiceDefinition,
ParticleSystemExplorerServiceDefinition,
SpriteManagerExplorerServiceDefinition,
AnimationGroupExplorerServiceDefinition,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ export const enum DefaultSectionsOrder {
Textures = 400,
PostProcesses = 500,
RenderingPipelines = 600,
ParticleSystems = 700,
SpriteManagers = 800,
AnimationGroups = 900,
GUIs = 1000,
FrameGraphs = 1100,
EffectLayers = 700,
ParticleSystems = 800,
SpriteManagers = 900,
AnimationGroups = 1000,
GUIs = 1100,
FrameGraphs = 1200,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import type { ServiceDefinition } from "../../../modularity/serviceDefinition";
import type { ISceneContext } from "../../sceneContext";
import type { ISceneExplorerService } from "./sceneExplorerService";

import { LayerRegular } from "@fluentui/react-icons";

import { Observable } from "core/Misc";
import { EffectLayer } from "core/Layers/effectLayer";
import { InterceptProperty } from "../../../instrumentation/propertyInstrumentation";
import { SceneContextIdentity } from "../../sceneContext";
import { DefaultSectionsOrder } from "./defaultSectionsMetadata";
import { SceneExplorerServiceIdentity } from "./sceneExplorerService";

export const EffectLayerExplorerServiceDefinition: ServiceDefinition<[], [ISceneExplorerService, ISceneContext]> = {
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<void>();

const nameHookToken = InterceptProperty(effectLayer, "name", {
afterSet: () => {
onChangeObservable.notifyObservers();
},
});

return {
get name() {
return effectLayer.name;
},
onChange: onChangeObservable,
dispose: () => {
nameHookToken.dispose();
onChangeObservable.clear();
},
};
},
entityIcon: () => <LayerRegular />,
getEntityAddedObservables: () => [scene.onNewEffectLayerAddedObservable],
getEntityRemovedObservables: () => [scene.onEffectLayerRemovedObservable],
});

return {
dispose: () => {
sectionRegistration.dispose();
},
};
},
};
Loading