diff --git a/examples/Configs_disableDoublePrecisionAndRAF.html b/examples/Configs_disableDoublePrecisionAndRAF.html new file mode 100644 index 0000000000..8aab23bc76 --- /dev/null +++ b/examples/Configs_disableDoublePrecisionAndRAF.html @@ -0,0 +1,103 @@ + + + + + + + xeokit Example + + + + + + + +
+

Configs - disabling double precision and RAF


+

In this example we use a Configs to disable xeokit's double-precision support, which gives a performance and memory boost + on low-power devices. This however also means that we can no longer render double-precision models without jittering.

+ +

We're also switching xeokit from using window.requestAnimationFrame to window.setInterval for its main render loop, which can also + give a performance boost for some cases.

+

Stats

+ +

Components Used

+ +
+ + + \ No newline at end of file diff --git a/examples/index.html b/examples/index.html index ad7677a419..95dbad7532 100644 --- a/examples/index.html +++ b/examples/index.html @@ -679,6 +679,11 @@ // ["DimensionsFootprintModel_example2", "Dimensions footprint experiment #2"] ], + "Configs": [ + "#Configuring the xeokit-sdk", + ["Configs_disableDoublePrecisionAndRAF", "Disable double precision (and RAF) for extra performance"] + ], + "Viewer": [ "#General viewer techniques", ["viewer_createDestroyRepeat", "Testing repeated viewer creation and deletion"], diff --git a/src/viewer/Configs.js b/src/viewer/Configs.js new file mode 100644 index 0000000000..538c773626 --- /dev/null +++ b/src/viewer/Configs.js @@ -0,0 +1,115 @@ +import {math} from "./scene/math/math.js"; +import {core} from "./scene/core"; + +/** + * Manages global configurations for all {@link Viewer}s. + * + * ## Usage + * + * In the example below, we'll disable xeokit's double-precision support, which gives a performance and memory boost + * on low-power devices, but means that we can no longer render double-precision models without jittering. + * + * We'll also switch from window.requestAnimationFrame to window.setInterval for xeokit's animations, which can also give a + * performance boost in some cases. + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#Configs_disableDoublePrecisionAndRAF)] + * + * ````javascript + * import {Configs, Viewer, XKTLoaderPlugin} from "../dist/xeokit-sdk.min.es.js"; + * + * // Access xeoit-sdk global configs. + * // We typically set configs only before we create any Viewers. + * const configs = new Configs(); + * + * // Disable 64-bit precision for extra speed. + * // Only set this config once, before you create any Viewers. + * configs.doublePrecisionEnabled = false; + * + * // Disable window.requestAnimationFrame (RAF) and use + * // window.setInterval for Viewer render loops. + * // This config can be switched dynamically, if needed. + * configs.rafEnabled = false; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * viewer.camera.eye = [-3.933, 2.855, 27.018]; + * viewer.camera.look = [4.400, 3.724, 8.899]; + * viewer.camera.up = [-0.018, 0.999, 0.039]; + * + * const xktLoader = new XKTLoaderPlugin(viewer); + * + * const model = xktLoader.load({ + * src: "../assets/models/xkt/v8/ifc/Duplex.ifc.xkt" + * }); + * ```` + */ +class Configs { + + /** + * Creates a Configs. + */ + constructor() { + + } + + /** + * Sets whether double precision mode is enabled for {@link Viewer}s. + * + * When double precision mode is enabled (default), {@link Viewer}s will accurately render models that contain + * double-precision coordinates, without jittering. + * + * Internally, double precision incurs extra performance and memory overhead, so if we're certain that + * we're not going to render models that rely on double-precision coordinates, then it's a good idea to disable + * it, especially on low-power devices. + * + * This should only be set once, before creating any {@link Viewer}s. + * + * @returns {boolean} + */ + set doublePrecisionEnabled(doublePrecision) { + math.setDoublePrecisionEnabled(doublePrecision); + } + + /** + * Gets whether double precision mode is enabled for all {@link Viewer}s. + * + * @returns {boolean} + */ + get doublePrecisionEnabled() { + return math.getDoublePrecisionEnabled(); + } + + + + /** + * Sets whether Viewers currently use window.requestAnimationFrame (RAF) or window.setInterval for animations. + * + * With RAF, the render loop is suspended whenever we switch away from the browser tab that + * contains our application. With setInterval, the render loop will continue running. Since a {@link Viewer} only + * renders frames when the view has actually updated, disabling RAF can actually give a performance boost. + * + * This is ````true```` by default, to use RAF. + * + * This can be dynamically set at any time. + * + * @returns {boolean} + */ + set rafEnabled(rafEnabled) { + core.setRAFEnabled(rafEnabled); + } + + /** + * Gets whether {@link Viewer}s currently use window.requestAnimationFrame (RAF) or window.setInterval for animations. + * + * @returns {boolean} + */ + get rafEnabled() { + return core.getRAFEnabled(); + } + + +} + +export {Configs}; \ No newline at end of file diff --git a/src/viewer/index.js b/src/viewer/index.js index eb0e5dad6d..c3d8373006 100644 --- a/src/viewer/index.js +++ b/src/viewer/index.js @@ -1,4 +1,5 @@ export * from "./localization/LocaleService.js"; export * from "./scene/index.js"; export * from "./Plugin.js"; -export * from "./Viewer.js"; \ No newline at end of file +export * from "./Viewer.js"; +export * from "./Configs.js"; \ No newline at end of file diff --git a/src/viewer/scene/core.js b/src/viewer/scene/core.js index 7cde72a842..e5b6b1800d 100644 --- a/src/viewer/scene/core.js +++ b/src/viewer/scene/core.js @@ -3,6 +3,9 @@ import {Map} from './utils/Map.js'; import {stats} from './stats.js'; import {utils} from './utils.js'; +let rafEnabled = true; +let interval = null; + const scenesRenderInfo = {}; // Used for throttling FPS for each Scene const sceneIDMap = new Map(); // Ensures unique scene IDs const taskQueue = new Queue(); // Task queue, which is pumped on each frame; tasks are pushed to it with calls to xeokit.schedule @@ -11,7 +14,6 @@ const taskBudget = 10; // Millisecs we're allowed to spend on tasks in each fram const fpsSamples = []; const numFPSSamples = 30; -let defaultScene = null;// Default singleton Scene, lazy-initialized in getter let lastTime = 0; let elapsedTime; let totalFPS = 0; @@ -71,6 +73,32 @@ function Core() { }); }; + /** + * @private + */ + this.setRAFEnabled = function(value) { + if (value === rafEnabled) { + return; + } + rafEnabled = value; + if (rafEnabled) { + if (interval !== null) { + clearInterval(interval); + interval = null; + } + window.requestAnimationFrame(frame); + } else { + interval = setInterval(frame, 16); + } + }; + + /** + * @private + */ + this.getRAFEnabled = function() { + return rafEnabled; + } + /** * @private */ @@ -153,7 +181,9 @@ const frame = function () { fireTickEvents(time); renderScenes(); lastTime = time; - window.requestAnimationFrame(frame); + if (rafEnabled) { + window.requestAnimationFrame(frame); + } }; function runTasks(time) { // Process as many enqueued tasks as we can within the per-frame task budget @@ -229,6 +259,10 @@ function renderScenes() { } } -window.requestAnimationFrame(frame); +if (rafEnabled) { + window.requestAnimationFrame(frame); +} else { + interval = setInterval(frame, 16); +} export {core}; \ No newline at end of file diff --git a/src/viewer/scene/math/math.js b/src/viewer/scene/math/math.js index d194d53b76..350ef4510d 100644 --- a/src/viewer/scene/math/math.js +++ b/src/viewer/scene/math/math.js @@ -1,7 +1,7 @@ // Some temporary vars to help avoid garbage collection -const doublePrecision = true; -const FloatArrayType = doublePrecision ? Float64Array : Float32Array; +let doublePrecision = true; +let FloatArrayType = doublePrecision ? Float64Array : Float32Array; const tempMat1 = new FloatArrayType(16); const tempMat2 = new FloatArrayType(16); @@ -13,6 +13,15 @@ const tempVec4 = new FloatArrayType(4); */ const math = { + setDoublePrecisionEnabled(enable) { + doublePrecision = enable; + FloatArrayType = doublePrecision ? Float64Array : Float32Array; + }, + + getDoublePrecisionEnabled() { + return doublePrecision; + }, + MIN_DOUBLE: -Number.MAX_SAFE_INTEGER, MAX_DOUBLE: Number.MAX_SAFE_INTEGER,