Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tile loading events for Voxels #12430

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions packages/engine/Source/Scene/VoxelPrimitive.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import CustomShader from "./Model/CustomShader.js";
import Cartographic from "../Core/Cartographic.js";
import Ellipsoid from "../Core/Ellipsoid.js";
import VerticalExaggeration from "../Core/VerticalExaggeration.js";
import Cesium3DTilesetStatistics from "./Cesium3DTilesetStatistics.js";

/**
* A primitive that renders voxel data from a {@link VoxelProvider}.
Expand Down Expand Up @@ -70,6 +71,12 @@ function VoxelPrimitive(options) {
*/
this._traversal = undefined;

/**
* @type {Cesium3DTilesetStatistics}
* @private
*/
this._statistics = new Cesium3DTilesetStatistics();

/**
* This member is not created until the provider is ready.
*
Expand Down Expand Up @@ -450,6 +457,112 @@ function VoxelPrimitive(options) {
}
}

/**
* The event fired to indicate that a tile's content was loaded.
* <p>
* The loaded tile is passed to the event listener.
* </p>
* <p>
* This event is fired during the tileset traversal while the frame is being rendered
* so that updates to the tile take effect in the same frame. Do not create or modify
* Cesium entities or primitives during the event listener.
* </p>
*
* @type {Event}
* @default new Event()
*
* @example
* voxelPrimitive.tileLoad.addEventListener(function(tile) {
* console.log('A tile was loaded.');
* });
*/
this.tileLoad = new Event();

/**
* The event fired to indicate that a tile's content was unloaded.
* <p>
* The unloaded {@link Cesium3DTile} is passed to the event listener.
* </p>
* <p>
* This event is fired immediately before the tile's content is unloaded while the frame is being
* rendered so that the event listener has access to the tile's content. Do not create
* or modify Cesium entities or primitives during the event listener.
* </p>
*
* @type {Event}
* @default new Event()
*
* @example
* primitive.tileUnload.addEventListener(function(tile) {
* console.log('A tile was unloaded from the cache.');
* });
*
*/
this.tileUnload = new Event();

/**
* The event fired to indicate progress of loading new tiles. This event is fired when a new tile
* is requested, when a requested tile is finished downloading, and when a downloaded tile has been
* processed and is ready to render.
* <p>
* The number of pending tile requests, <code>numberOfPendingRequests</code>, and number of tiles
* processing, <code>numberOfTilesProcessing</code> are passed to the event listener.
* </p>
* <p>
* This event is fired at the end of the frame after the scene is rendered.
* </p>
*
* @type {Event}
* @default new Event()
*
* @example
* tileset.loadProgress.addEventListener(function(numberOfPendingRequests, numberOfTilesProcessing) {
* if ((numberOfPendingRequests === 0) && (numberOfTilesProcessing === 0)) {
* console.log('Stopped loading');
* return;
* }
*
* console.log(`Loading: requests: ${numberOfPendingRequests}, processing: ${numberOfTilesProcessing}`);
* });
*/
this.loadProgress = new Event();

/**
* The event fired to indicate that all tiles that meet the screen space error this frame are loaded. The voxel
* primitive is completely loaded for this view.
* <p>
* This event is fired at the end of the frame after the scene is rendered.
* </p>
*
* @type {Event}
* @default new Event()
*
* @example
* tileset.allTilesLoaded.addEventListener(function() {
* console.log('All tiles are loaded');
* });
*/
this.allTilesLoaded = new Event();

/**
* The event fired to indicate that all tiles that meet the screen space error this frame are loaded. This event
* is fired once when all tiles in the initial view are loaded.
* <p>
* This event is fired at the end of the frame after the scene is rendered.
* </p>
*
* @type {Event}
* @default new Event()
*
* @example
* tileset.initialTilesLoaded.addEventListener(function() {
* console.log('Initial tiles are loaded');
* });
*
* @see Cesium3DTileset#allTilesLoaded
*/
this.initialTilesLoaded = new Event();

// If the provider fails to initialize the primitive will fail too.
const provider = this._provider;
initialize(this, provider);
Expand Down
56 changes: 55 additions & 1 deletion packages/engine/Source/Scene/VoxelTraversal.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ function VoxelTraversal(
*/
this._binaryTreeKeyframeWeighting = new Array(keyframeCount);

/**
* @type {boolean}
* @private
*/
this._initialTilesLoaded = false;

const binaryTreeKeyframeWeighting = this._binaryTreeKeyframeWeighting;
binaryTreeKeyframeWeighting[0] = 0;
binaryTreeKeyframeWeighting[keyframeCount - 1] = 0;
Expand Down Expand Up @@ -316,13 +322,13 @@ VoxelTraversal.prototype.update = function (
const timestamp1 = getTimestamp();
generateOctree(this, sampleCount, levelBlendFactor);
const timestamp2 = getTimestamp();

if (this._debugPrint) {
const loadAndUnloadTimeMs = timestamp1 - timestamp0;
const generateOctreeTimeMs = timestamp2 - timestamp1;
const totalTimeMs = timestamp2 - timestamp0;
printDebugInformation(
this,
frameState,
loadAndUnloadTimeMs,
generateOctreeTimeMs,
totalTimeMs,
Expand Down Expand Up @@ -422,6 +428,7 @@ function requestData(that, keyframeNode) {
function postRequestSuccess(result) {
that._simultaneousRequestCount--;
const length = provider.types.length;
that._primitive.tileLoad.raiseEvent();

if (!defined(result)) {
keyframeNode.state = KeyframeNode.LoadState.UNAVAILABLE;
Expand Down Expand Up @@ -645,6 +652,7 @@ function loadAndUnload(that, frameState) {
destroyedCount++;

const discardNode = keyframeNodesInMegatexture[addNodeIndex];
that._primitive.tileUnload.raiseEvent();
discardNode.spatialNode.destroyKeyframeNode(
discardNode,
that.megatextures,
Expand Down Expand Up @@ -705,6 +713,7 @@ function keyframePriority(previousKeyframe, keyframe, nextKeyframe, traversal) {
*/
function printDebugInformation(
that,
frameState,
loadAndUnloadTimeMs,
generateOctreeTimeMs,
totalTimeMs,
Expand Down Expand Up @@ -758,6 +767,51 @@ function printDebugInformation(
}
traverseRecursive(rootNode);

const numberOfPendingRequests =
loadStateByCount[KeyframeNode.LoadState.RECEIVING];
const numberOfTilesProcessing =
loadStateByCount[KeyframeNode.LoadState.RECEIVED];

const progressChanged =
numberOfPendingRequests !==
that._primitive._statistics.numberOfPendingRequests ||
numberOfTilesProcessing !==
that._primitive._statistics.numberOfTilesProcessing;

if (progressChanged) {
frameState.afterRender.push(function () {
that._primitive.loadProgress.raiseEvent(
numberOfPendingRequests,
numberOfTilesProcessing,
);

return true;
});
}

that._primitive._statistics.numberOfPendingRequests = numberOfPendingRequests;
that._primitive._statistics.numberOfTilesProcessing = numberOfTilesProcessing;

const tilesLoaded =
numberOfPendingRequests === 0 && numberOfTilesProcessing === 0;

// Events are raised (added to the afterRender queue) here since promises
// may resolve outside of the update loop that then raise events, e.g.,
// model's readyEvent
if (progressChanged && tilesLoaded) {
frameState.afterRender.push(function () {
that._primitive.allTilesLoaded.raiseEvent();
return true;
});
if (!that._initialTilesLoaded) {
that._initialTilesLoaded = true;
frameState.afterRender.push(function () {
that._primitive.initialTilesLoaded.raiseEvent();
return true;
});
}
}

const loadedKeyframeStatistics = `KEYFRAMES: ${
loadStatesByKeyframe[KeyframeNode.LoadState.LOADED]
}`;
Expand Down
Loading