Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into allow-external-tilese…
Browse files Browse the repository at this point in the history
…ts-in-multiple-contents
  • Loading branch information
javagl committed Jan 29, 2025
2 parents b1d4ecb + 4e6dde5 commit 92113d8
Show file tree
Hide file tree
Showing 8 changed files with 274 additions and 16 deletions.
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
- Fixed type of `ImageryLayer.fromProviderAsync`, to correctly show that the param `options` is optional. [#12400](https://github.com/CesiumGS/cesium/pull/12400)
- Fixed Draco decoding for vertex colors that are normalized `UNSIGNED_BYTE` or `UNSIGNED_SHORT`. [#12417](https://github.com/CesiumGS/cesium/pull/12417)
- Fixed type error when setting `Viewer.selectedEntity` [#12303](https://github.com/CesiumGS/cesium/issues/12303)
- Fixed urls with https in the documentation `basemap.nationalmap.gov` [#12375](https://github.com/CesiumGS/cesium/issues/12375)
- Fixed error in polyline when sinAngle is < 1. the value of expandWidth was too much. [#12434](https://github.com/CesiumGS/cesium/pull/12434)

## 1.125 - 2025-01-02

Expand All @@ -24,6 +26,7 @@

- Expanded integration with the [iTwin Platform](https://developer.bentley.com/) to load GeoJSON and KML data from the Reality Management API. Use `ITwinData.createDataSourceForRealityDataId` to load data as either GeoJSON or KML`. [#12344](https://github.com/CesiumGS/cesium/pull/12344)
- Added `environmentMapOptions` to `ModelGraphics`. For performance reasons by default, the environment map will not update if the entity position change. If environment map updates based on entity position are desired, provide an appropriate `environmentMapOptions.maximumPositionEpsilon` value. [#12358](https://github.com/CesiumGS/cesium/pull/12358)
- Added events to `VoxelPrimitive` to match `Cesium3DTileset`, including `allTilesLoaded`, `initialTilesLoaded`, `loadProgress`, `tileFailed`, `tileLoad`, `tileVisible`, `tileUnload`.

#### Fixes :wrench:

Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -422,3 +422,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu
- [Isaac Young](https://github.com/ibreathebsb)
- [Nick Crews](https://github.com/NickCrews)
- [胡文康](https://github.com/XiaoHu1994)
- [Parth Petkar](https://github.com/parthpetkar)
124 changes: 124 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,123 @@ function VoxelPrimitive(options) {
}
}

/**
* The event fired to indicate that a tile's content was loaded.
* <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}
*
* @example
* voxelPrimitive.tileLoad.addEventListener(function() {
* console.log('A tile was loaded.');
* });
*/
this.tileLoad = new Event();

/**
* This event fires once for each visible tile in a frame.
* <p>
* This event is fired during the traversal while the frame is being rendered.
*
* @type {Event}
*
* @example
* voxelPrimitive.tileVisible.addEventListener(function() {
* console.log('A tile is visible.');
* });
*
*/
this.tileVisible = new Event();

/**
* The event fired to indicate that a tile's content failed to load.
*
* @type {Event}
*
* @example
* voxelPrimitive.tileFailed.addEventListener(function() {
* console.log('An error occurred loading tile.');
* });
*/
this.tileFailed = new Event();

/**
* The event fired to indicate that a tile's content was unloaded.
*
* @type {Event}
*
* @example
* voxelPrimitive.tileUnload.addEventListener(function() {
* 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}
*
* @example
* voxelPrimitive.loadProgress.addEventListener(function(numberOfPendingRequests, numberOfTilesProcessing) {
* if ((numberOfPendingRequests === 0) && (numberOfTilesProcessing === 0)) {
* console.log('Finished 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}
*
* @example
* voxelPrimitive.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}
*
* @example
* voxelPrimitive.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
97 changes: 85 additions & 12 deletions 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,17 @@ VoxelTraversal.prototype.update = function (
const timestamp1 = getTimestamp();
generateOctree(this, sampleCount, levelBlendFactor);
const timestamp2 = getTimestamp();

if (this._debugPrint) {
const checkEventListeners =
primitive.loadProgress.numberOfListeners > 0 ||
primitive.allTilesLoaded.numberOfListeners > 0 ||
primitive.initialTilesLoaded.numberOfListeners > 0;
if (this._debugPrint || checkEventListeners) {
const loadAndUnloadTimeMs = timestamp1 - timestamp0;
const generateOctreeTimeMs = timestamp2 - timestamp1;
const totalTimeMs = timestamp2 - timestamp0;
printDebugInformation(
postPassesUpdate(
this,
frameState,
loadAndUnloadTimeMs,
generateOctreeTimeMs,
totalTimeMs,
Expand Down Expand Up @@ -418,6 +428,18 @@ function requestData(that, keyframeNode) {
}

const provider = that._primitive._provider;
const { keyframe, spatialNode } = keyframeNode;
if (spatialNode.level >= provider._implicitTileset.availableLevels) {
return;
}

const requestOptions = {
tileLevel: spatialNode.level,
tileX: spatialNode.x,
tileY: spatialNode.y,
tileZ: spatialNode.z,
keyframe: keyframe,
};

function postRequestSuccess(result) {
that._simultaneousRequestCount--;
Expand All @@ -443,34 +465,33 @@ function requestData(that, keyframeNode) {
keyframeNode.metadata[i] = data;
// State is received only when all metadata requests have been received
keyframeNode.state = KeyframeNode.LoadState.RECEIVED;
that._primitive.tileLoad.raiseEvent();
} else {
keyframeNode.state = KeyframeNode.LoadState.FAILED;
break;
}
}
}
if (keyframeNode.state === KeyframeNode.LoadState.FAILED) {
that._primitive.tileFailed.raiseEvent();
}
}

function postRequestFailure() {
that._simultaneousRequestCount--;
keyframeNode.state = KeyframeNode.LoadState.FAILED;
that._primitive.tileFailed.raiseEvent();
}

const { keyframe, spatialNode } = keyframeNode;
const promise = provider.requestData({
tileLevel: spatialNode.level,
tileX: spatialNode.x,
tileY: spatialNode.y,
tileZ: spatialNode.z,
keyframe: keyframe,
});
const promise = provider.requestData(requestOptions);

if (defined(promise)) {
that._simultaneousRequestCount++;
keyframeNode.state = KeyframeNode.LoadState.RECEIVING;
promise.then(postRequestSuccess).catch(postRequestFailure);
} else {
keyframeNode.state = KeyframeNode.LoadState.FAILED;
that._primitive.tileFailed.raiseEvent();
}
}

Expand Down Expand Up @@ -645,6 +666,7 @@ function loadAndUnload(that, frameState) {
destroyedCount++;

const discardNode = keyframeNodesInMegatexture[addNodeIndex];
that._primitive.tileUnload.raiseEvent();
discardNode.spatialNode.destroyKeyframeNode(
discardNode,
that.megatextures,
Expand Down Expand Up @@ -703,8 +725,9 @@ function keyframePriority(previousKeyframe, keyframe, nextKeyframe, traversal) {
*
* @private
*/
function printDebugInformation(
function postPassesUpdate(
that,
frameState,
loadAndUnloadTimeMs,
generateOctreeTimeMs,
totalTimeMs,
Expand Down Expand Up @@ -758,6 +781,55 @@ 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;
});
}
}

if (!that._debugPrint) {
return;
}

const loadedKeyframeStatistics = `KEYFRAMES: ${
loadStatesByKeyframe[KeyframeNode.LoadState.LOADED]
}`;
Expand Down Expand Up @@ -892,6 +964,7 @@ function generateOctree(that, sampleCount, levelBlendFactor) {
} else {
// Store the leaf node information instead
// Recursion stops here because there are no renderable children
that._primitive.tileVisible.raiseEvent();
if (useLeafNodes) {
const baseIdx = leafNodeCount * 5;
const keyframeNode = node.renderableKeyframeNodePrevious;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const defaultParameters = Object.freeze({
* @example
* // Example 1. USGS shaded relief tiles (KVP)
* const shadedRelief1 = new Cesium.WebMapTileServiceImageryProvider({
* url : 'http://basemap.nationalmap.gov/arcgis/rest/services/USGSShadedReliefOnly/MapServer/WMTS',
* url : 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSShadedReliefOnly/MapServer/WMTS',
* layer : 'USGSShadedReliefOnly',
* style : 'default',
* format : 'image/jpeg',
Expand All @@ -71,7 +71,7 @@ const defaultParameters = Object.freeze({
* @example
* // Example 2. USGS shaded relief tiles (RESTful)
* const shadedRelief2 = new Cesium.WebMapTileServiceImageryProvider({
* url : 'http://basemap.nationalmap.gov/arcgis/rest/services/USGSShadedReliefOnly/MapServer/WMTS/tile/1.0.0/USGSShadedReliefOnly/{Style}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.jpg',
* url : 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSShadedReliefOnly/MapServer/WMTS/tile/1.0.0/USGSShadedReliefOnly/{Style}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.jpg',
* layer : 'USGSShadedReliefOnly',
* style : 'default',
* format : 'image/jpeg',
Expand Down
2 changes: 1 addition & 1 deletion packages/engine/Source/Shaders/PolylineCommon.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ vec4 getPolylineWindowCoordinatesEC(vec4 positionEC, vec4 prevEC, vec4 nextEC, f
vec2 u = -thisSegmentForwardWC;
vec2 v = leftWC;
float sinAngle = abs(u.x * v.y - u.y * v.x);
expandWidth = clamp(expandWidth / sinAngle, 0.0, width * 2.0);
expandWidth = clamp(expandWidth / sinAngle, 0.0, width * 0.5);
}

vec2 offset = leftWC * expandDirection * expandWidth * czm_pixelRatio;
Expand Down
Loading

0 comments on commit 92113d8

Please sign in to comment.