Skip to content

Commit

Permalink
Update VoxelContent from the update loop in VoxelTraversal
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeshurun Hembd committed Jan 23, 2025
1 parent 20ac82c commit 1b42873
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 82 deletions.
5 changes: 3 additions & 2 deletions Apps/Sandcastle/gallery/Voxel Picking.html
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
const { tileLevel, tileX, tileY, tileZ } = options;

if (tileLevel >= this._levelCount) {
return undefined;
return Promise.reject(`No tiles available beyond level ${this._levelCount}`);
}

const dimensions = this.dimensions;
Expand All @@ -83,7 +83,8 @@
tileZ * dimensions.y * dimensions.x + tileY * dimensions.x + tileX;
const dataTile = constructRandomTileData(dimensions, type, randomSeed);

return Promise.resolve([dataTile]);
const content = new Cesium.VoxelContent({ metadata: [dataTile] });
return Promise.resolve(content);
};

function constructRandomTileData(dimensions, type, randomSeed) {
Expand Down
12 changes: 8 additions & 4 deletions Apps/Sandcastle/gallery/Voxels.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@

ProceduralSingleTileVoxelProvider.prototype.requestData = function (options) {
if (options.tileLevel >= 1) {
return undefined;
return Promise.reject(`No tiles available beyond level 0`);
}

const dimensions = this.dimensions;
Expand Down Expand Up @@ -93,7 +93,8 @@
}
}

return Promise.resolve([dataColor]);
const content = new Cesium.VoxelContent({ metadata: [dataColor] });
return Promise.resolve(content);
};

function ProceduralMultiTileVoxelProvider(shape) {
Expand Down Expand Up @@ -143,7 +144,9 @@
const { tileLevel, tileX, tileY, tileZ } = options;

if (tileLevel >= this._levelCount) {
return undefined;
return Promise.reject(
`No tiles available beyond level ${this._levelCount - 1}`,
);
}

const type = this.types[0];
Expand Down Expand Up @@ -204,7 +207,8 @@
}
}
}
return Promise.resolve([dataTile]);
const content = new Cesium.VoxelContent({ metadata: [dataTile] });
return Promise.resolve(content);
};

function createPrimitive(provider, customShader, modelMatrix) {
Expand Down
3 changes: 1 addition & 2 deletions packages/engine/Source/Scene/Cesium3DTilesVoxelProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,6 @@ Cesium3DTilesVoxelProvider.prototype.requestData = async function (options) {
tileY = 0,
tileZ = 0,
keyframe = 0,
frameState,
} = options;

if (keyframe !== 0) {
Expand Down Expand Up @@ -547,7 +546,7 @@ Cesium3DTilesVoxelProvider.prototype.requestData = async function (options) {
url: gltfRelative.url,
});

return VoxelContent.fromGltf(gltfResource, this, frameState);
return VoxelContent.fromGltf(gltfResource);
};

export default Cesium3DTilesVoxelProvider;
2 changes: 1 addition & 1 deletion packages/engine/Source/Scene/KeyframeNode.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const LoadState = Object.freeze({
UNLOADED: 0, // Has no data and is in dormant state
RECEIVING: 1, // Is waiting on data from the provider
RECEIVED: 2, // Received data from the provider
PROCESSING: 2, // Data received. Contents are being processed for rendering. Depending on the content, it might make its own requests for external data.
LOADED: 3, // Processed data from provider
FAILED: 4, // Failed to receive data from the provider
UNAVAILABLE: 5, // No data available for this tile
Expand Down
11 changes: 6 additions & 5 deletions packages/engine/Source/Scene/VoxelCell.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ VoxelCell.fromKeyframeNode = function (
//>>includeEnd('debug');

const voxelCell = new VoxelCell(primitive, tileIndex, sampleIndex);
const { spatialNode, metadata } = keyframeNode;
voxelCell._metadata = getMetadataForSample(primitive, metadata, sampleIndex);
const { spatialNode, content } = keyframeNode;
voxelCell._metadata = getMetadataForSample(primitive, content, sampleIndex);
voxelCell._orientedBoundingBox = getOrientedBoundingBox(
primitive,
spatialNode,
Expand All @@ -85,15 +85,16 @@ VoxelCell.fromKeyframeNode = function (
/**
* @private
* @param {VoxelPrimitive} primitive
* @param {object} metadata
* @param {VoxelContent} content
* @param {number} sampleIndex
* @returns {object}
*/
function getMetadataForSample(primitive, metadata, sampleIndex) {
if (!defined(metadata)) {
function getMetadataForSample(primitive, content, sampleIndex) {
if (!defined(content) || !defined(content.metadata)) {
return undefined;
}
const { names, types } = primitive.provider;
const { metadata } = content;
const metadataMap = {};
for (let i = 0; i < names.length; i++) {
const name = names[i];
Expand Down
18 changes: 4 additions & 14 deletions packages/engine/Source/Scene/VoxelContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import MetadataType from "./MetadataType.js";
* @exception {DeveloperError} One of loader and metadata must be defined.
* @exception {DeveloperError} metadata must be an array of TypedArrays.
*
* @private
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function VoxelContent(options) {
Expand Down Expand Up @@ -83,7 +82,7 @@ Object.defineProperties(VoxelContent.prototype, {
},
});

VoxelContent.fromGltf = async function (resource, provider, frameState) {
VoxelContent.fromGltf = async function (resource) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("resource", resource);
//>>includeEnd('debug');
Expand All @@ -105,16 +104,7 @@ VoxelContent.fromGltf = async function (resource, provider, frameState) {
throw error;
}

await loader.load();
loader.process(frameState);
await loader._loadResourcesPromise;
loader.process(frameState);

const metadata = processAttributes(
loader.components.scene.nodes[0].primitives[0].attributes,
provider,
);
return new VoxelContent({ resource, loader, metadata });
return new VoxelContent({ resource, loader });
};

/**
Expand Down Expand Up @@ -159,10 +149,10 @@ VoxelContent.prototype.update = function (primitive, frameState) {
* @returns {TypedArray[]} An array of typed arrays containing the attribute values
* @private
*/
function processAttributes(attributes, provider) {
function processAttributes(attributes, primitive) {
//function processAttributes(attributes, primitive) {
//const { names, types, componentTypes } = primitive.provider;
const { names, types, componentTypes } = provider;
const { names, types, componentTypes } = primitive.provider;
const data = new Array(attributes.length);

for (let i = 0; i < attributes.length; i++) {
Expand Down
82 changes: 48 additions & 34 deletions packages/engine/Source/Scene/VoxelTraversal.js
Original file line number Diff line number Diff line change
Expand Up @@ -413,11 +413,10 @@ function recomputeBoundingVolumesRecursive(that, node) {
*
* @param {VoxelTraversal} that
* @param {KeyframeNode} keyframeNode
* @param {FrameState} frameState
*
* @private
*/
function requestData(that, keyframeNode, frameState) {
function requestData(that, keyframeNode) {
if (
that._simultaneousRequestCount >=
VoxelTraversal.simultaneousRequestCountMaximum
Expand All @@ -430,34 +429,10 @@ function requestData(that, keyframeNode, frameState) {

function postRequestSuccess(result) {
that._simultaneousRequestCount--;
const length = provider.types.length;

if (!defined(result)) {
keyframeNode.state = KeyframeNode.LoadState.UNAVAILABLE;
//} else if (!Array.isArray(result) || result.length !== length) {
// TODO should this throw runtime error?
// TODO what if result is a VoxelContent? How do we check the metadata?
// keyframeNode.state = KeyframeNode.LoadState.FAILED;
} else {
const megatextures = that.megatextures;
keyframeNode.content = result;
keyframeNode.state = KeyframeNode.LoadState.RECEIVED;
const { metadata } = result;
for (let i = 0; i < length; i++) {
const { voxelCountPerTile, channelCount } = megatextures[i];
const { x, y, z } = voxelCountPerTile;
const tileVoxelCount = x * y * z;

const data = metadata[i];
const expectedLength = tileVoxelCount * channelCount;
if (data.length !== expectedLength) {
// State is received only when all metadata requests have been received
keyframeNode.state = KeyframeNode.LoadState.FAILED;
keyframeNode.content = undefined;
break;
}
}
}
keyframeNode.content = result;
keyframeNode.state = defined(result)
? KeyframeNode.LoadState.PROCESSING
: KeyframeNode.LoadState.UNAVAILABLE;
}

function postRequestFailure(error) {
Expand All @@ -472,7 +447,6 @@ function requestData(that, keyframeNode, frameState) {
tileY: spatialNode.y,
tileZ: spatialNode.z,
keyframe: keyframe,
frameState: frameState,
};
that._simultaneousRequestCount++;
keyframeNode.state = KeyframeNode.LoadState.RECEIVING;
Expand Down Expand Up @@ -567,9 +541,20 @@ function updateKeyframeNodes(that, frameState) {
continue;
}
if (highPriorityKeyframeNode.state === KeyframeNode.LoadState.UNLOADED) {
requestData(that, highPriorityKeyframeNode, frameState);
requestData(that, highPriorityKeyframeNode);
}
if (highPriorityKeyframeNode.state === KeyframeNode.LoadState.RECEIVED) {
if (highPriorityKeyframeNode.state === KeyframeNode.LoadState.PROCESSING) {
const { content } = highPriorityKeyframeNode;
content.update(that._primitive, frameState);
if (!content.ready) {
continue;
}
if (!validateMetadata(content.metadata, that)) {
// TODO should this throw runtime error?
highPriorityKeyframeNode.content = undefined;
highPriorityKeyframeNode.state = KeyframeNode.LoadState.FAILED;
continue;
}
let addNodeIndex = 0;
if (megatexture.isFull()) {
// If the megatexture is full, try removing a discardable node with the lowest priority.
Expand Down Expand Up @@ -602,6 +587,35 @@ function keyframeNodeSort(a, b) {
return b.highPriorityFrameNumber - a.highPriorityFrameNumber;
}

/**
* Check if an array of metadata is of the expected type and size
*
* @param {TypedArray[]} metadata The metadata to validate
* @param {VoxelTraversal} traversal The traversal to validate against
* @returns {boolean} <code>true</code> if the metadata is valid, <code>false</code> otherwise
*
* @private
*/
function validateMetadata(metadata, traversal) {
const length = traversal._primitive.provider.types.length;
if (!Array.isArray(metadata) || metadata.length !== length) {
return false;
}
const { megatextures } = traversal;
for (let i = 0; i < length; i++) {
const { voxelCountPerTile, channelCount } = megatextures[i];
const { x, y, z } = voxelCountPerTile;
const tileVoxelCount = x * y * z;

const data = metadata[i];
const expectedLength = tileVoxelCount * channelCount;
if (data.length !== expectedLength) {
return false;
}
}
return true;
}

/**
* @param {SpatialNode} spatialNode
* @param {number} visibilityPlaneMask
Expand Down Expand Up @@ -794,7 +808,7 @@ function printDebugInformation(
const loadStateStatistics =
`UNLOADED: ${loadStateByCount[KeyframeNode.LoadState.UNLOADED]} | ` +
`RECEIVING: ${loadStateByCount[KeyframeNode.LoadState.RECEIVING]} | ` +
`RECEIVED: ${loadStateByCount[KeyframeNode.LoadState.RECEIVED]} | ` +
`PROCESSING: ${loadStateByCount[KeyframeNode.LoadState.PROCESSING]} | ` +
`LOADED: ${loadStateByCount[KeyframeNode.LoadState.LOADED]} | ` +
`FAILED: ${loadStateByCount[KeyframeNode.LoadState.FAILED]} | ` +
`UNAVAILABLE: ${loadStateByCount[KeyframeNode.LoadState.UNAVAILABLE]} | ` +
Expand Down
Loading

0 comments on commit 1b42873

Please sign in to comment.