|
@@ -1,20 +1,61 @@
|
|
|
module BABYLON {
|
|
|
- // Standard optimizations
|
|
|
+ /**
|
|
|
+ * Defines the root class used to create scene optimization to use with SceneOptimizer
|
|
|
+ * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
|
|
|
+ */
|
|
|
export class SceneOptimization {
|
|
|
- public apply = (scene: Scene): boolean => {
|
|
|
- return true; // Return true if everything that can be done was applied
|
|
|
+ /**
|
|
|
+ * Gets a string describing the action executed by the current optimization
|
|
|
+ */
|
|
|
+ public getDescription(): string {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
|
|
|
+ * @param scene defines the current scene where to apply this optimization
|
|
|
+ * @returnstrue if everything that can be done was applied
|
|
|
+ */
|
|
|
+ public apply(scene: Scene): boolean {
|
|
|
+ return true;
|
|
|
};
|
|
|
|
|
|
+ /**
|
|
|
+ * Creates the SceneOptimization object
|
|
|
+ * @param priority defines the priority of this optimization (0 by default which means first in the list)
|
|
|
+ * @param desc defines the description associated with the optimization
|
|
|
+ */
|
|
|
constructor(public priority: number = 0) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Defines an optimization used to reduce the size of render target textures
|
|
|
+ * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
|
|
|
+ */
|
|
|
export class TextureOptimization extends SceneOptimization {
|
|
|
- constructor(public priority: number = 0, public maximumSize: number = 1024) {
|
|
|
+ /**
|
|
|
+ * Gets a string describing the action executed by the current optimization
|
|
|
+ */
|
|
|
+ public getDescription(): string {
|
|
|
+ return "Reducing render target texture size to " + this.maximumSize;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Creates the TextureOptimization object
|
|
|
+ * @param priority defines the priority of this optimization (0 by default which means first in the list)
|
|
|
+ * @param maximumSize defines the maximum sized allowed for textures (1024 is the default value). If a texture is bigger, it will be scaled down using a factor defined by the step parameter
|
|
|
+ * @param step defines the factor (0.5 by default) used to scale down textures bigger than maximum sized allowed.
|
|
|
+ */
|
|
|
+ constructor(public priority: number = 0, public maximumSize: number = 1024, public step = 0.5) {
|
|
|
super(priority);
|
|
|
}
|
|
|
|
|
|
- public apply = (scene: Scene): boolean => {
|
|
|
+ /**
|
|
|
+ * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
|
|
|
+ * @param scene defines the current scene where to apply this optimization
|
|
|
+ */
|
|
|
+ public apply(scene: Scene): boolean {
|
|
|
|
|
|
var allDone = true;
|
|
|
for (var index = 0; index < scene.textures.length; index++) {
|
|
@@ -28,7 +69,7 @@
|
|
|
var maxDimension = Math.max(currentSize.width, currentSize.height);
|
|
|
|
|
|
if (maxDimension > this.maximumSize) {
|
|
|
- texture.scale(0.5);
|
|
|
+ texture.scale(this.step);
|
|
|
allDone = false;
|
|
|
}
|
|
|
}
|
|
@@ -37,68 +78,230 @@
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Defines an optimization used to increase or decrease the rendering resolution
|
|
|
+ * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
|
|
|
+ */
|
|
|
export class HardwareScalingOptimization extends SceneOptimization {
|
|
|
- private _currentScale = 1;
|
|
|
+ private _currentScale = -1;
|
|
|
+ private _directionOffset = 1;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Gets a string describing the action executed by the current optimization
|
|
|
+ */
|
|
|
+ public getDescription(): string {
|
|
|
+ return "Setting hardware scaling level to " + this._currentScale;
|
|
|
+ }
|
|
|
|
|
|
- constructor(public priority: number = 0, public maximumScale: number = 2) {
|
|
|
+ /**
|
|
|
+ * Creates the HardwareScalingOptimization object
|
|
|
+ * @param priority priority defines the priority of this optimization (0 by default which means first in the list)
|
|
|
+ * @param maximumScale
|
|
|
+ * @param step
|
|
|
+ */
|
|
|
+ constructor(public priority: number = 0, public maximumScale: number = 2, public step: number = 0.25) {
|
|
|
super(priority);
|
|
|
}
|
|
|
|
|
|
- public apply = (scene: Scene): boolean => {
|
|
|
- this._currentScale++;
|
|
|
+ /**
|
|
|
+ * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
|
|
|
+ * @param scene defines the current scene where to apply this optimization
|
|
|
+ */
|
|
|
+ public apply(scene: Scene): boolean {
|
|
|
+ if (this._currentScale === -1) {
|
|
|
+ this._currentScale = scene.getEngine().getHardwareScalingLevel();
|
|
|
+ if (this._currentScale > this.maximumScale) {
|
|
|
+ this._directionOffset = -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this._currentScale += this._directionOffset * this.step;
|
|
|
|
|
|
scene.getEngine().setHardwareScalingLevel(this._currentScale);
|
|
|
|
|
|
- return this._currentScale >= this.maximumScale;
|
|
|
+ return this._directionOffset === 1 ? this._currentScale >= this.maximumScale : this._currentScale <= this.maximumScale;
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Defines an optimization used to remove shadows
|
|
|
+ * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
|
|
|
+ */
|
|
|
export class ShadowsOptimization extends SceneOptimization {
|
|
|
- public apply = (scene: Scene): boolean => {
|
|
|
+ /**
|
|
|
+ * Gets a string describing the action executed by the current optimization
|
|
|
+ */
|
|
|
+ public getDescription(): string {
|
|
|
+ return "Turning shadows off";
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
|
|
|
+ * @param scene defines the current scene where to apply this optimization
|
|
|
+ */
|
|
|
+ public apply(scene: Scene): boolean {
|
|
|
scene.shadowsEnabled = false;
|
|
|
return true;
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Defines an optimization used to turn post-processes off
|
|
|
+ * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
|
|
|
+ */
|
|
|
export class PostProcessesOptimization extends SceneOptimization {
|
|
|
- public apply = (scene: Scene): boolean => {
|
|
|
+ /**
|
|
|
+ * Gets a string describing the action executed by the current optimization
|
|
|
+ */
|
|
|
+ public getDescription(): string {
|
|
|
+ return "Turning post-processes off";
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
|
|
|
+ * @param scene defines the current scene where to apply this optimization
|
|
|
+ */
|
|
|
+ public apply(scene: Scene): boolean {
|
|
|
scene.postProcessesEnabled = false;
|
|
|
return true;
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Defines an optimization used to turn lens flares off
|
|
|
+ * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
|
|
|
+ */
|
|
|
export class LensFlaresOptimization extends SceneOptimization {
|
|
|
- public apply = (scene: Scene): boolean => {
|
|
|
+ /**
|
|
|
+ * Gets a string describing the action executed by the current optimization
|
|
|
+ */
|
|
|
+ public getDescription(): string {
|
|
|
+ return "Turning lens flares off";
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
|
|
|
+ * @param scene defines the current scene where to apply this optimization
|
|
|
+ */
|
|
|
+ public apply(scene: Scene): boolean {
|
|
|
scene.lensFlaresEnabled = false;
|
|
|
return true;
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Defines an optimization based on user defined callback.
|
|
|
+ * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
|
|
|
+ */
|
|
|
+ export class CustomOptimization extends SceneOptimization {
|
|
|
+ /**
|
|
|
+ * Callback called to apply the custom optimization.
|
|
|
+ * @param scene defines the scene to apply the optimization to
|
|
|
+ * @returns a boolean defining if all the optimization was applied or if more options are available (for the next turn)
|
|
|
+ */
|
|
|
+ public onApply: (scene: Scene) => boolean;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Callback called to get custom description
|
|
|
+ */
|
|
|
+ public onGetDescription: () => string;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Gets a string describing the action executed by the current optimization
|
|
|
+ */
|
|
|
+ public getDescription(): string {
|
|
|
+ if (this.onGetDescription) {
|
|
|
+ return this.onGetDescription();
|
|
|
+ }
|
|
|
+
|
|
|
+ return "Running user defined callback";
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
|
|
|
+ * @param scene defines the current scene where to apply this optimization
|
|
|
+ */
|
|
|
+ public apply(scene: Scene): boolean {
|
|
|
+ if (this.onApply) {
|
|
|
+ return this.onApply(scene);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Defines an optimization used to turn particles off
|
|
|
+ * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
|
|
|
+ */
|
|
|
export class ParticlesOptimization extends SceneOptimization {
|
|
|
- public apply = (scene: Scene): boolean => {
|
|
|
+ /**
|
|
|
+ * Gets a string describing the action executed by the current optimization
|
|
|
+ */
|
|
|
+ public getDescription(): string {
|
|
|
+ return "Turning particles off";
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
|
|
|
+ * @param scene defines the current scene where to apply this optimization
|
|
|
+ */
|
|
|
+ public apply(scene: Scene): boolean {
|
|
|
scene.particlesEnabled = false;
|
|
|
return true;
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Defines an optimization used to turn render targets off
|
|
|
+ * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
|
|
|
+ */
|
|
|
export class RenderTargetsOptimization extends SceneOptimization {
|
|
|
- public apply = (scene: Scene): boolean => {
|
|
|
+ /**
|
|
|
+ * Gets a string describing the action executed by the current optimization
|
|
|
+ */
|
|
|
+ public getDescription(): string {
|
|
|
+ return "Turning render targets off";
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
|
|
|
+ * @param scene defines the current scene where to apply this optimization
|
|
|
+ */
|
|
|
+ public apply(scene: Scene): boolean {
|
|
|
scene.renderTargetsEnabled = false;
|
|
|
return true;
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Defines an optimization used to merge meshes with compatible materials
|
|
|
+ * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
|
|
|
+ */
|
|
|
export class MergeMeshesOptimization extends SceneOptimization {
|
|
|
static _UpdateSelectionTree = false;
|
|
|
|
|
|
+ /**
|
|
|
+ * Gets or sets a boolean which defines if optimization octree has to be updated
|
|
|
+ */
|
|
|
public static get UpdateSelectionTree(): boolean {
|
|
|
return MergeMeshesOptimization._UpdateSelectionTree;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Gets or sets a boolean which defines if optimization octree has to be updated
|
|
|
+ */
|
|
|
public static set UpdateSelectionTree(value: boolean) {
|
|
|
MergeMeshesOptimization._UpdateSelectionTree = value;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Gets a string describing the action executed by the current optimization
|
|
|
+ */
|
|
|
+ public getDescription(): string {
|
|
|
+ return "Merging similar meshes together";
|
|
|
+ }
|
|
|
+
|
|
|
private _canBeMerged = (abstractMesh: AbstractMesh): boolean => {
|
|
|
if (!(abstractMesh instanceof Mesh)) {
|
|
|
return false;
|
|
@@ -125,7 +328,11 @@
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- public apply = (scene: Scene, updateSelectionTree?: boolean): boolean => {
|
|
|
+ /**
|
|
|
+ * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
|
|
|
+ * @param scene defines the current scene where to apply this optimization
|
|
|
+ */
|
|
|
+ public apply(scene: Scene, updateSelectionTree?: boolean): boolean {
|
|
|
|
|
|
var globalPool = scene.meshes.slice(0);
|
|
|
var globalLength = globalPool.length;
|
|
@@ -186,101 +393,285 @@
|
|
|
};
|
|
|
}
|
|
|
|
|
|
- // Options
|
|
|
+ /**
|
|
|
+ * Defines a list of options used by SceneOptimizer
|
|
|
+ * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
|
|
|
+ */
|
|
|
export class SceneOptimizerOptions {
|
|
|
+ /**
|
|
|
+ * Gets the list of optimizations to apply
|
|
|
+ */
|
|
|
public optimizations = new Array<SceneOptimization>();
|
|
|
|
|
|
+ /**
|
|
|
+ * Creates a new list of options used by SceneOptimizer
|
|
|
+ * @param targetFrameRate defines the target frame rate to reach (60 by default)
|
|
|
+ * @param trackerDuration defines the interval between two checkes (2000ms by default)
|
|
|
+ */
|
|
|
constructor(public targetFrameRate: number = 60, public trackerDuration: number = 2000) {
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Add a new optimization
|
|
|
+ * @param optimization defines the SceneOptimization to add to the list of active optimizations
|
|
|
+ */
|
|
|
+ public addOptimization(optimization: SceneOptimization): SceneOptimizerOptions {
|
|
|
+ this.optimizations.push(optimization);
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Add a new custom optimization
|
|
|
+ * @param onApply defines the callback called to apply the custom optimization.
|
|
|
+ * @param onGetDescription defines the callback called to get the description attached with the optimization.
|
|
|
+ * @param priority defines the priority of this optimization (0 by default which means first in the list)
|
|
|
+ */
|
|
|
+ public addCustomOptimization(onApply: (scene: Scene) => boolean, onGetDescription: () => string, priority: number = 0): SceneOptimizerOptions {
|
|
|
+ let optimization = new CustomOptimization(priority);
|
|
|
+ optimization.onApply = onApply;
|
|
|
+ optimization.onGetDescription = onGetDescription;
|
|
|
+
|
|
|
+ this.optimizations.push(optimization);
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Creates a list of pre-defined optimizations aimed to reduce the visual impact on the scene
|
|
|
+ * @param targetFrameRate defines the target frame rate (60 by default)
|
|
|
+ * @returns a SceneOptimizerOptions object
|
|
|
+ */
|
|
|
public static LowDegradationAllowed(targetFrameRate?: number): SceneOptimizerOptions {
|
|
|
var result = new SceneOptimizerOptions(targetFrameRate);
|
|
|
|
|
|
var priority = 0;
|
|
|
- result.optimizations.push(new MergeMeshesOptimization(priority));
|
|
|
- result.optimizations.push(new ShadowsOptimization(priority));
|
|
|
- result.optimizations.push(new LensFlaresOptimization(priority));
|
|
|
+ result.addOptimization(new MergeMeshesOptimization(priority));
|
|
|
+ result.addOptimization(new ShadowsOptimization(priority));
|
|
|
+ result.addOptimization(new LensFlaresOptimization(priority));
|
|
|
|
|
|
// Next priority
|
|
|
priority++;
|
|
|
- result.optimizations.push(new PostProcessesOptimization(priority));
|
|
|
- result.optimizations.push(new ParticlesOptimization(priority));
|
|
|
+ result.addOptimization(new PostProcessesOptimization(priority));
|
|
|
+ result.addOptimization(new ParticlesOptimization(priority));
|
|
|
|
|
|
// Next priority
|
|
|
priority++;
|
|
|
- result.optimizations.push(new TextureOptimization(priority, 1024));
|
|
|
+ result.addOptimization(new TextureOptimization(priority, 1024));
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Creates a list of pre-defined optimizations aimed to have a moderate impact on the scene visual
|
|
|
+ * @param targetFrameRate defines the target frame rate (60 by default)
|
|
|
+ * @returns a SceneOptimizerOptions object
|
|
|
+ */
|
|
|
public static ModerateDegradationAllowed(targetFrameRate?: number): SceneOptimizerOptions {
|
|
|
var result = new SceneOptimizerOptions(targetFrameRate);
|
|
|
|
|
|
var priority = 0;
|
|
|
- result.optimizations.push(new MergeMeshesOptimization(priority));
|
|
|
- result.optimizations.push(new ShadowsOptimization(priority));
|
|
|
- result.optimizations.push(new LensFlaresOptimization(priority));
|
|
|
+ result.addOptimization(new MergeMeshesOptimization(priority));
|
|
|
+ result.addOptimization(new ShadowsOptimization(priority));
|
|
|
+ result.addOptimization(new LensFlaresOptimization(priority));
|
|
|
|
|
|
// Next priority
|
|
|
priority++;
|
|
|
- result.optimizations.push(new PostProcessesOptimization(priority));
|
|
|
- result.optimizations.push(new ParticlesOptimization(priority));
|
|
|
+ result.addOptimization(new PostProcessesOptimization(priority));
|
|
|
+ result.addOptimization(new ParticlesOptimization(priority));
|
|
|
|
|
|
// Next priority
|
|
|
priority++;
|
|
|
- result.optimizations.push(new TextureOptimization(priority, 512));
|
|
|
+ result.addOptimization(new TextureOptimization(priority, 512));
|
|
|
|
|
|
// Next priority
|
|
|
priority++;
|
|
|
- result.optimizations.push(new RenderTargetsOptimization(priority));
|
|
|
+ result.addOptimization(new RenderTargetsOptimization(priority));
|
|
|
|
|
|
// Next priority
|
|
|
priority++;
|
|
|
- result.optimizations.push(new HardwareScalingOptimization(priority, 2));
|
|
|
+ result.addOptimization(new HardwareScalingOptimization(priority, 2));
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Creates a list of pre-defined optimizations aimed to have a big impact on the scene visual
|
|
|
+ * @param targetFrameRate defines the target frame rate (60 by default)
|
|
|
+ * @returns a SceneOptimizerOptions object
|
|
|
+ */
|
|
|
public static HighDegradationAllowed(targetFrameRate?: number): SceneOptimizerOptions {
|
|
|
var result = new SceneOptimizerOptions(targetFrameRate);
|
|
|
|
|
|
var priority = 0;
|
|
|
- result.optimizations.push(new MergeMeshesOptimization(priority));
|
|
|
- result.optimizations.push(new ShadowsOptimization(priority));
|
|
|
- result.optimizations.push(new LensFlaresOptimization(priority));
|
|
|
+ result.addOptimization(new MergeMeshesOptimization(priority));
|
|
|
+ result.addOptimization(new ShadowsOptimization(priority));
|
|
|
+ result.addOptimization(new LensFlaresOptimization(priority));
|
|
|
|
|
|
// Next priority
|
|
|
priority++;
|
|
|
- result.optimizations.push(new PostProcessesOptimization(priority));
|
|
|
- result.optimizations.push(new ParticlesOptimization(priority));
|
|
|
+ result.addOptimization(new PostProcessesOptimization(priority));
|
|
|
+ result.addOptimization(new ParticlesOptimization(priority));
|
|
|
|
|
|
// Next priority
|
|
|
priority++;
|
|
|
- result.optimizations.push(new TextureOptimization(priority, 256));
|
|
|
+ result.addOptimization(new TextureOptimization(priority, 256));
|
|
|
|
|
|
// Next priority
|
|
|
priority++;
|
|
|
- result.optimizations.push(new RenderTargetsOptimization(priority));
|
|
|
+ result.addOptimization(new RenderTargetsOptimization(priority));
|
|
|
|
|
|
// Next priority
|
|
|
priority++;
|
|
|
- result.optimizations.push(new HardwareScalingOptimization(priority, 4));
|
|
|
+ result.addOptimization(new HardwareScalingOptimization(priority, 4));
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Class used to run optimizations in order to reach a target frame rate
|
|
|
+ * @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
|
|
|
+ */
|
|
|
+ export class SceneOptimizer implements IDisposable {
|
|
|
+ private _isRunning = false;
|
|
|
+ private _options: SceneOptimizerOptions;
|
|
|
+ private _scene: Scene;
|
|
|
+ private _currentPriorityLevel = 0;
|
|
|
+ private _targetFrameRate = 60;
|
|
|
+ private _trackerDuration = 2000;
|
|
|
+ private _currentFrameRate = 0;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Defines an observable called when the optimizer reaches the target frame rate
|
|
|
+ */
|
|
|
+ public onSuccessObservable = new Observable<SceneOptimizer>();
|
|
|
+ /**
|
|
|
+ * Defines an observable called when the optimizer enables an optimization
|
|
|
+ */
|
|
|
+ public onNewOptimizationAppliedObservable = new Observable<SceneOptimization>();
|
|
|
+ /**
|
|
|
+ * Defines an observable called when the optimizer is not able to reach the target frame rate
|
|
|
+ */
|
|
|
+ public onFailureObservable = new Observable<SceneOptimizer>();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Gets the current priority level (0 at start)
|
|
|
+ */
|
|
|
+ public get currentPriorityLevel(): number {
|
|
|
+ return this._currentPriorityLevel;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Gets the current frame rate checked by the SceneOptimizer
|
|
|
+ */
|
|
|
+ public get currentFrameRate(): number {
|
|
|
+ return this._currentFrameRate;
|
|
|
+ }
|
|
|
|
|
|
- // Scene optimizer tool
|
|
|
- export class SceneOptimizer {
|
|
|
+ /**
|
|
|
+ * Gets or sets the current target frame rate (60 by default)
|
|
|
+ */
|
|
|
+ public get targetFrameRate(): number {
|
|
|
+ return this._targetFrameRate;
|
|
|
+ }
|
|
|
|
|
|
- static _CheckCurrentState(scene: Scene, options: SceneOptimizerOptions, currentPriorityLevel: number, onSuccess?: () => void, onFailure?: () => void) {
|
|
|
- // TODO: add an epsilon
|
|
|
- if (scene.getEngine().getFps() >= options.targetFrameRate) {
|
|
|
- if (onSuccess) {
|
|
|
- onSuccess();
|
|
|
+ /**
|
|
|
+ * Gets or sets the current target frame rate (60 by default)
|
|
|
+ */
|
|
|
+ public set targetFrameRate(value: number) {
|
|
|
+ this._targetFrameRate = value;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Gets or sets the current interval between two checks (every 2000ms by default)
|
|
|
+ */
|
|
|
+ public get trackerDuration(): number {
|
|
|
+ return this._trackerDuration;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Gets or sets the current interval between two checks (every 2000ms by default)
|
|
|
+ */
|
|
|
+ public set trackerDuration(value: number) {
|
|
|
+ this._trackerDuration = value;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Gets the list of active optimizations
|
|
|
+ */
|
|
|
+ public get optimizations(): SceneOptimization[] {
|
|
|
+ return this._options.optimizations;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Creates a new SceneOptimizer
|
|
|
+ * @param scene defines the scene to work on
|
|
|
+ * @param options defines the options to use with the SceneOptimizer
|
|
|
+ * @param autoGeneratePriorities defines if priorities must be generated and not read from SceneOptimization property (true by default)
|
|
|
+ */
|
|
|
+ public constructor(scene: Scene, options?: SceneOptimizerOptions, autoGeneratePriorities = true) {
|
|
|
+ if (!options) {
|
|
|
+ this._options = new SceneOptimizerOptions();
|
|
|
+ } else {
|
|
|
+ this._options = options;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this._options.targetFrameRate) {
|
|
|
+ this._targetFrameRate = this._options.targetFrameRate;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this._options.trackerDuration) {
|
|
|
+ this._trackerDuration = this._options.trackerDuration;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (autoGeneratePriorities) {
|
|
|
+ let priority = 0;
|
|
|
+ for (var optim of this._options.optimizations) {
|
|
|
+ optim.priority = priority++;
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ this._scene = scene || Engine.LastCreatedScene;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Stops the current optimizer
|
|
|
+ */
|
|
|
+ public stop() {
|
|
|
+ this._isRunning = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ public reset() {
|
|
|
+ this._currentPriorityLevel = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ public start() {
|
|
|
+ if (this._isRunning) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this._isRunning = true;
|
|
|
+
|
|
|
+ // Let's wait for the scene to be ready before running our check
|
|
|
+ this._scene.executeWhenReady(() => {
|
|
|
+ setTimeout(() => {
|
|
|
+ this._checkCurrentState();
|
|
|
+ }, this._trackerDuration);
|
|
|
+ });
|
|
|
+ }
|
|
|
|
|
|
+ private _checkCurrentState() {
|
|
|
+ if (!this._isRunning) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ let scene = this._scene;
|
|
|
+ let options = this._options;
|
|
|
+
|
|
|
+ this._currentFrameRate = Math.round(scene.getEngine().getFps());
|
|
|
+
|
|
|
+ if (this._currentFrameRate >= this._targetFrameRate) {
|
|
|
+ this._isRunning = false;
|
|
|
+ this.onSuccessObservable.notifyObservers(this);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -290,45 +681,68 @@
|
|
|
for (var index = 0; index < options.optimizations.length; index++) {
|
|
|
var optimization = options.optimizations[index];
|
|
|
|
|
|
- if (optimization.priority === currentPriorityLevel) {
|
|
|
+ if (optimization.priority === this._currentPriorityLevel) {
|
|
|
noOptimizationApplied = false;
|
|
|
allDone = allDone && optimization.apply(scene);
|
|
|
+ this.onNewOptimizationAppliedObservable.notifyObservers(optimization);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// If no optimization was applied, this is a failure :(
|
|
|
if (noOptimizationApplied) {
|
|
|
- if (onFailure) {
|
|
|
- onFailure();
|
|
|
- }
|
|
|
+ this._isRunning = false;
|
|
|
+ this.onFailureObservable.notifyObservers(this);
|
|
|
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// If all optimizations were done, move to next level
|
|
|
if (allDone) {
|
|
|
- currentPriorityLevel++;
|
|
|
+ this._currentPriorityLevel++;
|
|
|
}
|
|
|
|
|
|
// Let's the system running for a specific amount of time before checking FPS
|
|
|
scene.executeWhenReady(() => {
|
|
|
setTimeout(() => {
|
|
|
- SceneOptimizer._CheckCurrentState(scene, options, currentPriorityLevel, onSuccess, onFailure);
|
|
|
- }, options.trackerDuration);
|
|
|
+ this._checkCurrentState();
|
|
|
+ }, this._trackerDuration);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- public static OptimizeAsync(scene: Scene, options?: SceneOptimizerOptions, onSuccess?: () => void, onFailure?: () => void): void {
|
|
|
- if (!options) {
|
|
|
- options = SceneOptimizerOptions.ModerateDegradationAllowed();
|
|
|
+ /**
|
|
|
+ * Release all resources
|
|
|
+ */
|
|
|
+ public dispose(): void {
|
|
|
+ this.onSuccessObservable.clear();
|
|
|
+ this.onFailureObservable.clear();
|
|
|
+ this.onNewOptimizationAppliedObservable.clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Helper function to create a SceneOptimizer with one single line of code
|
|
|
+ * @param scene defines the scene to work on
|
|
|
+ * @param options defines the options to use with the SceneOptimizer
|
|
|
+ * @param onSuccess defines a callback to call on success
|
|
|
+ * @param onFailure defines a callback to call on failure
|
|
|
+ */
|
|
|
+ public static OptimizeAsync(scene: Scene, options?: SceneOptimizerOptions, onSuccess?: () => void, onFailure?: () => void): SceneOptimizer {
|
|
|
+ let optimizer = new SceneOptimizer(scene, options || SceneOptimizerOptions.ModerateDegradationAllowed(), false);
|
|
|
+
|
|
|
+ if (onSuccess) {
|
|
|
+ optimizer.onSuccessObservable.add(() => {
|
|
|
+ onSuccess();
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
- // Let's the system running for a specific amount of time before checking FPS
|
|
|
- scene.executeWhenReady(() => {
|
|
|
- setTimeout(() => {
|
|
|
- SceneOptimizer._CheckCurrentState(scene, <SceneOptimizerOptions>options, 0, onSuccess, onFailure);
|
|
|
- }, (<SceneOptimizerOptions>options).trackerDuration);
|
|
|
- });
|
|
|
+ if (onFailure) {
|
|
|
+ optimizer.onFailureObservable.add(() => {
|
|
|
+ onFailure();
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ optimizer.start();
|
|
|
+
|
|
|
+ return optimizer;
|
|
|
}
|
|
|
}
|
|
|
}
|