|
@@ -18,11 +18,15 @@ import { DirectionalLight } from 'babylonjs/Lights/directionalLight';
|
|
|
import { LogEntry } from '../log/logComponent';
|
|
|
import { PointerEventTypes } from 'babylonjs/Events/pointerEvents';
|
|
|
import { Color3 } from 'babylonjs/Maths/math.color';
|
|
|
+import { PostProcess } from 'babylonjs/PostProcesses/postProcess';
|
|
|
+import { Constants } from 'babylonjs/Engines/constants';
|
|
|
+import { CurrentScreenBlock } from 'babylonjs/Materials/Node/Blocks/Dual/currentScreenBlock';
|
|
|
+import { NodeMaterialModes } from 'babylonjs/Materials/Node/Enums/nodeMaterialModes';
|
|
|
|
|
|
export class PreviewManager {
|
|
|
private _nodeMaterial: NodeMaterial;
|
|
|
- private _onBuildObserver: Nullable<Observer<NodeMaterial>>;
|
|
|
- private _onPreviewCommandActivatedObserver: Nullable<Observer<void>>;
|
|
|
+ private _onBuildObserver: Nullable<Observer<NodeMaterial>>;
|
|
|
+ private _onPreviewCommandActivatedObserver: Nullable<Observer<boolean>>;
|
|
|
private _onAnimationCommandActivatedObserver: Nullable<Observer<void>>;
|
|
|
private _onUpdateRequiredObserver: Nullable<Observer<void>>;
|
|
|
private _onPreviewBackgroundChangedObserver: Nullable<Observer<void>>;
|
|
@@ -34,9 +38,10 @@ export class PreviewManager {
|
|
|
private _meshes: AbstractMesh[];
|
|
|
private _camera: ArcRotateCamera;
|
|
|
private _material: NodeMaterial;
|
|
|
- private _globalState: GlobalState;
|
|
|
- private _currentType: number;
|
|
|
+ private _globalState: GlobalState;
|
|
|
+ private _currentType: number;
|
|
|
private _lightParent: TransformNode;
|
|
|
+ private _postprocess: Nullable<PostProcess>;
|
|
|
|
|
|
public constructor(targetCanvas: HTMLCanvasElement, globalState: GlobalState) {
|
|
|
this._nodeMaterial = globalState.nodeMaterial;
|
|
@@ -47,13 +52,16 @@ export class PreviewManager {
|
|
|
this._updatePreview(serializationObject);
|
|
|
});
|
|
|
|
|
|
- this._onPreviewCommandActivatedObserver = globalState.onPreviewCommandActivated.add(() => {
|
|
|
+ this._onPreviewCommandActivatedObserver = globalState.onPreviewCommandActivated.add((forceRefresh: boolean) => {
|
|
|
+ if (forceRefresh) {
|
|
|
+ this._currentType = -1;
|
|
|
+ }
|
|
|
this._refreshPreviewMesh();
|
|
|
});
|
|
|
|
|
|
this._onLightUpdatedObserver = globalState.onLightUpdated.add(() => {
|
|
|
this._prepareLights();
|
|
|
- });
|
|
|
+ });
|
|
|
|
|
|
this._onUpdateRequiredObserver = globalState.onUpdateRequiredObservable.add(() => {
|
|
|
let serializationObject = this._nodeMaterial.serialize();
|
|
@@ -61,7 +69,7 @@ export class PreviewManager {
|
|
|
});
|
|
|
|
|
|
this._onPreviewBackgroundChangedObserver = globalState.onPreviewBackgroundChanged.add(() => {
|
|
|
- this._scene.clearColor = this._globalState.backgroundColor;
|
|
|
+ this._scene.clearColor = this._globalState.backgroundColor;
|
|
|
});
|
|
|
|
|
|
this._onAnimationCommandActivatedObserver = globalState.onAnimationCommandActivated.add(() => {
|
|
@@ -74,7 +82,7 @@ export class PreviewManager {
|
|
|
|
|
|
this._onDepthPrePassChangedObserver = globalState.onDepthPrePassChanged.add(() => {
|
|
|
this._material.needDepthPrePass = this._globalState.depthPrePass;
|
|
|
- });
|
|
|
+ });
|
|
|
|
|
|
this._engine = new Engine(targetCanvas, true);
|
|
|
this._scene = new Scene(this._engine);
|
|
@@ -97,11 +105,11 @@ export class PreviewManager {
|
|
|
});
|
|
|
|
|
|
// let cameraLastRotation = 0;
|
|
|
- let lastOffsetX:number | undefined = undefined;
|
|
|
- // const lightRotationParallaxSpeed = 0.5;
|
|
|
- const lightRotationSpeed = 0.01;
|
|
|
+ let lastOffsetX: number | undefined = undefined;
|
|
|
+ // const lightRotationParallaxSpeed = 0.5;
|
|
|
+ const lightRotationSpeed = 0.01;
|
|
|
|
|
|
- this._scene.onPointerObservable.add(evt => {
|
|
|
+ this._scene.onPointerObservable.add((evt) => {
|
|
|
if (this._globalState.controlCamera) {
|
|
|
return;
|
|
|
}
|
|
@@ -119,7 +127,7 @@ export class PreviewManager {
|
|
|
lastOffsetX = evt.event.offsetX;
|
|
|
}
|
|
|
|
|
|
- var rotateLighting = (lastOffsetX - evt.event.offsetX) * lightRotationSpeed;
|
|
|
+ var rotateLighting = (lastOffsetX - evt.event.offsetX) * lightRotationSpeed;
|
|
|
this._lightParent.rotation.y += rotateLighting;
|
|
|
lastOffsetX = evt.event.offsetX;
|
|
|
});
|
|
@@ -131,7 +139,7 @@ export class PreviewManager {
|
|
|
// if (!this._globalState.controlCamera) {
|
|
|
// return;
|
|
|
// }
|
|
|
- // var rotateLighting = (this._camera.alpha - cameraLastRotation) * lightRotationParallaxSpeed;
|
|
|
+ // var rotateLighting = (this._camera.alpha - cameraLastRotation) * lightRotationParallaxSpeed;
|
|
|
// this._lightParent.rotate(Vector3.Up(), rotateLighting);
|
|
|
// cameraLastRotation = this._camera.alpha;
|
|
|
// });
|
|
@@ -139,7 +147,7 @@ export class PreviewManager {
|
|
|
|
|
|
private _handleAnimations() {
|
|
|
this._scene.stopAllAnimations();
|
|
|
-
|
|
|
+
|
|
|
if (this._globalState.rotatePreview) {
|
|
|
for (var root of this._scene.rootNodes) {
|
|
|
let transformNode = root as TransformNode;
|
|
@@ -165,14 +173,14 @@ export class PreviewManager {
|
|
|
|
|
|
// Create new lights based on settings
|
|
|
if (this._globalState.hemisphericLight) {
|
|
|
- new HemisphericLight("Hemispheric light", new Vector3(0, 1, 0), this._scene);
|
|
|
+ new HemisphericLight("Hemispheric light", new Vector3(0, 1, 0), this._scene);
|
|
|
}
|
|
|
|
|
|
if (this._globalState.directionalLight0) {
|
|
|
let dir0 = new DirectionalLight("Directional light #0", new Vector3(0.841626576496605, -0.2193391004130599, -0.49351298337996535), this._scene);
|
|
|
dir0.intensity = 0.9;
|
|
|
dir0.diffuse = new Color3(0.9294117647058824, 0.9725490196078431, 0.996078431372549);
|
|
|
- dir0.specular = new Color3(0.9294117647058824, 0.9725490196078431, 0.996078431372549);
|
|
|
+ dir0.specular = new Color3(0.9294117647058824, 0.9725490196078431, 0.996078431372549);
|
|
|
dir0.parent = this._lightParent;
|
|
|
}
|
|
|
|
|
@@ -180,49 +188,50 @@ export class PreviewManager {
|
|
|
let dir1 = new DirectionalLight("Directional light #1", new Vector3(-0.9519937437504213, -0.24389315636999764, -0.1849974057546125), this._scene);
|
|
|
dir1.intensity = 1.2;
|
|
|
dir1.specular = new Color3(0.9803921568627451, 0.9529411764705882, 0.7725490196078432);
|
|
|
- dir1.diffuse = new Color3(0.9803921568627451, 0.9529411764705882, 0.7725490196078432);
|
|
|
- dir1.parent = this._lightParent;
|
|
|
+ dir1.diffuse = new Color3(0.9803921568627451, 0.9529411764705882, 0.7725490196078432);
|
|
|
+ dir1.parent = this._lightParent;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private _prepareMeshes() {
|
|
|
- this._prepareLights();
|
|
|
-
|
|
|
- // Framing
|
|
|
- this._camera.useFramingBehavior = true;
|
|
|
-
|
|
|
- var framingBehavior = this._camera.getBehaviorByName("Framing") as FramingBehavior;
|
|
|
-
|
|
|
- setTimeout(() => { // Let the behavior activate first
|
|
|
- framingBehavior.framingTime = 0;
|
|
|
- framingBehavior.elevationReturnTime = -1;
|
|
|
-
|
|
|
- if (this._scene.meshes.length) {
|
|
|
- var worldExtends = this._scene.getWorldExtends();
|
|
|
- this._camera.lowerRadiusLimit = null;
|
|
|
- this._camera.upperRadiusLimit = null;
|
|
|
- framingBehavior.zoomOnBoundingInfo(worldExtends.min, worldExtends.max);
|
|
|
- }
|
|
|
-
|
|
|
- this._camera.pinchPrecision = 200 / this._camera.radius;
|
|
|
- this._camera.upperRadiusLimit = 5 * this._camera.radius;
|
|
|
- });
|
|
|
+ if (this._globalState.mode !== NodeMaterialModes.PostProcess) {
|
|
|
+ this._prepareLights();
|
|
|
+
|
|
|
+ // Framing
|
|
|
+ this._camera.useFramingBehavior = true;
|
|
|
|
|
|
- this._camera.wheelDeltaPercentage = 0.01;
|
|
|
- this._camera.pinchDeltaPercentage = 0.01;
|
|
|
+ var framingBehavior = this._camera.getBehaviorByName("Framing") as FramingBehavior;
|
|
|
|
|
|
- // Animations
|
|
|
- this._handleAnimations();
|
|
|
+ setTimeout(() => { // Let the behavior activate first
|
|
|
+ framingBehavior.framingTime = 0;
|
|
|
+ framingBehavior.elevationReturnTime = -1;
|
|
|
|
|
|
- // Material
|
|
|
+ if (this._scene.meshes.length) {
|
|
|
+ var worldExtends = this._scene.getWorldExtends();
|
|
|
+ this._camera.lowerRadiusLimit = null;
|
|
|
+ this._camera.upperRadiusLimit = null;
|
|
|
+ framingBehavior.zoomOnBoundingInfo(worldExtends.min, worldExtends.max);
|
|
|
+ }
|
|
|
+
|
|
|
+ this._camera.pinchPrecision = 200 / this._camera.radius;
|
|
|
+ this._camera.upperRadiusLimit = 5 * this._camera.radius;
|
|
|
+ });
|
|
|
+
|
|
|
+ this._camera.wheelDeltaPercentage = 0.01;
|
|
|
+ this._camera.pinchDeltaPercentage = 0.01;
|
|
|
+
|
|
|
+ // Animations
|
|
|
+ this._handleAnimations();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Material
|
|
|
let serializationObject = this._nodeMaterial.serialize();
|
|
|
this._updatePreview(serializationObject);
|
|
|
}
|
|
|
|
|
|
- private _refreshPreviewMesh() {
|
|
|
+ private _refreshPreviewMesh() {
|
|
|
|
|
|
if (this._currentType !== this._globalState.previewMeshType || this._currentType === PreviewMeshType.Custom) {
|
|
|
-
|
|
|
this._currentType = this._globalState.previewMeshType;
|
|
|
if (this._meshes && this._meshes.length) {
|
|
|
for (var mesh of this._meshes) {
|
|
@@ -241,46 +250,48 @@ export class PreviewManager {
|
|
|
SceneLoader.ShowLoadingScreen = false;
|
|
|
|
|
|
this._globalState.onIsLoadingChanged.notifyObservers(true);
|
|
|
-
|
|
|
- switch (this._globalState.previewMeshType) {
|
|
|
- case PreviewMeshType.Box:
|
|
|
- SceneLoader.AppendAsync("https://models.babylonjs.com/", "roundedCube.glb", this._scene).then(() => {
|
|
|
- this._meshes.push(...this._scene.meshes);
|
|
|
- this._prepareMeshes();
|
|
|
- });
|
|
|
- break;
|
|
|
- case PreviewMeshType.Sphere:
|
|
|
- this._meshes.push(Mesh.CreateSphere("dummy-sphere", 32, 2, this._scene));
|
|
|
- break;
|
|
|
- case PreviewMeshType.Torus:
|
|
|
- this._meshes.push(Mesh.CreateTorus("dummy-torus", 2, 0.5, 32, this._scene));
|
|
|
- break;
|
|
|
- case PreviewMeshType.Cylinder:
|
|
|
- SceneLoader.AppendAsync("https://models.babylonjs.com/", "roundedCylinder.glb", this._scene).then(() => {
|
|
|
- this._meshes.push(...this._scene.meshes);
|
|
|
- this._prepareMeshes();
|
|
|
- });
|
|
|
- return;
|
|
|
- case PreviewMeshType.Plane:
|
|
|
- let plane = Mesh.CreateGround("dummy-plane", 2, 2, 128, this._scene);
|
|
|
- plane.scaling.y = -1;
|
|
|
- plane.rotation.x = Math.PI;
|
|
|
- this._meshes.push(plane);
|
|
|
- break;
|
|
|
- case PreviewMeshType.ShaderBall:
|
|
|
- SceneLoader.AppendAsync("https://models.babylonjs.com/", "shaderBall.glb", this._scene).then(() => {
|
|
|
- this._meshes.push(...this._scene.meshes);
|
|
|
- this._prepareMeshes();
|
|
|
- });
|
|
|
- return;
|
|
|
- case PreviewMeshType.Custom:
|
|
|
- SceneLoader.AppendAsync("file:", this._globalState.previewMeshFile, this._scene).then(() => {
|
|
|
- this._meshes.push(...this._scene.meshes);
|
|
|
- this._prepareMeshes();
|
|
|
- });
|
|
|
- return;
|
|
|
+
|
|
|
+ if (this._globalState.mode !== NodeMaterialModes.PostProcess) {
|
|
|
+ switch (this._globalState.previewMeshType) {
|
|
|
+ case PreviewMeshType.Box:
|
|
|
+ SceneLoader.AppendAsync("https://models.babylonjs.com/", "roundedCube.glb", this._scene).then(() => {
|
|
|
+ this._meshes.push(...this._scene.meshes);
|
|
|
+ this._prepareMeshes();
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ case PreviewMeshType.Sphere:
|
|
|
+ this._meshes.push(Mesh.CreateSphere("dummy-sphere", 32, 2, this._scene));
|
|
|
+ break;
|
|
|
+ case PreviewMeshType.Torus:
|
|
|
+ this._meshes.push(Mesh.CreateTorus("dummy-torus", 2, 0.5, 32, this._scene));
|
|
|
+ break;
|
|
|
+ case PreviewMeshType.Cylinder:
|
|
|
+ SceneLoader.AppendAsync("https://models.babylonjs.com/", "roundedCylinder.glb", this._scene).then(() => {
|
|
|
+ this._meshes.push(...this._scene.meshes);
|
|
|
+ this._prepareMeshes();
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ case PreviewMeshType.Plane:
|
|
|
+ let plane = Mesh.CreateGround("dummy-plane", 2, 2, 128, this._scene);
|
|
|
+ plane.scaling.y = -1;
|
|
|
+ plane.rotation.x = Math.PI;
|
|
|
+ this._meshes.push(plane);
|
|
|
+ break;
|
|
|
+ case PreviewMeshType.ShaderBall:
|
|
|
+ SceneLoader.AppendAsync("https://models.babylonjs.com/", "shaderBall.glb", this._scene).then(() => {
|
|
|
+ this._meshes.push(...this._scene.meshes);
|
|
|
+ this._prepareMeshes();
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ case PreviewMeshType.Custom:
|
|
|
+ SceneLoader.AppendAsync("file:", this._globalState.previewMeshFile, this._scene).then(() => {
|
|
|
+ this._meshes.push(...this._scene.meshes);
|
|
|
+ this._prepareMeshes();
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
this._prepareMeshes();
|
|
|
}
|
|
|
}
|
|
@@ -296,8 +307,29 @@ export class PreviewManager {
|
|
|
tempMaterial.backFaceCulling = this._globalState.backFaceCulling;
|
|
|
tempMaterial.needDepthPrePass = this._globalState.depthPrePass;
|
|
|
|
|
|
- if (this._meshes.length) {
|
|
|
- let tasks = this._meshes.map(m => this._forceCompilationAsync(tempMaterial, m));
|
|
|
+ if (this._postprocess) {
|
|
|
+ this._postprocess.dispose(this._camera);
|
|
|
+ this._postprocess = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this._globalState.mode === NodeMaterialModes.PostProcess) {
|
|
|
+ this._globalState.onIsLoadingChanged.notifyObservers(false);
|
|
|
+
|
|
|
+ this._postprocess = tempMaterial.createPostProcess(this._camera, 1.0, Constants.TEXTURE_NEAREST_SAMPLINGMODE, this._engine);
|
|
|
+
|
|
|
+ const currentScreen = tempMaterial.getBlockByPredicate((block) => block instanceof CurrentScreenBlock);
|
|
|
+ if (currentScreen) {
|
|
|
+ this._postprocess!.onApplyObservable.add((effect) => {
|
|
|
+ effect.setTexture("textureSampler", (currentScreen as CurrentScreenBlock).texture);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this._material) {
|
|
|
+ this._material.dispose();
|
|
|
+ }
|
|
|
+ this._material = tempMaterial;
|
|
|
+ } else if (this._meshes.length) {
|
|
|
+ let tasks = this._meshes.map((m) => this._forceCompilationAsync(tempMaterial, m));
|
|
|
|
|
|
Promise.all(tasks).then(() => {
|
|
|
for (var mesh of this._meshes) {
|
|
@@ -306,19 +338,20 @@ export class PreviewManager {
|
|
|
|
|
|
if (this._material) {
|
|
|
this._material.dispose();
|
|
|
- }
|
|
|
-
|
|
|
- this._material = tempMaterial;
|
|
|
+ }
|
|
|
+
|
|
|
+ this._material = tempMaterial;
|
|
|
this._globalState.onIsLoadingChanged.notifyObservers(false);
|
|
|
- }).catch(reason => {
|
|
|
+ }).catch((reason) => {
|
|
|
this._globalState.onLogRequiredObservable.notifyObservers(new LogEntry("Shader compilation error:\r\n" + reason, true));
|
|
|
this._globalState.onIsLoadingChanged.notifyObservers(false);
|
|
|
});
|
|
|
} else {
|
|
|
- this._material = tempMaterial;
|
|
|
+ this._material = tempMaterial;
|
|
|
}
|
|
|
- } catch(err) {
|
|
|
+ } catch (err) {
|
|
|
// Ignore the error
|
|
|
+ this._globalState.onIsLoadingChanged.notifyObservers(false);
|
|
|
}
|
|
|
}
|
|
|
|