babylon.sceneOptimizer.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. var __extends = (this && this.__extends) || function (d, b) {
  2. for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
  3. function __() { this.constructor = d; }
  4. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  5. };
  6. var BABYLON;
  7. (function (BABYLON) {
  8. // Standard optimizations
  9. var SceneOptimization = (function () {
  10. function SceneOptimization(priority) {
  11. if (priority === void 0) { priority = 0; }
  12. this.priority = priority;
  13. this.apply = function (scene) {
  14. return true; // Return true if everything that can be done was applied
  15. };
  16. }
  17. return SceneOptimization;
  18. })();
  19. BABYLON.SceneOptimization = SceneOptimization;
  20. var TextureOptimization = (function (_super) {
  21. __extends(TextureOptimization, _super);
  22. function TextureOptimization(priority, maximumSize) {
  23. var _this = this;
  24. if (priority === void 0) { priority = 0; }
  25. if (maximumSize === void 0) { maximumSize = 1024; }
  26. _super.call(this, priority);
  27. this.priority = priority;
  28. this.maximumSize = maximumSize;
  29. this.apply = function (scene) {
  30. var allDone = true;
  31. for (var index = 0; index < scene.textures.length; index++) {
  32. var texture = scene.textures[index];
  33. if (!texture.canRescale) {
  34. continue;
  35. }
  36. var currentSize = texture.getSize();
  37. var maxDimension = Math.max(currentSize.width, currentSize.height);
  38. if (maxDimension > _this.maximumSize) {
  39. texture.scale(0.5);
  40. allDone = false;
  41. }
  42. }
  43. return allDone;
  44. };
  45. }
  46. return TextureOptimization;
  47. })(SceneOptimization);
  48. BABYLON.TextureOptimization = TextureOptimization;
  49. var HardwareScalingOptimization = (function (_super) {
  50. __extends(HardwareScalingOptimization, _super);
  51. function HardwareScalingOptimization(priority, maximumScale) {
  52. var _this = this;
  53. if (priority === void 0) { priority = 0; }
  54. if (maximumScale === void 0) { maximumScale = 2; }
  55. _super.call(this, priority);
  56. this.priority = priority;
  57. this.maximumScale = maximumScale;
  58. this._currentScale = 1;
  59. this.apply = function (scene) {
  60. _this._currentScale++;
  61. scene.getEngine().setHardwareScalingLevel(_this._currentScale);
  62. return _this._currentScale >= _this.maximumScale;
  63. };
  64. }
  65. return HardwareScalingOptimization;
  66. })(SceneOptimization);
  67. BABYLON.HardwareScalingOptimization = HardwareScalingOptimization;
  68. var ShadowsOptimization = (function (_super) {
  69. __extends(ShadowsOptimization, _super);
  70. function ShadowsOptimization() {
  71. _super.apply(this, arguments);
  72. this.apply = function (scene) {
  73. scene.shadowsEnabled = false;
  74. return true;
  75. };
  76. }
  77. return ShadowsOptimization;
  78. })(SceneOptimization);
  79. BABYLON.ShadowsOptimization = ShadowsOptimization;
  80. var PostProcessesOptimization = (function (_super) {
  81. __extends(PostProcessesOptimization, _super);
  82. function PostProcessesOptimization() {
  83. _super.apply(this, arguments);
  84. this.apply = function (scene) {
  85. scene.postProcessesEnabled = false;
  86. return true;
  87. };
  88. }
  89. return PostProcessesOptimization;
  90. })(SceneOptimization);
  91. BABYLON.PostProcessesOptimization = PostProcessesOptimization;
  92. var LensFlaresOptimization = (function (_super) {
  93. __extends(LensFlaresOptimization, _super);
  94. function LensFlaresOptimization() {
  95. _super.apply(this, arguments);
  96. this.apply = function (scene) {
  97. scene.lensFlaresEnabled = false;
  98. return true;
  99. };
  100. }
  101. return LensFlaresOptimization;
  102. })(SceneOptimization);
  103. BABYLON.LensFlaresOptimization = LensFlaresOptimization;
  104. var ParticlesOptimization = (function (_super) {
  105. __extends(ParticlesOptimization, _super);
  106. function ParticlesOptimization() {
  107. _super.apply(this, arguments);
  108. this.apply = function (scene) {
  109. scene.particlesEnabled = false;
  110. return true;
  111. };
  112. }
  113. return ParticlesOptimization;
  114. })(SceneOptimization);
  115. BABYLON.ParticlesOptimization = ParticlesOptimization;
  116. var RenderTargetsOptimization = (function (_super) {
  117. __extends(RenderTargetsOptimization, _super);
  118. function RenderTargetsOptimization() {
  119. _super.apply(this, arguments);
  120. this.apply = function (scene) {
  121. scene.renderTargetsEnabled = false;
  122. return true;
  123. };
  124. }
  125. return RenderTargetsOptimization;
  126. })(SceneOptimization);
  127. BABYLON.RenderTargetsOptimization = RenderTargetsOptimization;
  128. var MergeMeshesOptimization = (function (_super) {
  129. __extends(MergeMeshesOptimization, _super);
  130. function MergeMeshesOptimization() {
  131. var _this = this;
  132. _super.apply(this, arguments);
  133. this._canBeMerged = function (abstractMesh) {
  134. if (!(abstractMesh instanceof BABYLON.Mesh)) {
  135. return false;
  136. }
  137. var mesh = abstractMesh;
  138. if (!mesh.isVisible || !mesh.isEnabled()) {
  139. return false;
  140. }
  141. if (mesh.instances.length > 0) {
  142. return false;
  143. }
  144. if (mesh.skeleton || mesh.hasLODLevels) {
  145. return false;
  146. }
  147. return true;
  148. };
  149. this.apply = function (scene, updateSelectionTree) {
  150. var globalPool = scene.meshes.slice(0);
  151. var globalLength = globalPool.length;
  152. for (var index = 0; index < globalLength; index++) {
  153. var currentPool = new Array();
  154. var current = globalPool[index];
  155. // Checks
  156. if (!_this._canBeMerged(current)) {
  157. continue;
  158. }
  159. currentPool.push(current);
  160. // Find compatible meshes
  161. for (var subIndex = index + 1; subIndex < globalLength; subIndex++) {
  162. var otherMesh = globalPool[subIndex];
  163. if (!_this._canBeMerged(otherMesh)) {
  164. continue;
  165. }
  166. if (otherMesh.material !== current.material) {
  167. continue;
  168. }
  169. if (otherMesh.checkCollisions !== current.checkCollisions) {
  170. continue;
  171. }
  172. currentPool.push(otherMesh);
  173. globalLength--;
  174. globalPool.splice(subIndex, 1);
  175. subIndex--;
  176. }
  177. if (currentPool.length < 2) {
  178. continue;
  179. }
  180. // Merge meshes
  181. BABYLON.Mesh.MergeMeshes(currentPool);
  182. }
  183. if (updateSelectionTree != undefined) {
  184. if (updateSelectionTree) {
  185. scene.createOrUpdateSelectionOctree();
  186. }
  187. }
  188. else if (MergeMeshesOptimization.UpdateSelectionTree) {
  189. scene.createOrUpdateSelectionOctree();
  190. }
  191. return true;
  192. };
  193. }
  194. Object.defineProperty(MergeMeshesOptimization, "UpdateSelectionTree", {
  195. get: function () {
  196. return MergeMeshesOptimization._UpdateSelectionTree;
  197. },
  198. set: function (value) {
  199. MergeMeshesOptimization._UpdateSelectionTree = value;
  200. },
  201. enumerable: true,
  202. configurable: true
  203. });
  204. MergeMeshesOptimization._UpdateSelectionTree = false;
  205. return MergeMeshesOptimization;
  206. })(SceneOptimization);
  207. BABYLON.MergeMeshesOptimization = MergeMeshesOptimization;
  208. // Options
  209. var SceneOptimizerOptions = (function () {
  210. function SceneOptimizerOptions(targetFrameRate, trackerDuration) {
  211. if (targetFrameRate === void 0) { targetFrameRate = 60; }
  212. if (trackerDuration === void 0) { trackerDuration = 2000; }
  213. this.targetFrameRate = targetFrameRate;
  214. this.trackerDuration = trackerDuration;
  215. this.optimizations = new Array();
  216. }
  217. SceneOptimizerOptions.LowDegradationAllowed = function (targetFrameRate) {
  218. var result = new SceneOptimizerOptions(targetFrameRate);
  219. var priority = 0;
  220. result.optimizations.push(new MergeMeshesOptimization(priority));
  221. result.optimizations.push(new ShadowsOptimization(priority));
  222. result.optimizations.push(new LensFlaresOptimization(priority));
  223. // Next priority
  224. priority++;
  225. result.optimizations.push(new PostProcessesOptimization(priority));
  226. result.optimizations.push(new ParticlesOptimization(priority));
  227. // Next priority
  228. priority++;
  229. result.optimizations.push(new TextureOptimization(priority, 1024));
  230. return result;
  231. };
  232. SceneOptimizerOptions.ModerateDegradationAllowed = function (targetFrameRate) {
  233. var result = new SceneOptimizerOptions(targetFrameRate);
  234. var priority = 0;
  235. result.optimizations.push(new MergeMeshesOptimization(priority));
  236. result.optimizations.push(new ShadowsOptimization(priority));
  237. result.optimizations.push(new LensFlaresOptimization(priority));
  238. // Next priority
  239. priority++;
  240. result.optimizations.push(new PostProcessesOptimization(priority));
  241. result.optimizations.push(new ParticlesOptimization(priority));
  242. // Next priority
  243. priority++;
  244. result.optimizations.push(new TextureOptimization(priority, 512));
  245. // Next priority
  246. priority++;
  247. result.optimizations.push(new RenderTargetsOptimization(priority));
  248. // Next priority
  249. priority++;
  250. result.optimizations.push(new HardwareScalingOptimization(priority, 2));
  251. return result;
  252. };
  253. SceneOptimizerOptions.HighDegradationAllowed = function (targetFrameRate) {
  254. var result = new SceneOptimizerOptions(targetFrameRate);
  255. var priority = 0;
  256. result.optimizations.push(new MergeMeshesOptimization(priority));
  257. result.optimizations.push(new ShadowsOptimization(priority));
  258. result.optimizations.push(new LensFlaresOptimization(priority));
  259. // Next priority
  260. priority++;
  261. result.optimizations.push(new PostProcessesOptimization(priority));
  262. result.optimizations.push(new ParticlesOptimization(priority));
  263. // Next priority
  264. priority++;
  265. result.optimizations.push(new TextureOptimization(priority, 256));
  266. // Next priority
  267. priority++;
  268. result.optimizations.push(new RenderTargetsOptimization(priority));
  269. // Next priority
  270. priority++;
  271. result.optimizations.push(new HardwareScalingOptimization(priority, 4));
  272. return result;
  273. };
  274. return SceneOptimizerOptions;
  275. })();
  276. BABYLON.SceneOptimizerOptions = SceneOptimizerOptions;
  277. // Scene optimizer tool
  278. var SceneOptimizer = (function () {
  279. function SceneOptimizer() {
  280. }
  281. SceneOptimizer._CheckCurrentState = function (scene, options, currentPriorityLevel, onSuccess, onFailure) {
  282. // TODO: add an epsilon
  283. if (scene.getEngine().getFps() >= options.targetFrameRate) {
  284. if (onSuccess) {
  285. onSuccess();
  286. }
  287. return;
  288. }
  289. // Apply current level of optimizations
  290. var allDone = true;
  291. var noOptimizationApplied = true;
  292. for (var index = 0; index < options.optimizations.length; index++) {
  293. var optimization = options.optimizations[index];
  294. if (optimization.priority === currentPriorityLevel) {
  295. noOptimizationApplied = false;
  296. allDone = allDone && optimization.apply(scene);
  297. }
  298. }
  299. // If no optimization was applied, this is a failure :(
  300. if (noOptimizationApplied) {
  301. if (onFailure) {
  302. onFailure();
  303. }
  304. return;
  305. }
  306. // If all optimizations were done, move to next level
  307. if (allDone) {
  308. currentPriorityLevel++;
  309. }
  310. // Let's the system running for a specific amount of time before checking FPS
  311. scene.executeWhenReady(function () {
  312. setTimeout(function () {
  313. SceneOptimizer._CheckCurrentState(scene, options, currentPriorityLevel, onSuccess, onFailure);
  314. }, options.trackerDuration);
  315. });
  316. };
  317. SceneOptimizer.OptimizeAsync = function (scene, options, onSuccess, onFailure) {
  318. if (!options) {
  319. options = SceneOptimizerOptions.ModerateDegradationAllowed();
  320. }
  321. // Let's the system running for a specific amount of time before checking FPS
  322. scene.executeWhenReady(function () {
  323. setTimeout(function () {
  324. SceneOptimizer._CheckCurrentState(scene, options, 0, onSuccess, onFailure);
  325. }, options.trackerDuration);
  326. });
  327. };
  328. return SceneOptimizer;
  329. })();
  330. BABYLON.SceneOptimizer = SceneOptimizer;
  331. })(BABYLON || (BABYLON = {}));