123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832 |
- import Check from "../Core/Check.js";
- import combine from "../Core/combine.js";
- import defaultValue from "../Core/defaultValue.js";
- import defined from "../Core/defined.js";
- import destroyObject from "../Core/destroyObject.js";
- import deprecationWarning from "../Core/deprecationWarning.js";
- import Event from "../Core/Event.js";
- import getTimestamp from "../Core/getTimestamp.js";
- import JulianDate from "../Core/JulianDate.js";
- import CesiumMath from "../Core/Math.js";
- import Matrix4 from "../Core/Matrix4.js";
- import Resource from "../Core/Resource.js";
- import ClippingPlaneCollection from "./ClippingPlaneCollection.js";
- import PointCloud from "./PointCloud.js";
- import PointCloudEyeDomeLighting from "./PointCloudEyeDomeLighting.js";
- import PointCloudShading from "./PointCloudShading.js";
- import SceneMode from "./SceneMode.js";
- import ShadowMode from "./ShadowMode.js";
- /**
- * Provides playback of time-dynamic point cloud data.
- * <p>
- * Point cloud frames are prefetched in intervals determined by the average frame load time and the current clock speed.
- * If intermediate frames cannot be loaded in time to meet playback speed, they will be skipped. If frames are sufficiently
- * small or the clock is sufficiently slow then no frames will be skipped.
- * </p>
- *
- * @alias TimeDynamicPointCloud
- * @constructor
- *
- * @param {object} options Object with the following properties:
- * @param {Clock} options.clock A {@link Clock} instance that is used when determining the value for the time dimension.
- * @param {TimeIntervalCollection} options.intervals A {@link TimeIntervalCollection} with its data property being an object containing a <code>uri</code> to a 3D Tiles Point Cloud tile and an optional <code>transform</code>.
- * @param {boolean} [options.show=true] Determines if the point cloud will be shown.
- * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] A 4x4 transformation matrix that transforms the point cloud.
- * @param {ShadowMode} [options.shadows=ShadowMode.ENABLED] Determines whether the point cloud casts or receives shadows from light sources.
- * @param {number} [options.maximumMemoryUsage=256] The maximum amount of memory in MB that can be used by the point cloud.
- * @param {object} [options.shading] Options for constructing a {@link PointCloudShading} object to control point attenuation and eye dome lighting.
- * @param {Cesium3DTileStyle} [options.style] The style, defined using the {@link https://github.com/CesiumGS/3d-tiles/tree/main/specification/Styling|3D Tiles Styling language}, applied to each point in the point cloud.
- * @param {ClippingPlaneCollection} [options.clippingPlanes] The {@link ClippingPlaneCollection} used to selectively disable rendering the point cloud.
- */
- function TimeDynamicPointCloud(options) {
- options = defaultValue(options, defaultValue.EMPTY_OBJECT);
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("options.clock", options.clock);
- Check.typeOf.object("options.intervals", options.intervals);
- //>>includeEnd('debug');
- /**
- * Determines if the point cloud will be shown.
- *
- * @type {boolean}
- * @default true
- */
- this.show = defaultValue(options.show, true);
- /**
- * A 4x4 transformation matrix that transforms the point cloud.
- *
- * @type {Matrix4}
- * @default Matrix4.IDENTITY
- */
- this.modelMatrix = Matrix4.clone(
- defaultValue(options.modelMatrix, Matrix4.IDENTITY)
- );
- /**
- * Determines whether the point cloud casts or receives shadows from light sources.
- * <p>
- * Enabling shadows has a performance impact. A point cloud that casts shadows must be rendered twice, once from the camera and again from the light's point of view.
- * </p>
- * <p>
- * Shadows are rendered only when {@link Viewer#shadows} is <code>true</code>.
- * </p>
- *
- * @type {ShadowMode}
- * @default ShadowMode.ENABLED
- */
- this.shadows = defaultValue(options.shadows, ShadowMode.ENABLED);
- /**
- * The maximum amount of GPU memory (in MB) that may be used to cache point cloud frames.
- * <p>
- * Frames that are not being loaded or rendered are unloaded to enforce this.
- * </p>
- * <p>
- * If decreasing this value results in unloading tiles, the tiles are unloaded the next frame.
- * </p>
- *
- * @type {number}
- * @default 256
- *
- * @see TimeDynamicPointCloud#totalMemoryUsageInBytes
- */
- this.maximumMemoryUsage = defaultValue(options.maximumMemoryUsage, 256);
- /**
- * Options for controlling point size based on geometric error and eye dome lighting.
- * @type {PointCloudShading}
- */
- this.shading = new PointCloudShading(options.shading);
- /**
- * The style, defined using the
- * {@link https://github.com/CesiumGS/3d-tiles/tree/main/specification/Styling|3D Tiles Styling language},
- * applied to each point in the point cloud.
- * <p>
- * Assign <code>undefined</code> to remove the style, which will restore the visual
- * appearance of the point cloud to its default when no style was applied.
- * </p>
- *
- * @type {Cesium3DTileStyle}
- *
- * @example
- * pointCloud.style = new Cesium.Cesium3DTileStyle({
- * color : {
- * conditions : [
- * ['${Classification} === 0', 'color("purple", 0.5)'],
- * ['${Classification} === 1', 'color("red")'],
- * ['true', '${COLOR}']
- * ]
- * },
- * show : '${Classification} !== 2'
- * });
- *
- * @see {@link https://github.com/CesiumGS/3d-tiles/tree/main/specification/Styling|3D Tiles Styling language}
- */
- this.style = options.style;
- /**
- * The event fired to indicate that a frame failed to load. A frame may fail to load if the
- * request for its uri fails or processing fails due to invalid content.
- * <p>
- * If there are no event listeners, error messages will be logged to the console.
- * </p>
- * <p>
- * The error object passed to the listener contains two properties:
- * <ul>
- * <li><code>uri</code>: the uri of the failed frame.</li>
- * <li><code>message</code>: the error message.</li>
- * </ul>
- *
- * @type {Event}
- * @default new Event()
- *
- * @example
- * pointCloud.frameFailed.addEventListener(function(error) {
- * console.log(`An error occurred loading frame: ${error.uri}`);
- * console.log(`Error: ${error.message}`);
- * });
- */
- this.frameFailed = new Event();
- /**
- * The event fired to indicate that a new frame was rendered.
- * <p>
- * The time dynamic point cloud {@link TimeDynamicPointCloud} is passed to the event listener.
- * </p>
- * @type {Event}
- * @default new Event()
- *
- * @example
- * pointCloud.frameChanged.addEventListener(function(timeDynamicPointCloud) {
- * viewer.camera.viewBoundingSphere(timeDynamicPointCloud.boundingSphere);
- * });
- */
- this.frameChanged = new Event();
- this._clock = options.clock;
- this._intervals = options.intervals;
- this._clippingPlanes = undefined;
- this.clippingPlanes = options.clippingPlanes; // Call setter
- this._pointCloudEyeDomeLighting = new PointCloudEyeDomeLighting();
- this._loadTimestamp = undefined;
- this._clippingPlanesState = 0;
- this._styleDirty = false;
- this._pickId = undefined;
- this._totalMemoryUsageInBytes = 0;
- this._frames = [];
- this._previousInterval = undefined;
- this._nextInterval = undefined;
- this._lastRenderedFrame = undefined;
- this._clockMultiplier = 0.0;
- this._resolveReadyPromise = undefined;
- const that = this;
- // This is here for backwards compatibility and can be removed when readyPromise is removed.
- this._readyPromise = new Promise(function (resolve) {
- that._resolveReadyPromise = resolve;
- });
- // For calculating average load time of the last N frames
- this._runningSum = 0.0;
- this._runningLength = 0;
- this._runningIndex = 0;
- this._runningSamples = new Array(5).fill(0.0);
- this._runningAverage = 0.0;
- }
- Object.defineProperties(TimeDynamicPointCloud.prototype, {
- /**
- * The {@link ClippingPlaneCollection} used to selectively disable rendering the point cloud.
- *
- * @memberof TimeDynamicPointCloud.prototype
- *
- * @type {ClippingPlaneCollection}
- */
- clippingPlanes: {
- get: function () {
- return this._clippingPlanes;
- },
- set: function (value) {
- ClippingPlaneCollection.setOwner(value, this, "_clippingPlanes");
- },
- },
- /**
- * The total amount of GPU memory in bytes used by the point cloud.
- *
- * @memberof TimeDynamicPointCloud.prototype
- *
- * @type {number}
- * @readonly
- *
- * @see TimeDynamicPointCloud#maximumMemoryUsage
- */
- totalMemoryUsageInBytes: {
- get: function () {
- return this._totalMemoryUsageInBytes;
- },
- },
- /**
- * The bounding sphere of the frame being rendered. Returns <code>undefined</code> if no frame is being rendered.
- *
- * @memberof TimeDynamicPointCloud.prototype
- *
- * @type {BoundingSphere}
- * @readonly
- */
- boundingSphere: {
- get: function () {
- if (defined(this._lastRenderedFrame)) {
- return this._lastRenderedFrame.pointCloud.boundingSphere;
- }
- return undefined;
- },
- },
- /**
- * Gets the promise that will be resolved when the point cloud renders a frame for the first time.
- *
- * @memberof TimeDynamicPointCloud.prototype
- *
- * @type {Promise<TimeDynamicPointCloud>}
- * @readonly
- * @deprecated
- */
- readyPromise: {
- get: function () {
- deprecationWarning(
- "TimeDynamicPointCloud.readyPromise",
- "TimeDynamicPointCloud.readyPromise was deprecated in CesiumJS 1.104. It will be removed in 1.107. Use TimeDynamicPointCloud.frameFailed instead."
- );
- return this._readyPromise;
- },
- },
- });
- function getFragmentShaderLoaded(fs) {
- return `uniform vec4 czm_pickColor;\n${fs}`;
- }
- function getUniformMapLoaded(stream) {
- return function (uniformMap) {
- return combine(uniformMap, {
- czm_pickColor: function () {
- return stream._pickId.color;
- },
- });
- };
- }
- function getPickIdLoaded() {
- return "czm_pickColor";
- }
- /**
- * Marks the point cloud's {@link TimeDynamicPointCloud#style} as dirty, which forces all
- * points to re-evaluate the style in the next frame.
- */
- TimeDynamicPointCloud.prototype.makeStyleDirty = function () {
- this._styleDirty = true;
- };
- /**
- * Exposed for testing.
- *
- * @private
- */
- TimeDynamicPointCloud.prototype._getAverageLoadTime = function () {
- if (this._runningLength === 0) {
- // Before any frames have loaded make a best guess about the average load time
- return 0.05;
- }
- return this._runningAverage;
- };
- const scratchDate = new JulianDate();
- function getClockMultiplier(that) {
- const clock = that._clock;
- const isAnimating = clock.canAnimate && clock.shouldAnimate;
- const multiplier = clock.multiplier;
- return isAnimating ? multiplier : 0.0;
- }
- function getIntervalIndex(that, interval) {
- return that._intervals.indexOf(interval.start);
- }
- function getNextInterval(that, currentInterval) {
- const intervals = that._intervals;
- const clock = that._clock;
- const multiplier = getClockMultiplier(that);
- if (multiplier === 0.0) {
- return undefined;
- }
- const averageLoadTime = that._getAverageLoadTime();
- const time = JulianDate.addSeconds(
- clock.currentTime,
- averageLoadTime * multiplier,
- scratchDate
- );
- let index = intervals.indexOf(time);
- const currentIndex = getIntervalIndex(that, currentInterval);
- if (index === currentIndex) {
- if (multiplier >= 0) {
- ++index;
- } else {
- --index;
- }
- }
- // Returns undefined if not in range
- return intervals.get(index);
- }
- function getCurrentInterval(that) {
- const intervals = that._intervals;
- const clock = that._clock;
- const time = clock.currentTime;
- const index = intervals.indexOf(time);
- // Returns undefined if not in range
- return intervals.get(index);
- }
- function reachedInterval(that, currentInterval, nextInterval) {
- const multiplier = getClockMultiplier(that);
- const currentIndex = getIntervalIndex(that, currentInterval);
- const nextIndex = getIntervalIndex(that, nextInterval);
- if (multiplier >= 0) {
- return currentIndex >= nextIndex;
- }
- return currentIndex <= nextIndex;
- }
- function handleFrameFailure(that, uri) {
- return function (error) {
- const message = defined(error.message) ? error.message : error.toString();
- if (that.frameFailed.numberOfListeners > 0) {
- that.frameFailed.raiseEvent({
- uri: uri,
- message: message,
- });
- } else {
- console.log(`A frame failed to load: ${uri}`);
- console.log(`Error: ${message}`);
- }
- };
- }
- function requestFrame(that, interval, frameState) {
- const index = getIntervalIndex(that, interval);
- const frames = that._frames;
- let frame = frames[index];
- if (!defined(frame)) {
- const transformArray = interval.data.transform;
- const transform = defined(transformArray)
- ? Matrix4.fromArray(transformArray)
- : undefined;
- const uri = interval.data.uri;
- frame = {
- pointCloud: undefined,
- transform: transform,
- timestamp: getTimestamp(),
- sequential: true,
- ready: false,
- touchedFrameNumber: frameState.frameNumber,
- uri: uri,
- };
- frames[index] = frame;
- Resource.fetchArrayBuffer({
- url: uri,
- })
- .then(function (arrayBuffer) {
- // PERFORMANCE_IDEA: share a memory pool, render states, shaders, and other resources among all
- // frames. Each frame just needs an index/offset into the pool.
- frame.pointCloud = new PointCloud({
- arrayBuffer: arrayBuffer,
- cull: true,
- fragmentShaderLoaded: getFragmentShaderLoaded,
- uniformMapLoaded: getUniformMapLoaded(that),
- pickIdLoaded: getPickIdLoaded,
- });
- })
- .catch(handleFrameFailure(that, uri));
- }
- return frame;
- }
- function updateAverageLoadTime(that, loadTime) {
- that._runningSum += loadTime;
- that._runningSum -= that._runningSamples[that._runningIndex];
- that._runningSamples[that._runningIndex] = loadTime;
- that._runningLength = Math.min(
- that._runningLength + 1,
- that._runningSamples.length
- );
- that._runningIndex = (that._runningIndex + 1) % that._runningSamples.length;
- that._runningAverage = that._runningSum / that._runningLength;
- }
- function prepareFrame(that, frame, updateState, frameState) {
- if (frame.touchedFrameNumber < frameState.frameNumber - 1) {
- // If this frame was not loaded in sequential updates then it can't be used it for calculating the average load time.
- // For example: selecting a frame on the timeline, selecting another frame before the request finishes, then selecting this frame later.
- frame.sequential = false;
- }
- const pointCloud = frame.pointCloud;
- if (defined(pointCloud) && !frame.ready) {
- // Call update to prepare renderer resources. Don't render anything yet.
- const commandList = frameState.commandList;
- const lengthBeforeUpdate = commandList.length;
- renderFrame(that, frame, updateState, frameState);
- if (pointCloud.ready) {
- // Point cloud became ready this update
- frame.ready = true;
- that._totalMemoryUsageInBytes += pointCloud.geometryByteLength;
- commandList.length = lengthBeforeUpdate; // Don't allow preparing frame to insert commands.
- if (frame.sequential) {
- // Update the values used to calculate average load time
- const loadTime = (getTimestamp() - frame.timestamp) / 1000.0;
- updateAverageLoadTime(that, loadTime);
- }
- }
- }
- frame.touchedFrameNumber = frameState.frameNumber;
- }
- const scratchModelMatrix = new Matrix4();
- function getGeometricError(that, pointCloud) {
- const shading = that.shading;
- if (defined(shading) && defined(shading.baseResolution)) {
- return shading.baseResolution;
- } else if (defined(pointCloud.boundingSphere)) {
- return CesiumMath.cbrt(
- pointCloud.boundingSphere.volume() / pointCloud.pointsLength
- );
- }
- return 0.0;
- }
- function getMaximumAttenuation(that) {
- const shading = that.shading;
- if (defined(shading) && defined(shading.maximumAttenuation)) {
- return shading.maximumAttenuation;
- }
- // Return a hardcoded maximum attenuation. For a tileset this would instead be the maximum screen space error.
- return 10.0;
- }
- const defaultShading = new PointCloudShading();
- function renderFrame(that, frame, updateState, frameState) {
- const shading = defaultValue(that.shading, defaultShading);
- const pointCloud = frame.pointCloud;
- const transform = defaultValue(frame.transform, Matrix4.IDENTITY);
- pointCloud.modelMatrix = Matrix4.multiplyTransformation(
- that.modelMatrix,
- transform,
- scratchModelMatrix
- );
- pointCloud.style = that.style;
- pointCloud.time = updateState.timeSinceLoad;
- pointCloud.shadows = that.shadows;
- pointCloud.clippingPlanes = that._clippingPlanes;
- pointCloud.isClipped = updateState.isClipped;
- pointCloud.attenuation = shading.attenuation;
- pointCloud.backFaceCulling = shading.backFaceCulling;
- pointCloud.normalShading = shading.normalShading;
- pointCloud.geometricError = getGeometricError(that, pointCloud);
- pointCloud.geometricErrorScale = shading.geometricErrorScale;
- pointCloud.maximumAttenuation = getMaximumAttenuation(that);
- try {
- pointCloud.update(frameState);
- } catch (error) {
- handleFrameFailure(that, frame.uri)(error);
- }
- frame.touchedFrameNumber = frameState.frameNumber;
- }
- function loadFrame(that, interval, updateState, frameState) {
- const frame = requestFrame(that, interval, frameState);
- prepareFrame(that, frame, updateState, frameState);
- }
- function getUnloadCondition(frameState) {
- return function (frame) {
- // Unload all frames that aren't currently being loaded or rendered
- return frame.touchedFrameNumber < frameState.frameNumber;
- };
- }
- function unloadFrames(that, unloadCondition) {
- const frames = that._frames;
- const length = frames.length;
- for (let i = 0; i < length; ++i) {
- const frame = frames[i];
- if (defined(frame)) {
- if (!defined(unloadCondition) || unloadCondition(frame)) {
- const pointCloud = frame.pointCloud;
- if (frame.ready) {
- that._totalMemoryUsageInBytes -= pointCloud.geometryByteLength;
- }
- if (defined(pointCloud)) {
- pointCloud.destroy();
- }
- if (frame === that._lastRenderedFrame) {
- that._lastRenderedFrame = undefined;
- }
- frames[i] = undefined;
- }
- }
- }
- }
- function getFrame(that, interval) {
- const index = getIntervalIndex(that, interval);
- const frame = that._frames[index];
- if (defined(frame) && frame.ready) {
- return frame;
- }
- }
- function updateInterval(that, interval, frame, updateState, frameState) {
- if (defined(frame)) {
- if (frame.ready) {
- return true;
- }
- loadFrame(that, interval, updateState, frameState);
- return frame.ready;
- }
- return false;
- }
- function getNearestReadyInterval(
- that,
- previousInterval,
- currentInterval,
- updateState,
- frameState
- ) {
- let i;
- let interval;
- let frame;
- const intervals = that._intervals;
- const frames = that._frames;
- const currentIndex = getIntervalIndex(that, currentInterval);
- const previousIndex = getIntervalIndex(that, previousInterval);
- if (currentIndex >= previousIndex) {
- // look backwards
- for (i = currentIndex; i >= previousIndex; --i) {
- interval = intervals.get(i);
- frame = frames[i];
- if (updateInterval(that, interval, frame, updateState, frameState)) {
- return interval;
- }
- }
- } else {
- // look forwards
- for (i = currentIndex; i <= previousIndex; ++i) {
- interval = intervals.get(i);
- frame = frames[i];
- if (updateInterval(that, interval, frame, updateState, frameState)) {
- return interval;
- }
- }
- }
- // If no intervals are ready return the previous interval
- return previousInterval;
- }
- function setFramesDirty(that, clippingPlanesDirty, styleDirty) {
- const frames = that._frames;
- const framesLength = frames.length;
- for (let i = 0; i < framesLength; ++i) {
- const frame = frames[i];
- if (defined(frame) && defined(frame.pointCloud)) {
- frame.pointCloud.clippingPlanesDirty = clippingPlanesDirty;
- frame.pointCloud.styleDirty = styleDirty;
- }
- }
- }
- const updateState = {
- timeSinceLoad: 0,
- isClipped: false,
- clippingPlanesDirty: false,
- };
- /**
- * @private
- */
- TimeDynamicPointCloud.prototype.update = function (frameState) {
- if (frameState.mode === SceneMode.MORPHING) {
- return;
- }
- if (!this.show) {
- return;
- }
- if (!defined(this._pickId)) {
- this._pickId = frameState.context.createPickId({
- primitive: this,
- });
- }
- if (!defined(this._loadTimestamp)) {
- this._loadTimestamp = JulianDate.clone(frameState.time);
- }
- // For styling
- const timeSinceLoad = Math.max(
- JulianDate.secondsDifference(frameState.time, this._loadTimestamp) * 1000,
- 0.0
- );
- // Update clipping planes
- const clippingPlanes = this._clippingPlanes;
- let clippingPlanesState = 0;
- let clippingPlanesDirty = false;
- const isClipped = defined(clippingPlanes) && clippingPlanes.enabled;
- if (isClipped) {
- clippingPlanes.update(frameState);
- clippingPlanesState = clippingPlanes.clippingPlanesState;
- }
- if (this._clippingPlanesState !== clippingPlanesState) {
- this._clippingPlanesState = clippingPlanesState;
- clippingPlanesDirty = true;
- }
- const styleDirty = this._styleDirty;
- this._styleDirty = false;
- if (clippingPlanesDirty || styleDirty) {
- setFramesDirty(this, clippingPlanesDirty, styleDirty);
- }
- updateState.timeSinceLoad = timeSinceLoad;
- updateState.isClipped = isClipped;
- const shading = this.shading;
- const eyeDomeLighting = this._pointCloudEyeDomeLighting;
- const commandList = frameState.commandList;
- const lengthBeforeUpdate = commandList.length;
- let previousInterval = this._previousInterval;
- let nextInterval = this._nextInterval;
- const currentInterval = getCurrentInterval(this);
- if (!defined(currentInterval)) {
- return;
- }
- let clockMultiplierChanged = false;
- const clockMultiplier = getClockMultiplier(this);
- const clockPaused = clockMultiplier === 0;
- if (clockMultiplier !== this._clockMultiplier) {
- clockMultiplierChanged = true;
- this._clockMultiplier = clockMultiplier;
- }
- if (!defined(previousInterval) || clockPaused) {
- previousInterval = currentInterval;
- }
- if (
- !defined(nextInterval) ||
- clockMultiplierChanged ||
- reachedInterval(this, currentInterval, nextInterval)
- ) {
- nextInterval = getNextInterval(this, currentInterval);
- }
- previousInterval = getNearestReadyInterval(
- this,
- previousInterval,
- currentInterval,
- updateState,
- frameState
- );
- let frame = getFrame(this, previousInterval);
- if (!defined(frame)) {
- // The frame is not ready to render. This can happen when the simulation starts or when scrubbing the timeline
- // to a frame that hasn't loaded yet. Just render the last rendered frame in its place until it finishes loading.
- loadFrame(this, previousInterval, updateState, frameState);
- frame = this._lastRenderedFrame;
- }
- if (defined(frame)) {
- renderFrame(this, frame, updateState, frameState);
- }
- if (defined(nextInterval)) {
- // Start loading the next frame
- loadFrame(this, nextInterval, updateState, frameState);
- }
- const that = this;
- if (defined(frame) && !defined(this._lastRenderedFrame)) {
- frameState.afterRender.push(function () {
- // This is here for backwards compatibility and can be removed when readyPromise is removed.
- that._resolveReadyPromise(that);
- return true;
- });
- }
- if (defined(frame) && frame !== this._lastRenderedFrame) {
- if (that.frameChanged.numberOfListeners > 0) {
- frameState.afterRender.push(function () {
- that.frameChanged.raiseEvent(that);
- return true;
- });
- }
- }
- this._previousInterval = previousInterval;
- this._nextInterval = nextInterval;
- this._lastRenderedFrame = frame;
- const totalMemoryUsageInBytes = this._totalMemoryUsageInBytes;
- const maximumMemoryUsageInBytes = this.maximumMemoryUsage * 1024 * 1024;
- if (totalMemoryUsageInBytes > maximumMemoryUsageInBytes) {
- unloadFrames(this, getUnloadCondition(frameState));
- }
- const lengthAfterUpdate = commandList.length;
- const addedCommandsLength = lengthAfterUpdate - lengthBeforeUpdate;
- if (
- defined(shading) &&
- shading.attenuation &&
- shading.eyeDomeLighting &&
- addedCommandsLength > 0
- ) {
- eyeDomeLighting.update(
- frameState,
- lengthBeforeUpdate,
- shading,
- this.boundingSphere
- );
- }
- };
- /**
- * Returns true if this object was destroyed; otherwise, false.
- * <br /><br />
- * If this object was destroyed, it should not be used; calling any function other than
- * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
- *
- * @returns {boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
- *
- * @see TimeDynamicPointCloud#destroy
- */
- TimeDynamicPointCloud.prototype.isDestroyed = function () {
- return false;
- };
- /**
- * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
- * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
- * <br /><br />
- * Once an object is destroyed, it should not be used; calling any function other than
- * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
- * assign the return value (<code>undefined</code>) to the object as done in the example.
- *
- * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
- *
- * @example
- * pointCloud = pointCloud && pointCloud.destroy();
- *
- * @see TimeDynamicPointCloud#isDestroyed
- */
- TimeDynamicPointCloud.prototype.destroy = function () {
- unloadFrames(this);
- this._clippingPlanes = this._clippingPlanes && this._clippingPlanes.destroy();
- this._pickId = this._pickId && this._pickId.destroy();
- return destroyObject(this);
- };
- export default TimeDynamicPointCloud;
|