123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- module BABYLON {
- // Standard optimizations
- export class SceneOptimization {
- public apply = (scene: Scene): boolean => {
- return true; // Return true if everything that can be done was applied
- };
- constructor(public priority: number = 0) {
- }
- }
- export class TextureOptimization extends SceneOptimization {
- constructor(public priority: number = 0, public maximumSize: number = 1024) {
- super(priority);
- }
- public apply = (scene: Scene): boolean => {
- var allDone = true;
- for (var index = 0; index < scene.textures.length; index++) {
- var texture = scene.textures[index];
- if (!texture.canRescale) {
- continue;
- }
- var currentSize = texture.getSize();
- var maxDimension = Math.max(currentSize.width, currentSize.height);
- if (maxDimension > this.maximumSize) {
- texture.scale(0.5);
- allDone = false;
- }
- }
- return allDone;
- }
- }
- export class HardwareScalingOptimization extends SceneOptimization {
- private _currentScale = 1;
- constructor(public priority: number = 0, public maximumScale: number = 2) {
- super(priority);
- }
- public apply = (scene: Scene): boolean => {
- this._currentScale++;
- scene.getEngine().setHardwareScalingLevel(this._currentScale);
- return this._currentScale >= this.maximumScale;
- };
- }
- export class ShadowsOptimization extends SceneOptimization {
- public apply = (scene: Scene): boolean => {
- scene.shadowsEnabled = false;
- return true;
- };
- }
- export class PostProcessesOptimization extends SceneOptimization {
- public apply = (scene: Scene): boolean => {
- scene.postProcessesEnabled = false;
- return true;
- };
- }
- export class LensFlaresOptimization extends SceneOptimization {
- public apply = (scene: Scene): boolean => {
- scene.lensFlaresEnabled = false;
- return true;
- };
- }
- export class ParticlesOptimization extends SceneOptimization {
- public apply = (scene: Scene): boolean => {
- scene.particlesEnabled = false;
- return true;
- };
- }
- export class RenderTargetsOptimization extends SceneOptimization {
- public apply = (scene: Scene): boolean => {
- scene.renderTargetsEnabled = false;
- return true;
- };
- }
- export class MergeMeshesOptimization extends SceneOptimization {
- private _canBeMerged = (abstractMesh: AbstractMesh): boolean => {
- if (!(abstractMesh instanceof Mesh)) {
- return false;
- }
- var mesh = <Mesh>abstractMesh;
- if (!mesh.isVisible || !mesh.isEnabled()) {
- return false;
- }
- if (mesh.instances.length > 0) {
- return false;
- }
- if (mesh.skeleton || mesh.hasLODLevels) {
- return false;
- }
- return true;
- }
- public apply = (scene: Scene): boolean => {
- var globalPool = scene.meshes.slice(0);
- var globalLength = globalPool.length;
- for (var index = 0; index < globalLength; index++) {
- var currentPool = new Array<Mesh>();
- var current = globalPool[index];
- // Checks
- if (!this._canBeMerged(current)) {
- continue;
- }
- currentPool.push(<Mesh>current);
- // Find compatible meshes
- for (var subIndex = index + 1; subIndex < globalLength; subIndex++) {
- var otherMesh = globalPool[subIndex];
- if (!this._canBeMerged(otherMesh)) {
- continue;
- }
- if (otherMesh.material !== current.material) {
- continue;
- }
- if (otherMesh.checkCollisions !== current.checkCollisions) {
- continue;
- }
- currentPool.push(<Mesh>otherMesh);
- globalLength--;
- globalPool.splice(subIndex, 1);
- subIndex--;
- }
- if (currentPool.length < 2) {
- continue;
- }
- // Merge meshes
- Mesh.MergeMeshes(currentPool);
- }
- return true;
- };
- }
- // Options
- export class SceneOptimizerOptions {
- public optimizations = new Array<SceneOptimization>();
- constructor(public targetFrameRate: number = 60, public trackerDuration: number = 2000) {
- }
- 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));
- // Next priority
- priority++;
- result.optimizations.push(new PostProcessesOptimization(priority));
- result.optimizations.push(new ParticlesOptimization(priority));
- // Next priority
- priority++;
- result.optimizations.push(new TextureOptimization(priority, 1024));
- return result;
- }
- 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));
- // Next priority
- priority++;
- result.optimizations.push(new PostProcessesOptimization(priority));
- result.optimizations.push(new ParticlesOptimization(priority));
- // Next priority
- priority++;
- result.optimizations.push(new TextureOptimization(priority, 512));
- // Next priority
- priority++;
- result.optimizations.push(new RenderTargetsOptimization(priority));
- // Next priority
- priority++;
- result.optimizations.push(new HardwareScalingOptimization(priority, 2));
- return result;
- }
- 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));
- // Next priority
- priority++;
- result.optimizations.push(new PostProcessesOptimization(priority));
- result.optimizations.push(new ParticlesOptimization(priority));
- // Next priority
- priority++;
- result.optimizations.push(new TextureOptimization(priority, 256));
- // Next priority
- priority++;
- result.optimizations.push(new RenderTargetsOptimization(priority));
- // Next priority
- priority++;
- result.optimizations.push(new HardwareScalingOptimization(priority, 4));
- return result;
- }
- }
- // Scene optimizer tool
- export class SceneOptimizer {
- 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();
- }
- return;
- }
- // Apply current level of optimizations
- var allDone = true;
- var noOptimizationApplied = true;
- for (var index = 0; index < options.optimizations.length; index++) {
- var optimization = options.optimizations[index];
- if (optimization.priority === currentPriorityLevel) {
- noOptimizationApplied = false;
- allDone = allDone && optimization.apply(scene);
- }
- }
- // If no optimization was applied, this is a failure :(
- if (noOptimizationApplied) {
- if (onFailure) {
- onFailure();
- }
- return;
- }
- // If all optimizations were done, move to next level
- if (allDone) {
- 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);
- });
- }
- public static OptimizeAsync(scene: Scene, options?: SceneOptimizerOptions, onSuccess?: () => void, onFailure?: () => void): void {
- if (!options) {
- options = SceneOptimizerOptions.ModerateDegradationAllowed();
- }
- // Let's the system running for a specific amount of time before checking FPS
- scene.executeWhenReady(() => {
- setTimeout(() => {
- SceneOptimizer._CheckCurrentState(scene, options, 0, onSuccess, onFailure);
- }, options.trackerDuration);
- });
- }
- }
- }
|