Skip to content

Commit f1e5e82

Browse files
authored
Inspector v2: Add GUI and Frame Graphs to Scene Explorer (#16873)
This PR adds support for GUI (AdvancedDynamicTexture) and Frame Graphs to Scene Explorer. - Configures the gui dependency in the inspector v2 test app and in Playground (when it uses inspector v2). - Add support for the two new scene explorer sections. - NOTE: The gui scene explorer service only imports types from the gui package so that it doesn't cause the gui package to be loaded when it otherwise often will not be.
1 parent e55da60 commit f1e5e82

File tree

7 files changed

+137
-6
lines changed

7 files changed

+137
-6
lines changed

packages/dev/inspector-v2/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"devDependencies": {
1919
"@dev/addons": "^1.0.0",
2020
"@dev/core": "1.0.0",
21+
"@dev/gui": "^1.0.0",
2122
"@dev/loaders": "1.0.0",
2223
"@dev/materials": "^1.0.0",
2324
"@fluentui/react-components": "^9.62.0",

packages/dev/inspector-v2/src/inspector.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import { SkeletonPropertiesServiceDefinition } from "./services/panes/properties
2828
import { SpritePropertiesServiceDefinition } from "./services/panes/properties/spritePropertiesService";
2929
import { TransformPropertiesServiceDefinition } from "./services/panes/properties/transformPropertiesService";
3030
import { AnimationGroupExplorerServiceDefinition } from "./services/panes/scene/animationGroupExplorerService";
31+
import { FrameGraphExplorerServiceDefinition } from "./services/panes/scene/frameGraphExplorerService";
32+
import { GuiExplorerServiceDefinition } from "./services/panes/scene/guiExplorerService";
3133
import { MaterialExplorerServiceDefinition } from "./services/panes/scene/materialExplorerService";
3234
import { NodeHierarchyServiceDefinition } from "./services/panes/scene/nodeExplorerService";
3335
import { ParticleSystemExplorerServiceDefinition } from "./services/panes/scene/particleSystemExplorerService";
@@ -190,6 +192,8 @@ function _ShowInspector(scene: Nullable<Scene>, options: Partial<IInspectorOptio
190192
ParticleSystemExplorerServiceDefinition,
191193
SpriteManagerHierarchyServiceDefinition,
192194
AnimationGroupExplorerServiceDefinition,
195+
GuiExplorerServiceDefinition,
196+
FrameGraphExplorerServiceDefinition,
193197

194198
// Properties pane tab and related services.
195199
PropertiesServiceDefinition,
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import type { ServiceDefinition } from "../../../modularity/serviceDefinition";
2+
import type { ISceneContext } from "../../sceneContext";
3+
import type { ISceneExplorerService } from "./sceneExplorerService";
4+
5+
import { FrameRegular } from "@fluentui/react-icons";
6+
7+
import { FrameGraph } from "core/FrameGraph/frameGraph";
8+
import { Observable } from "core/Misc";
9+
import { InterceptProperty } from "../../../instrumentation/propertyInstrumentation";
10+
import { SceneContextIdentity } from "../../sceneContext";
11+
import { SceneExplorerServiceIdentity } from "./sceneExplorerService";
12+
13+
export const FrameGraphExplorerServiceDefinition: ServiceDefinition<[], [ISceneExplorerService, ISceneContext]> = {
14+
friendlyName: "Frame Graph Hierarchy",
15+
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity],
16+
factory: (sceneExplorerService, sceneContext) => {
17+
const scene = sceneContext.currentScene;
18+
if (!scene) {
19+
return undefined;
20+
}
21+
22+
const sectionRegistration = sceneExplorerService.addSection({
23+
displayName: "Frame Graph",
24+
order: 1000,
25+
predicate: (entity) => entity instanceof FrameGraph,
26+
getRootEntities: () => scene.frameGraphs,
27+
getEntityDisplayInfo: (frameGraph) => {
28+
const onChangeObservable = new Observable<void>();
29+
30+
const nameHookToken = InterceptProperty(frameGraph, "name", {
31+
afterSet: () => {
32+
onChangeObservable.notifyObservers();
33+
},
34+
});
35+
36+
return {
37+
get name() {
38+
return frameGraph.name;
39+
},
40+
onChange: onChangeObservable,
41+
dispose: () => {
42+
nameHookToken.dispose();
43+
onChangeObservable.clear();
44+
},
45+
};
46+
},
47+
entityIcon: () => <FrameRegular />,
48+
getEntityAddedObservables: () => [scene.onNewFrameGraphAddedObservable],
49+
getEntityRemovedObservables: () => [scene.onFrameGraphRemovedObservable],
50+
});
51+
52+
return {
53+
dispose: () => {
54+
sectionRegistration.dispose();
55+
},
56+
};
57+
},
58+
};
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import type { AdvancedDynamicTexture } from "gui/index";
2+
import type { ServiceDefinition } from "../../../modularity/serviceDefinition";
3+
import type { ISceneContext } from "../../sceneContext";
4+
import type { ISceneExplorerService } from "./sceneExplorerService";
5+
6+
import { AppGenericRegular } from "@fluentui/react-icons";
7+
8+
import { Observable } from "core/Misc";
9+
import { InterceptProperty } from "../../../instrumentation/propertyInstrumentation";
10+
import { SceneContextIdentity } from "../../sceneContext";
11+
import { SceneExplorerServiceIdentity } from "./sceneExplorerService";
12+
13+
// Don't use instanceof in this case as we don't want to bring in the gui package just to check if the entity is an AdvancedDynamicTexture.
14+
function IsAdvancedDynamicTexture(entity: unknown): entity is AdvancedDynamicTexture {
15+
return (entity as AdvancedDynamicTexture)?.constructor?.name === "AdvancedDynamicTexture";
16+
}
17+
18+
export const GuiExplorerServiceDefinition: ServiceDefinition<[], [ISceneExplorerService, ISceneContext]> = {
19+
friendlyName: "GUI Hierarchy",
20+
consumes: [SceneExplorerServiceIdentity, SceneContextIdentity],
21+
factory: (sceneExplorerService, sceneContext) => {
22+
const scene = sceneContext.currentScene;
23+
if (!scene) {
24+
return undefined;
25+
}
26+
27+
const sectionRegistration = sceneExplorerService.addSection({
28+
displayName: "GUI",
29+
order: 900,
30+
predicate: IsAdvancedDynamicTexture,
31+
getRootEntities: () => scene.textures.filter(IsAdvancedDynamicTexture),
32+
getEntityDisplayInfo: (texture) => {
33+
const onChangeObservable = new Observable<void>();
34+
35+
const nameHookToken = InterceptProperty(texture, "name", {
36+
afterSet: () => {
37+
onChangeObservable.notifyObservers();
38+
},
39+
});
40+
41+
return {
42+
get name() {
43+
return texture.name;
44+
},
45+
onChange: onChangeObservable,
46+
dispose: () => {
47+
nameHookToken.dispose();
48+
onChangeObservable.clear();
49+
},
50+
};
51+
},
52+
entityIcon: () => <AppGenericRegular />,
53+
getEntityAddedObservables: () => [scene.onNewTextureAddedObservable],
54+
getEntityRemovedObservables: () => [scene.onTextureRemovedObservable],
55+
});
56+
57+
return {
58+
dispose: () => {
59+
sectionRegistration.dispose();
60+
},
61+
};
62+
},
63+
};

packages/dev/inspector-v2/src/services/panes/scene/texturesExplorerService.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import type { ServiceDefinition } from "../../../modularity/serviceDefinition";
22
import type { ISceneContext } from "../../sceneContext";
33
import type { ISceneExplorerService } from "./sceneExplorerService";
44

5-
import { ImageRegular } from "@fluentui/react-icons";
5+
import { ImageEditRegular, ImageRegular } from "@fluentui/react-icons";
66

7-
import { Texture } from "core/Materials/Textures/texture";
7+
import { BaseTexture } from "core/Materials/Textures/baseTexture";
8+
import { DynamicTexture } from "core/Materials/Textures/dynamicTexture";
89
import { Observable } from "core/Misc";
910
import { InterceptProperty } from "../../../instrumentation/propertyInstrumentation";
1011
import { SceneContextIdentity } from "../../sceneContext";
@@ -22,8 +23,8 @@ export const TextureHierarchyServiceDefinition: ServiceDefinition<[], [ISceneExp
2223
const sectionRegistration = sceneExplorerService.addSection({
2324
displayName: "Textures",
2425
order: 400,
25-
predicate: (entity) => entity instanceof Texture,
26-
getRootEntities: () => scene.textures,
26+
predicate: (entity): entity is BaseTexture => entity instanceof BaseTexture && entity.getClassName() !== "AdvancedDynamicTexture",
27+
getRootEntities: () => scene.textures.filter((texture) => texture.getClassName() !== "AdvancedDynamicTexture"),
2728
getEntityDisplayInfo: (texture) => {
2829
const onChangeObservable = new Observable<void>();
2930

@@ -44,7 +45,7 @@ export const TextureHierarchyServiceDefinition: ServiceDefinition<[], [ISceneExp
4445
},
4546
};
4647
},
47-
entityIcon: () => <ImageRegular />,
48+
entityIcon: ({ entity: texture }) => (texture instanceof DynamicTexture ? <ImageEditRegular /> : <ImageRegular />),
4849
getEntityAddedObservables: () => [scene.onNewTextureAddedObservable],
4950
getEntityRemovedObservables: () => [scene.onTextureRemovedObservable],
5051
});

packages/dev/inspector-v2/webpack.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ module.exports = (env) => {
2323
resolve: {
2424
extensions: [".ts", ".tsx", ".js", ".jsx"],
2525
alias: {
26+
addons: path.resolve("../../dev/addons/dist"),
2627
core: path.resolve("../../dev/core/dist"),
28+
gui: path.resolve("../../dev/gui/dist"),
2729
loaders: path.resolve("../../dev/loaders/dist"),
28-
addons: path.resolve("../../dev/addons/dist"),
2930
materials: path.resolve("../../dev/materials/dist"),
3031
"shared-ui-components": path.resolve("../../dev/sharedUiComponents/src"),
3132
},

packages/tools/playground/webpack.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ module.exports = (env) => {
2525
materials: path.resolve("../../dev/materials/dist"),
2626
core: path.resolve("../../dev/core/dist"),
2727
loaders: path.resolve("../../dev/loaders/dist"),
28+
gui: path.resolve("../../dev/gui/dist"),
2829
},
2930
},
3031
externals: [
@@ -42,6 +43,8 @@ module.exports = (env) => {
4243
return callback(null, "ADDONS");
4344
} else if (/^materials\//.test(request)) {
4445
return callback(null, "BABYLON");
46+
} else if (/^gui\//.test(request)) {
47+
return callback(null, "BABYLON.GUI");
4548
}
4649
}
4750

0 commit comments

Comments
 (0)