babylon.sceneOptimizer.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  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. if (mesh.parent) {
  148. return false;
  149. }
  150. return true;
  151. };
  152. this.apply = function (scene, updateSelectionTree) {
  153. var globalPool = scene.meshes.slice(0);
  154. var globalLength = globalPool.length;
  155. for (var index = 0; index < globalLength; index++) {
  156. var currentPool = new Array();
  157. var current = globalPool[index];
  158. // Checks
  159. if (!_this._canBeMerged(current)) {
  160. continue;
  161. }
  162. currentPool.push(current);
  163. // Find compatible meshes
  164. for (var subIndex = index + 1; subIndex < globalLength; subIndex++) {
  165. var otherMesh = globalPool[subIndex];
  166. if (!_this._canBeMerged(otherMesh)) {
  167. continue;
  168. }
  169. if (otherMesh.material !== current.material) {
  170. continue;
  171. }
  172. if (otherMesh.checkCollisions !== current.checkCollisions) {
  173. continue;
  174. }
  175. currentPool.push(otherMesh);
  176. globalLength--;
  177. globalPool.splice(subIndex, 1);
  178. subIndex--;
  179. }
  180. if (currentPool.length < 2) {
  181. continue;
  182. }
  183. // Merge meshes
  184. BABYLON.Mesh.MergeMeshes(currentPool);
  185. }
  186. if (updateSelectionTree != undefined) {
  187. if (updateSelectionTree) {
  188. scene.createOrUpdateSelectionOctree();
  189. }
  190. }
  191. else if (MergeMeshesOptimization.UpdateSelectionTree) {
  192. scene.createOrUpdateSelectionOctree();
  193. }
  194. return true;
  195. };
  196. }
  197. Object.defineProperty(MergeMeshesOptimization, "UpdateSelectionTree", {
  198. get: function () {
  199. return MergeMeshesOptimization._UpdateSelectionTree;
  200. },
  201. set: function (value) {
  202. MergeMeshesOptimization._UpdateSelectionTree = value;
  203. },
  204. enumerable: true,
  205. configurable: true
  206. });
  207. MergeMeshesOptimization._UpdateSelectionTree = false;
  208. return MergeMeshesOptimization;
  209. })(SceneOptimization);
  210. BABYLON.MergeMeshesOptimization = MergeMeshesOptimization;
  211. // Options
  212. var SceneOptimizerOptions = (function () {
  213. function SceneOptimizerOptions(targetFrameRate, trackerDuration) {
  214. if (targetFrameRate === void 0) { targetFrameRate = 60; }
  215. if (trackerDuration === void 0) { trackerDuration = 2000; }
  216. this.targetFrameRate = targetFrameRate;
  217. this.trackerDuration = trackerDuration;
  218. this.optimizations = new Array();
  219. }
  220. SceneOptimizerOptions.LowDegradationAllowed = function (targetFrameRate) {
  221. var result = new SceneOptimizerOptions(targetFrameRate);
  222. var priority = 0;
  223. result.optimizations.push(new MergeMeshesOptimization(priority));
  224. result.optimizations.push(new ShadowsOptimization(priority));
  225. result.optimizations.push(new LensFlaresOptimization(priority));
  226. // Next priority
  227. priority++;
  228. result.optimizations.push(new PostProcessesOptimization(priority));
  229. result.optimizations.push(new ParticlesOptimization(priority));
  230. // Next priority
  231. priority++;
  232. result.optimizations.push(new TextureOptimization(priority, 1024));
  233. return result;
  234. };
  235. SceneOptimizerOptions.ModerateDegradationAllowed = function (targetFrameRate) {
  236. var result = new SceneOptimizerOptions(targetFrameRate);
  237. var priority = 0;
  238. result.optimizations.push(new MergeMeshesOptimization(priority));
  239. result.optimizations.push(new ShadowsOptimization(priority));
  240. result.optimizations.push(new LensFlaresOptimization(priority));
  241. // Next priority
  242. priority++;
  243. result.optimizations.push(new PostProcessesOptimization(priority));
  244. result.optimizations.push(new ParticlesOptimization(priority));
  245. // Next priority
  246. priority++;
  247. result.optimizations.push(new TextureOptimization(priority, 512));
  248. // Next priority
  249. priority++;
  250. result.optimizations.push(new RenderTargetsOptimization(priority));
  251. // Next priority
  252. priority++;
  253. result.optimizations.push(new HardwareScalingOptimization(priority, 2));
  254. return result;
  255. };
  256. SceneOptimizerOptions.HighDegradationAllowed = function (targetFrameRate) {
  257. var result = new SceneOptimizerOptions(targetFrameRate);
  258. var priority = 0;
  259. result.optimizations.push(new MergeMeshesOptimization(priority));
  260. result.optimizations.push(new ShadowsOptimization(priority));
  261. result.optimizations.push(new LensFlaresOptimization(priority));
  262. // Next priority
  263. priority++;
  264. result.optimizations.push(new PostProcessesOptimization(priority));
  265. result.optimizations.push(new ParticlesOptimization(priority));
  266. // Next priority
  267. priority++;
  268. result.optimizations.push(new TextureOptimization(priority, 256));
  269. // Next priority
  270. priority++;
  271. result.optimizations.push(new RenderTargetsOptimization(priority));
  272. // Next priority
  273. priority++;
  274. result.optimizations.push(new HardwareScalingOptimization(priority, 4));
  275. return result;
  276. };
  277. return SceneOptimizerOptions;
  278. })();
  279. BABYLON.SceneOptimizerOptions = SceneOptimizerOptions;
  280. // Scene optimizer tool
  281. var SceneOptimizer = (function () {
  282. function SceneOptimizer() {
  283. }
  284. SceneOptimizer._CheckCurrentState = function (scene, options, currentPriorityLevel, onSuccess, onFailure) {
  285. // TODO: add an epsilon
  286. if (scene.getEngine().getFps() >= options.targetFrameRate) {
  287. if (onSuccess) {
  288. onSuccess();
  289. }
  290. return;
  291. }
  292. // Apply current level of optimizations
  293. var allDone = true;
  294. var noOptimizationApplied = true;
  295. for (var index = 0; index < options.optimizations.length; index++) {
  296. var optimization = options.optimizations[index];
  297. if (optimization.priority === currentPriorityLevel) {
  298. noOptimizationApplied = false;
  299. allDone = allDone && optimization.apply(scene);
  300. }
  301. }
  302. // If no optimization was applied, this is a failure :(
  303. if (noOptimizationApplied) {
  304. if (onFailure) {
  305. onFailure();
  306. }
  307. return;
  308. }
  309. // If all optimizations were done, move to next level
  310. if (allDone) {
  311. currentPriorityLevel++;
  312. }
  313. // Let's the system running for a specific amount of time before checking FPS
  314. scene.executeWhenReady(function () {
  315. setTimeout(function () {
  316. SceneOptimizer._CheckCurrentState(scene, options, currentPriorityLevel, onSuccess, onFailure);
  317. }, options.trackerDuration);
  318. });
  319. };
  320. SceneOptimizer.OptimizeAsync = function (scene, options, onSuccess, onFailure) {
  321. if (!options) {
  322. options = SceneOptimizerOptions.ModerateDegradationAllowed();
  323. }
  324. // Let's the system running for a specific amount of time before checking FPS
  325. scene.executeWhenReady(function () {
  326. setTimeout(function () {
  327. SceneOptimizer._CheckCurrentState(scene, options, 0, onSuccess, onFailure);
  328. }, options.trackerDuration);
  329. });
  330. };
  331. return SceneOptimizer;
  332. })();
  333. BABYLON.SceneOptimizer = SceneOptimizer;
  334. })(BABYLON || (BABYLON = {}));