From eb4ec2036bf267d064dd68be1afcff7eff55046b Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Tue, 17 Sep 2024 17:01:41 +0200
Subject: [PATCH 01/38] First, partial support of GPM classes
---
packages/engine/Source/Scene/GltfGpmLoader.js | 469 ++++++++++++++++++
.../Model/Extensions/Gpm/AnchorPointDirect.js | 50 ++
.../Extensions/Gpm/AnchorPointIndirect.js | 66 +++
.../Model/Extensions/Gpm/CorrelationGroup.js | 67 +++
.../Model/Extensions/Gpm/GltfGpmLocal.js | 145 ++++++
.../Extensions/Gpm/MeshPrimitiveGpmLocal.js | 27 +
.../Scene/Model/Extensions/Gpm/PpeMetadata.js | 67 +++
.../Scene/Model/Extensions/Gpm/PpeSource.js | 72 +++
.../Scene/Model/Extensions/Gpm/PpeTexture.js | 115 +++++
.../Scene/Model/Extensions/Gpm/Spdcf.js | 87 ++++
.../Scene/Model/Extensions/Gpm/StorageType.js | 27 +
11 files changed, 1192 insertions(+)
create mode 100644 packages/engine/Source/Scene/GltfGpmLoader.js
create mode 100644 packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js
create mode 100644 packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js
create mode 100644 packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js
create mode 100644 packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js
create mode 100644 packages/engine/Source/Scene/Model/Extensions/Gpm/MeshPrimitiveGpmLocal.js
create mode 100644 packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
create mode 100644 packages/engine/Source/Scene/Model/Extensions/Gpm/PpeSource.js
create mode 100644 packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
create mode 100644 packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js
create mode 100644 packages/engine/Source/Scene/Model/Extensions/Gpm/StorageType.js
diff --git a/packages/engine/Source/Scene/GltfGpmLoader.js b/packages/engine/Source/Scene/GltfGpmLoader.js
new file mode 100644
index 000000000000..b3463abb8054
--- /dev/null
+++ b/packages/engine/Source/Scene/GltfGpmLoader.js
@@ -0,0 +1,469 @@
+import Check from "../Core/Check.js";
+import defaultValue from "../Core/defaultValue.js";
+import defined from "../Core/defined.js";
+import ResourceCache from "./ResourceCache.js";
+import ResourceLoader from "./ResourceLoader.js";
+import ResourceLoaderState from "./ResourceLoaderState.js";
+import PropertyTexture from "./PropertyTexture.js";
+import StructuralMetadata from "./StructuralMetadata.js";
+import MetadataSchema from "./MetadataSchema.js";
+
+/**
+ * Loads glTF NGA_gpm_local
+ *
+ * Implements the {@link ResourceLoader} interface.
+ *
+ * Implementation note: This is an experimental implementation. It is based
+ * on a GltfStructuralMetadataLoader, by removing everything that is not
+ * related to property textures, and translating the "ppeTextures" of
+ * the NGA_gpm_local extension into property textures. These will be
+ * returned as part of a `StructuralMetadata` object, which may override
+ * any `StructuralMetadata` that was read directly from the glTF.
+ *
+ * @alias GltfGpmLoader
+ * @constructor
+ * @augments ResourceLoader
+ *
+ * @param {object} options Object with the following properties:
+ * @param {object} options.gltf The glTF JSON.
+ * @param {string} [options.extension] The NGA_gpm_local
extension object.
+ * @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
+ * @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
+ * @param {SupportedImageFormats} options.supportedImageFormats The supported image formats.
+ * @param {FrameState} options.frameState The frame state.
+ * @param {string} [options.cacheKey] The cache key of the resource.
+ * @param {boolean} [options.asynchronous=true] Determines if WebGL resource creation will be spread out over several frames or block until all WebGL resources are created.
+ *
+ * @private
+ * @experimental This feature is subject to change without Cesium's standard deprecation policy.
+ */
+function GltfGpmLoader(options) {
+ options = defaultValue(options, defaultValue.EMPTY_OBJECT);
+ const gltf = options.gltf;
+ const extension = options.extension;
+ const gltfResource = options.gltfResource;
+ const baseResource = options.baseResource;
+ const supportedImageFormats = options.supportedImageFormats;
+ const frameState = options.frameState;
+ const cacheKey = options.cacheKey;
+ const asynchronous = defaultValue(options.asynchronous, true);
+
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.object("options.gltf", gltf);
+ Check.typeOf.object("options.extension", extension);
+ Check.typeOf.object("options.gltfResource", gltfResource);
+ Check.typeOf.object("options.baseResource", baseResource);
+ Check.typeOf.object("options.supportedImageFormats", supportedImageFormats);
+ Check.typeOf.object("options.frameState", frameState);
+ //>>includeEnd('debug');
+
+ this._gltfResource = gltfResource;
+ this._baseResource = baseResource;
+ this._gltf = gltf;
+ this._extension = extension;
+ this._supportedImageFormats = supportedImageFormats;
+ this._frameState = frameState;
+ this._cacheKey = cacheKey;
+ this._asynchronous = asynchronous;
+ this._textureLoaders = [];
+ this._textureIds = [];
+ this._structuralMetadata = undefined;
+ this._state = ResourceLoaderState.UNLOADED;
+ this._promise = undefined;
+}
+
+if (defined(Object.create)) {
+ GltfGpmLoader.prototype = Object.create(ResourceLoader.prototype);
+ GltfGpmLoader.prototype.constructor = GltfGpmLoader;
+}
+
+Object.defineProperties(GltfGpmLoader.prototype, {
+ /**
+ * The cache key of the resource.
+ *
+ * @memberof GltfGpmLoader.prototype
+ *
+ * @type {string}
+ * @readonly
+ * @private
+ */
+ cacheKey: {
+ get: function () {
+ return this._cacheKey;
+ },
+ },
+ /**
+ * The parsed structural metadata
+ *
+ * @memberof GltfGpmLoader.prototype
+ *
+ * @type {StructuralMetadata}
+ * @readonly
+ * @private
+ */
+ structuralMetadata: {
+ get: function () {
+ return this._structuralMetadata;
+ },
+ },
+});
+
+async function loadResources(loader) {
+ try {
+ const texturesPromise = loadTextures(loader);
+ await texturesPromise;
+
+ if (loader.isDestroyed()) {
+ return;
+ }
+
+ loader._gltf = undefined; // No longer need to hold onto the glTF
+
+ loader._state = ResourceLoaderState.LOADED;
+ return loader;
+ } catch (error) {
+ if (loader.isDestroyed()) {
+ return;
+ }
+
+ loader.unload();
+ loader._state = ResourceLoaderState.FAILED;
+ const errorMessage = "Failed to load GPM data";
+ throw loader.getError(errorMessage, error);
+ }
+}
+
+/**
+ * Loads the resource.
+ * @returns {Promise} A promise which resolves to the loader when the resource loading is completed.
+ * @private
+ */
+GltfGpmLoader.prototype.load = function () {
+ if (defined(this._promise)) {
+ return this._promise;
+ }
+
+ this._state = ResourceLoaderState.LOADING;
+ this._promise = loadResources(this);
+ return this._promise;
+};
+
+function gatherUsedTextureIds(gpmExtension) {
+ // Gather the used textures
+ const textureIds = {};
+ const ppeTextures = gpmExtension.ppeTextures;
+ if (defined(ppeTextures)) {
+ for (let i = 0; i < ppeTextures.length; i++) {
+ const ppeTexture = ppeTextures[i];
+ // The texture is a valid textureInfo.
+ textureIds[ppeTexture.index] = ppeTexture;
+ }
+ }
+ return textureIds;
+}
+
+function loadTextures(gpmLoader) {
+ let textureIds;
+ if (defined(gpmLoader._extension)) {
+ textureIds = gatherUsedTextureIds(gpmLoader._extension);
+ }
+
+ const gltf = gpmLoader._gltf;
+ const gltfResource = gpmLoader._gltfResource;
+ const baseResource = gpmLoader._baseResource;
+ const supportedImageFormats = gpmLoader._supportedImageFormats;
+ const frameState = gpmLoader._frameState;
+ const asynchronous = gpmLoader._asynchronous;
+
+ // Load the textures
+ const texturePromises = [];
+ for (const textureId in textureIds) {
+ if (textureIds.hasOwnProperty(textureId)) {
+ const textureLoader = ResourceCache.getTextureLoader({
+ gltf: gltf,
+ textureInfo: textureIds[textureId],
+ gltfResource: gltfResource,
+ baseResource: baseResource,
+ supportedImageFormats: supportedImageFormats,
+ frameState: frameState,
+ asynchronous: asynchronous,
+ });
+ gpmLoader._textureLoaders.push(textureLoader);
+ gpmLoader._textureIds.push(textureId);
+ texturePromises.push(textureLoader.load());
+ }
+ }
+
+ return Promise.all(texturePromises);
+}
+
+/**
+ * A static mapping from PPE texture property identifier keys
+ * to `MetadataSchema` instances. This is used to create each
+ * schema (with a certain structure) only ONCE in
+ * obtainPpeTexturesMetadataSchema
+ *
+ * @private
+ */
+GltfGpmLoader.ppeTexturesMetadataSchemaCache = new Map();
+
+/**
+ * Create the JSON description of a metadata class that treats
+ * the given PPE texture as a property texture property(!).
+ *
+ * @param {any} ppeTexture - The PPE texture
+ * @param {number} index - The index of the texture in the extension
+ * @returns The class JSON
+ */
+GltfGpmLoader.prototype.createPpeTextureClassJson = function (
+ ppeTexture,
+ index
+) {
+ const traits = ppeTexture.traits;
+ const ppePropertyName = traits.source;
+
+ // XXX_UNCERTAINTY: The ppeTexture will have a structure
+ // like this:
+ //
+ //"ppeTextures" : [
+ // {
+ // "traits" : {
+ // "source" : "SIGZ",
+ // "min" : 0.0,
+ // "max" : 16.0
+ // },
+ // "index" : 2,
+ // "noData" : 255,
+ // "offset" : 0.0,
+ // "scale" : 0.06274509803921569,
+ // "texCoord" : 1
+ // },
+ //
+ // Note that in GPM 1.2d, the min/max should be part of the
+ // texture, but in the actual data (GPM 1.2i), they are in
+ // the traits (ppeMetadata). And there, they/ seem to denote
+ // the min/max values that actually appear in the texture.
+ // So they are integrated into the 'scale' factor here:
+ const min = traits.min ?? 0;
+ const max = traits.max ?? 255;
+ const minMaxScale = 255.0 / (max - min);
+ const offset = ppeTexture.offset;
+ const scale = ppeTexture.scale * minMaxScale;
+ const classJson = {
+ name: `PPE texture class ${index}`,
+ properties: {
+ [ppePropertyName]: {
+ name: "PPE",
+ type: "SCALAR",
+ componentType: "UINT8",
+ normalized: true,
+ offset: offset,
+ scale: scale,
+ },
+ },
+ };
+ return classJson;
+};
+
+/**
+ * Returns the `MetadataSchema` for the PPE textures in this instance.
+ *
+ * This method will return a (statically/globally) cached metadata
+ * schema that reflects the structure of the PPE textures in this
+ * instance, creating and caching it if necessary.
+ *
+ * For details on the cache key, see `collectPpeTexturePropertyIdentifiers`
+ *
+ * @returns The `MetadataSchema`
+ */
+GltfGpmLoader.prototype.obtainPpeTexturesMetadataSchema = function () {
+ const ppeTexturePropertyIdentifiers = this.collectPpeTexturePropertyIdentifiers();
+ const key = ppeTexturePropertyIdentifiers.toString();
+ let ppeTexturesMetadataSchema = GltfGpmLoader.ppeTexturesMetadataSchemaCache.get(
+ key
+ );
+ if (defined(ppeTexturesMetadataSchema)) {
+ // XXX_UNCERTAINTY Debug log
+ //console.log(`Using cached schema for GPM PPE textures with key ${key}`);
+ return ppeTexturesMetadataSchema;
+ }
+
+ // XXX_UNCERTAINTY Debug log - if caching works, this should be printed only ONCE!
+ console.log(`Creating schema for GPM PPE textures with key ${key}`);
+ const schemaId = `PPE_TEXTURE_SCHEMA_${GltfGpmLoader.ppeTexturesMetadataSchemaCache.size}`;
+ const ppeTexturesMetadataSchemaJson = {
+ id: schemaId,
+ classes: {},
+ };
+
+ const extension = this._extension;
+ if (defined(extension.ppeTextures)) {
+ for (let i = 0; i < extension.ppeTextures.length; i++) {
+ const ppeTexture = extension.ppeTextures[i];
+ const classId = `ppeTexture_${i}`;
+ const classJson = this.createPpeTextureClassJson(ppeTexture, i);
+ ppeTexturesMetadataSchemaJson.classes[classId] = classJson;
+ }
+ }
+
+ ppeTexturesMetadataSchema = MetadataSchema.fromJson(
+ ppeTexturesMetadataSchemaJson
+ );
+ GltfGpmLoader.ppeTexturesMetadataSchemaCache.set(
+ key,
+ ppeTexturesMetadataSchema
+ );
+ return ppeTexturesMetadataSchema;
+};
+
+/**
+ * Creates an array of strings that serve as identifiers for PPE textures.
+ *
+ * Each glTF may define multiple `ppeTexture` objects within the
+ * `NGA_gpm_local` extensions. Each of these textures corresponds
+ * to one 'property texture property(!)' in a metadata schema.
+ *
+ * This method will create an array where each element is a (JSON)
+ * string representation of the parts of a GPM PPE texture definition
+ * that are relevant for distinguishing two PPE textures in terms
+ * of their structure within a `StructuralMetadata`.
+ *
+ * @returns The identifiers
+ */
+GltfGpmLoader.prototype.collectPpeTexturePropertyIdentifiers = function () {
+ const extension = this._extension;
+ const ppeTexturePropertyIdentifiers = [];
+ if (defined(extension.ppeTextures)) {
+ for (let i = 0; i < extension.ppeTextures.length; i++) {
+ const ppeTexture = extension.ppeTextures[i];
+ // The following will create an identifier that can be used
+ // to define two PPE textures as "representing the same
+ // property texture property" within a structural metadata
+ // schema.
+ const classJson = this.createPpeTextureClassJson(ppeTexture, i);
+ const ppeTexturePropertyIdentifier = JSON.stringify(classJson);
+ ppeTexturePropertyIdentifiers.push(ppeTexturePropertyIdentifier);
+ }
+ }
+ return ppeTexturePropertyIdentifiers;
+};
+
+/**
+ * Processes the resource until it becomes ready.
+ *
+ * @param {FrameState} frameState The frame state.
+ * @private
+ */
+GltfGpmLoader.prototype.process = function (frameState) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.object("frameState", frameState);
+ //>>includeEnd('debug');
+
+ if (this._state === ResourceLoaderState.READY) {
+ return true;
+ }
+
+ if (this._state !== ResourceLoaderState.LOADED) {
+ return false;
+ }
+
+ const textureLoaders = this._textureLoaders;
+ const textureLoadersLength = textureLoaders.length;
+ let ready = true;
+ for (let i = 0; i < textureLoadersLength; ++i) {
+ const textureLoader = textureLoaders[i];
+ const textureReady = textureLoader.process(frameState);
+ ready = ready && textureReady;
+ }
+
+ if (!ready) {
+ return false;
+ }
+
+ const textures = {};
+ for (let i = 0; i < this._textureIds.length; ++i) {
+ const textureId = this._textureIds[i];
+ const textureLoader = textureLoaders[i];
+ if (!textureLoader.isDestroyed()) {
+ textures[textureId] = textureLoader.texture;
+ }
+ }
+
+ const ppeTexturesMetadataSchema = this.obtainPpeTexturesMetadataSchema();
+ const extension = this._extension;
+ const propertyTextures = [];
+ if (defined(extension.ppeTextures)) {
+ for (let i = 0; i < extension.ppeTextures.length; i++) {
+ const ppeTexture = extension.ppeTextures[i];
+ const classId = `ppeTexture_${i}`;
+ const traits = ppeTexture.traits;
+ const ppePropertyName = traits.source;
+ const metadataClass = ppeTexturesMetadataSchema.classes[classId];
+
+ // XXX_UNCERTAINTY Debug log
+ //console.log(
+ // `Creating property texture with class ${classId} and property ${ppePropertyName}`
+ //);
+
+ const ppeTextureAsPropertyTexture = {
+ class: classId,
+ properties: {
+ [ppePropertyName]: {
+ index: ppeTexture.index,
+ texCoord: ppeTexture.texCoord,
+ },
+ },
+ };
+ propertyTextures.push(
+ new PropertyTexture({
+ id: i,
+ name: ppeTexture.name,
+ propertyTexture: ppeTextureAsPropertyTexture,
+ class: metadataClass,
+ textures: textures,
+ })
+ );
+ }
+ }
+
+ const structuralMetadata = new StructuralMetadata({
+ schema: ppeTexturesMetadataSchema,
+ propertyTables: [],
+ propertyTextures: propertyTextures,
+ propertyAttributes: [],
+ statistics: extension.statistics,
+ extras: extension.extras,
+ extensions: extension.extensions,
+ });
+ this._structuralMetadata = structuralMetadata;
+
+ this._state = ResourceLoaderState.READY;
+ return true;
+};
+
+function unloadTextures(gpmLoader) {
+ const textureLoaders = gpmLoader._textureLoaders;
+ const textureLoadersLength = textureLoaders.length;
+ for (let i = 0; i < textureLoadersLength; ++i) {
+ ResourceCache.unload(textureLoaders[i]);
+ }
+ gpmLoader._textureLoaders.length = 0;
+ gpmLoader._textureIds.length = 0;
+}
+
+/**
+ * Unloads the resource.
+ * @private
+ */
+GltfGpmLoader.prototype.unload = function () {
+ unloadTextures(this);
+
+ if (defined(this._schemaLoader)) {
+ ResourceCache.unload(this._schemaLoader);
+ }
+ this._schemaLoader = undefined;
+
+ this._structuralMetadata = undefined;
+};
+
+export default GltfGpmLoader;
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js
new file mode 100644
index 000000000000..79e71895214a
--- /dev/null
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js
@@ -0,0 +1,50 @@
+import Check from "../Core/Check.js";
+
+/**
+ * Metadata for one stored anchor point using direct storage
+ *
+ * @private
+ * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
+ */
+function AnchorPointDirect(options) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.object("options.position", options.property);
+ Check.typeOf.object("options.adjustmentParams", options.adjustmentParams);
+ //>>includeEnd('debug');
+
+ this._position = options.position;
+ this._adjustmentParams = options.adjustmentParams;
+}
+
+Object.defineProperties(AnchorPointDirect.prototype, {
+ /**
+ * Anchor point geographic coordinates in meters as X/Easting, Y/Northing, Z/HAE
+ *
+ * @memberof AnchorPointDirect.prototype
+ * @type {Cartesian3}
+ * @readonly
+ * @private
+ */
+ position: {
+ get: function () {
+ return this._position;
+ },
+ },
+
+ /**
+ * The delta-x delta-y delta-z adjustment values in meters per anchor
+ * point.
+ *
+ * @memberof AnchorPointDirect.prototype
+ * @type {Cartesian3}
+ * @readonly
+ * @private
+ */
+ adjustmentParams: {
+ get: function () {
+ return this._adjustmentParams;
+ },
+ },
+});
+
+export default AnchorPointDirect;
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js
new file mode 100644
index 000000000000..c70996f33485
--- /dev/null
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js
@@ -0,0 +1,66 @@
+import Check from "../Core/Check.js";
+
+/**
+ * Metadata for one stored anchor point.
+ *
+ * @private
+ * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
+ */
+function AnchorPointIndirect(options) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.object("options.position", options.property);
+ Check.typeOf.object("options.adjustmentParams", options.adjustmentParams);
+ Check.typeOf.object("options.covarianceMatrix", options.covarianceMatrix);
+ //>>includeEnd('debug');
+
+ this._position = options.position;
+ this._adjustmentParams = options.adjustmentParams;
+ this._covarianceMatrix = options.covarianceMatrix;
+}
+
+Object.defineProperties(AnchorPointIndirect.prototype, {
+ /**
+ * Anchor point geographic coordinates in meters as X/Easting, Y/Northing, Z/HAE
+ *
+ * @memberof AnchorPointIndirect.prototype
+ * @type {Cartesian3}
+ * @readonly
+ * @private
+ */
+ position: {
+ get: function () {
+ return this._position;
+ },
+ },
+
+ /**
+ * The delta-x delta-y delta-z adjustment values in meters per anchor
+ * point.
+ *
+ * @memberof AnchorPointIndirect.prototype
+ * @type {Cartesian3}
+ * @readonly
+ * @private
+ */
+ adjustmentParams: {
+ get: function () {
+ return this._adjustmentParams;
+ },
+ },
+
+ /**
+ * The 3x3 covariance matrix.
+ *
+ * @memberof AnchorPointIndirect.prototype
+ * @type {Matrix3}
+ * @readonly
+ * @private
+ */
+ covarianceMatrix: {
+ get: function () {
+ return this._covarianceMatrix;
+ },
+ },
+});
+
+export default AnchorPointIndirect;
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js
new file mode 100644
index 000000000000..e535ea6a43a2
--- /dev/null
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js
@@ -0,0 +1,67 @@
+import Check from "../Core/Check.js";
+
+/**
+ * Metadata identifying parameters using same correlation modeling and
+ * associated correlation parameters.
+ *
+ * @private
+ * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
+ */
+function CorrelationGroup(options) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.object("options.groupFlags", options.groupFlags);
+ Check.typeOf.object("options.rotationThetas", options.rotationThetas);
+ Check.typeOf.object("options.params", options.params);
+ //>>includeEnd('debug');
+
+ this._groupFlags = options.groupFlags;
+ this._rotationThetas = options.rotationThetas;
+ this._params = options.params;
+}
+
+Object.defineProperties(CorrelationGroup.prototype, {
+ /**
+ * Array of 3 booleans indicating if parameters delta-x delta-y delta-z
+ * used in the correlation group
+ *
+ * @memberof CorrelationGroup.prototype
+ * @type {boolean[]}
+ * @readonly
+ * @private
+ */
+ groupFlags: {
+ get: function () {
+ return this._groupFlags;
+ },
+ },
+
+ /**
+ * Rotations in milliradians about X, Y, Z axes, respectively
+ *
+ * @memberof CorrelationGroup.prototype
+ * @type {Cartesian3}
+ * @readonly
+ * @private
+ */
+ rotationThetas: {
+ get: function () {
+ return this._rotationThetas;
+ },
+ },
+
+ /**
+ * Array of 3 sets of SPDCF parameters, for the U, V, W directions, respectively
+ *
+ * @memberof CorrelationGroup.prototype
+ * @type {Spdcf[]}
+ * @readonly
+ * @private
+ */
+ params: {
+ get: function () {
+ return this._params;
+ },
+ },
+});
+
+export default CorrelationGroup;
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js
new file mode 100644
index 000000000000..016c27bf81cb
--- /dev/null
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js
@@ -0,0 +1,145 @@
+import defined from "../Core/defined.js";
+import Check from "../Core/Check.js";
+import StorageType from "./StorageType.js";
+import RuntimeError from "../Core/RuntimeError.js";
+
+/**
+ * The GPM metadata for a Ground-Space Indirect implementation stored
+ * locally (i.e. a tile and/or leaf node).
+ *
+ * @private
+ * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
+ */
+function GltfGpmLocal(options) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.object("options.storageType", options.storageType);
+ //>>includeEnd('debug');
+
+ this._storageType = options.storageType;
+ this._anchorPointsIndirect = options.anchorPointsIndirect;
+ this._anchorPointsDirect = options.anchorPointsDirect;
+ this._intraTileCorrelationGroups = options.intraTileCorrelationGroups;
+ this._covarianceDirect = options.covarianceDirect;
+
+ //>>includeStart('debug', pragmas.debug);
+ if (this.storageType === StorageType.Indirect) {
+ if (!defined(this.anchorPointsIndirect)) {
+ throw new RuntimeError(
+ "The anchorPointsIndirect are required for 'Indirect' storage"
+ );
+ }
+ if (!defined(this.intraTileCorrelationGroups)) {
+ throw new RuntimeError(
+ "The intraTileCorrelationGroups are required for 'Indirect' storage"
+ );
+ }
+ if (defined(this.anchorPointsDirect)) {
+ throw new RuntimeError(
+ "The anchorPointsDirect must be omitted for 'Indirect' storage"
+ );
+ }
+ if (defined(this.covarianceDirect)) {
+ throw new RuntimeError(
+ "The covarianceDirect must be omitted for 'Indirect' storage"
+ );
+ }
+ } else {
+ // Direct storage
+ if (!defined(this.anchorPointsDirect)) {
+ throw new RuntimeError(
+ "The anchorPointsDirect are required for 'Direct' storage"
+ );
+ }
+ if (!defined(this.covarianceDirect)) {
+ throw new RuntimeError(
+ "The covarianceDirect is required for 'Direct' storage"
+ );
+ }
+ if (defined(this.anchorPointsIndirect)) {
+ throw new RuntimeError(
+ "The anchorPointsIndirect must be omitted for 'Direct' storage"
+ );
+ }
+ if (defined(this.intraTileCorrelationGroups)) {
+ throw new RuntimeError(
+ "The intraTileCorrelationGroups must be omitted for 'Direct' storage"
+ );
+ }
+ }
+ //>>includeEnd('debug');
+}
+
+Object.defineProperties(GltfGpmLocal.prototype, {
+ /**
+ * Specifies if covariance storage is indirect or direct.
+ *
+ * @memberof GltfGpmLocal.prototype
+ * @type {StorageType}
+ * @readonly
+ * @private
+ */
+ storageType: {
+ get: function () {
+ return this._storageType;
+ },
+ },
+
+ /**
+ * Array of stored indirect anchor points
+ *
+ * @memberof GltfGpmLocal.prototype
+ * @type {AnchorPointIndirect[]}
+ * @readonly
+ * @private
+ */
+ anchorPointsIndirect: {
+ get: function () {
+ return this._anchorPointsIndirect;
+ },
+ },
+
+ /**
+ * Array of stored direct anchor points
+ *
+ * @memberof GltfGpmLocal.prototype
+ * @type {AnchorPointDirect[]}
+ * @readonly
+ * @private
+ */
+ anchorPointsDirect: {
+ get: function () {
+ return this._anchorPointsDirect;
+ },
+ },
+
+ /**
+ * Metadata identifying parameters using same correlation modeling and
+ * associated correlation parameters
+ *
+ * @memberof GltfGpmLocal.prototype
+ * @type {CorrelationGroup[]}
+ * @readonly
+ * @private
+ */
+ intraTileCorrelationGroups: {
+ get: function () {
+ return this._intraTileCorrelationGroups;
+ },
+ },
+
+ /**
+ * The full covariance of anchor point parameters
+ *
+ * @memberof GltfGpmLocal.prototype
+ * @type {Matrix3}
+ * @readonly
+ * @private
+ */
+ covarianceDirect: {
+ get: function () {
+ return this._covarianceDirect;
+ },
+ },
+});
+
+export default GltfGpmLocal;
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/MeshPrimitiveGpmLocal.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/MeshPrimitiveGpmLocal.js
new file mode 100644
index 000000000000..1ca122137744
--- /dev/null
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/MeshPrimitiveGpmLocal.js
@@ -0,0 +1,27 @@
+/**
+ * Local Generic Point-cloud Model information about a glTF primitive.
+ *
+ * @private
+ * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
+ */
+function MeshPrimitiveGpmLocal(options) {
+ this._ppeTextures = options.ppeTextures;
+}
+
+Object.defineProperties(MeshPrimitiveGpmLocal.prototype, {
+ /**
+ * An array of ppe textures.
+ *
+ * @memberof MeshPrimitiveGpmLocal.prototype
+ * @type {PpeTexture[]|undefined}
+ * @readonly
+ * @private
+ */
+ ppeTextures: {
+ get: function () {
+ return this._ppeTextures;
+ },
+ },
+});
+
+export default MeshPrimitiveGpmLocal;
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
new file mode 100644
index 000000000000..26f0d152284a
--- /dev/null
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
@@ -0,0 +1,67 @@
+import Check from "../Core/Check.js";
+
+/**
+ * Metadata related to the stored PPE data.
+ *
+ * @private
+ * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
+ */
+function PpeMetadata(options) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.object("options.source", options.source);
+ //>>includeEnd('debug');
+
+ this._min = options.min;
+ this._max = options.max;
+ this._source = options.source;
+}
+
+Object.defineProperties(PpeMetadata.prototype, {
+ /**
+ * Minimum allowed value for the property. This is the minimum of all
+ * values after the transforms based on the offset and scale properties
+ * have been applied.
+ *
+ * @memberof PpeMetadata.prototype
+ * @type {number|undefined}
+ * @readonly
+ * @private
+ */
+ min: {
+ get: function () {
+ return this._min;
+ },
+ },
+
+ /**
+ * Maximum allowed value for the property. This is the maximum of all
+ * values after the transforms based on the offset and scale properties
+ * have been applied.
+ *
+ * @memberof PpeMetadata.prototype
+ * @type {number|undefined}
+ * @readonly
+ * @private
+ */
+ max: {
+ get: function () {
+ return this._max;
+ },
+ },
+
+ /**
+ * Possible error source contents
+ *
+ * @memberof PpeMetadata.prototype
+ * @type {PpeSource}
+ * @readonly
+ * @private
+ */
+ source: {
+ get: function () {
+ return this._source;
+ },
+ },
+});
+
+export default PpeMetadata;
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeSource.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeSource.js
new file mode 100644
index 000000000000..d44acabe4e1c
--- /dev/null
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeSource.js
@@ -0,0 +1,72 @@
+/**
+ * An enum of per-point error sources
+ *
+ * @enum {string}
+ * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
+ */
+const PpeSource = {
+ /**
+ * The PPE standard deviation of error in the x dimension of the MCS (sigma x). Value will be squared
+ * and used to populate the (1,1) element in the PPE covariance matrix.
+ *
+ * @type {string}
+ * @constant
+ */
+ SIGX: "SIGX",
+
+ /**
+ * The PPE standard deviation of error in the y dimension of the MCS (sigma y). Value will be squared
+ * and used to populate the (2,2) element in the PPE covariance matrix.
+ *
+ * @type {string}
+ * @constant
+ */
+ SIGY: "SIGY",
+
+ /**
+ * The PPE standard deviation of error in the z dimension of the MCS (sigma z). Value will be squared
+ * and used to populate the (3,3) element in the PPE covariance matrix.
+ *
+ * @type {string}
+ * @constant
+ */
+ SIGZ: "SIGZ",
+
+ /**
+ * The PPE variance of error in the x dimension of the MCS (sigma x2). Value will be used to populate
+ * the (1,1) element in the PPE covariance matrix.
+ *
+ * @type {string}
+ * @constant
+ */
+ VARX: "VARX",
+
+ /**
+ * The PPE variance of error in the y dimension of the MCS (sigma y2). Value will be used to populate
+ * the (2,2) element in the PPE covariance matrix.
+ *
+ * @type {string}
+ * @constant
+ */
+ VARY: "VARY",
+
+ /**
+ * The PPE variance of error in the z dimension of the MCS (sigma z2). Value will be used to populate
+ * the (3,3) element in the PPE covariance matrix.
+ *
+ * @type {string}
+ * @constant
+ */
+ VARZ: "VARZ",
+
+ /**
+ * The PPE radial error in the horizontal dimension (x-y) of the MCS (sigma radial) . Value will be squared
+ * and used to populate the (1,1) and (2,2) element in the PPE covariance matrix.
+ *
+ * @type {string}
+ * @constant
+ */
+ SIGR: "VARZ",
+};
+
+export default Object.freeze(PpeSource);
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
new file mode 100644
index 000000000000..07d2fb5b6be8
--- /dev/null
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
@@ -0,0 +1,115 @@
+import Check from "../Core/Check.js";
+
+/**
+ * PPE (Per-Point Error) texture in `NGA_gpm_local`.
+ *
+ * This is a valid glTF `TextureInfo` object (with a required `index`
+ * and an optional `texCoord)`, with additional properties that
+ * describe the structure of the metdata that is stored in the texture.
+ *
+ * @private
+ * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
+ */
+function PpeTexture(options) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.object("options.traits", options.traits);
+ Check.typeOf.object("options.index", options.index);
+ //>>includeEnd('debug');
+
+ this._traits = options.traits;
+ this._noData = options.noData;
+ this._offset = options.offset;
+ this._scale = options.scale;
+ this._index = options.index;
+ this._texCoord = options.texCoord;
+}
+
+Object.defineProperties(PpeTexture.prototype, {
+ /**
+ * The data contained here applies to this node and corresponding
+ * texture.
+ *
+ * @memberof PpeTexture.prototype
+ * @type {PpeMetadata}
+ * @readonly
+ * @private
+ */
+ traits: {
+ get: function () {
+ return this._traits;
+ },
+ },
+
+ /**
+ * A value to represent missing data - also known as a sentinel value -
+ * wherever it appears.
+ *
+ * @memberof PpeTexture.prototype
+ * @type {number|undefined}
+ * @readonly
+ * @private
+ */
+ noData: {
+ get: function () {
+ return this._noData;
+ },
+ },
+
+ /**
+ * An offset to apply to property values.
+ *
+ * @memberof PpeTexture.prototype
+ * @type {number|undefined}
+ * @readonly
+ * @private
+ */
+ offset: {
+ get: function () {
+ return this._offset;
+ },
+ },
+
+ /**
+ * An scale to apply to property values.
+ *
+ * @memberof PpeTexture.prototype
+ * @type {number|undefined}
+ * @readonly
+ * @private
+ */
+ scale: {
+ get: function () {
+ return this._scale;
+ },
+ },
+
+ /**
+ * The index of the texture
+ *
+ * @memberof PpeTexture.prototype
+ * @type {number}
+ * @readonly
+ * @private
+ */
+ index: {
+ get: function () {
+ return this._index;
+ },
+ },
+
+ /**
+ * The set index of texture's TEXCOORD attribute used for texture coordinate mapping.
+ *
+ * @memberof PpeTexture.prototype
+ * @type {number|undefined}
+ * @readonly
+ * @private
+ */
+ texCoord: {
+ get: function () {
+ return this._texCoord;
+ },
+ },
+});
+
+export default PpeTexture;
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js
new file mode 100644
index 000000000000..548752d533e4
--- /dev/null
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js
@@ -0,0 +1,87 @@
+import Check from "../Core/Check.js";
+
+/**
+ * Variables for a Strictly Positive-Definite Correlation Function.
+ *
+ * Parameters (A, alpha, beta, T) used to describe the correlation decrease
+ * between points as a function of delta time.
+ *
+ * @private
+ * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
+ */
+function Spdcf(options) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.number.greaterThan("options.A", options.A, 0.0);
+ Check.typeOf.number.lessThanOrEquals("options.A", options.A, 1.0);
+ Check.typeOf.number.greaterThanOrEquals("options.alpha", options.alpha, 0.0);
+ Check.typeOf.number.lessThan("options.alpha", options.alpha, 1.0);
+ Check.typeOf.number.greaterThanOrEquals("options.beta", options.beta, 0.0);
+ Check.typeOf.number.lessThanOrEquals("options.beta", options.beta, 10.0);
+ Check.typeOf.number.greaterThan("options.T", options.T, 0.0);
+ //>>includeEnd('debug');
+
+ this._A = options.A;
+ this._alpha = options.alpha;
+ this._beta = options.beta;
+ this._T = options.T;
+}
+
+Object.defineProperties(Spdcf.prototype, {
+ /**
+ * In (0, 1]
+ *
+ * @memberof Spdcf.prototype
+ * @type {number}
+ * @readonly
+ * @private
+ */
+ A: {
+ get: function () {
+ return this._A;
+ },
+ },
+
+ /**
+ * In [0, 1)
+ *
+ * @memberof Spdcf.prototype
+ * @type {number}
+ * @readonly
+ * @private
+ */
+ alpha: {
+ get: function () {
+ return this._alpha;
+ },
+ },
+
+ /**
+ * In [0, 10]
+ *
+ * @memberof Spdcf.prototype
+ * @type {number}
+ * @readonly
+ * @private
+ */
+ beta: {
+ get: function () {
+ return this._beta;
+ },
+ },
+
+ /**
+ * In (0, +inf)
+ *
+ * @memberof Spdcf.prototype
+ * @type {number}
+ * @readonly
+ * @private
+ */
+ T: {
+ get: function () {
+ return this._T;
+ },
+ },
+});
+
+export default Spdcf;
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/StorageType.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/StorageType.js
new file mode 100644
index 000000000000..f706c32b63e1
--- /dev/null
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/StorageType.js
@@ -0,0 +1,27 @@
+/**
+ * An enum of storage types for covariance information
+ *
+ * @enum {string}
+ * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
+ */
+const StorageType = {
+ /**
+ * Store the full error covariance of the anchor points, to include the cross-covariance terms
+ *
+ * @type {string}
+ * @constant
+ */
+ Direct: "Direct",
+
+ /**
+ * A full covariance matrix is stored for each of the anchor points. However, in this case the
+ * cross-covariance terms are not directly stored, but can be computed by a set of spatial
+ * correlation function parameters which are stored in the metadata.
+ *
+ * @type {string}
+ * @constant
+ */
+ Indirect: "Indirect",
+};
+
+export default Object.freeze(StorageType);
From d7f1c9195afb7016cd5e0c290f7dc740195903d9 Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Wed, 18 Sep 2024 18:30:57 +0200
Subject: [PATCH 02/38] Fix import and usage of 'Check'
---
.../Scene/Model/Extensions/Gpm/AnchorPointDirect.js | 4 ++--
.../Scene/Model/Extensions/Gpm/AnchorPointIndirect.js | 4 ++--
.../Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js | 2 +-
.../Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js | 8 ++++----
.../Source/Scene/Model/Extensions/Gpm/PpeMetadata.js | 2 +-
.../Source/Scene/Model/Extensions/Gpm/PpeTexture.js | 2 +-
.../engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js | 2 +-
7 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js
index 79e71895214a..903330dada7f 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js
@@ -1,4 +1,4 @@
-import Check from "../Core/Check.js";
+import Check from "../../../../Core/Check.js";
/**
* Metadata for one stored anchor point using direct storage
@@ -8,7 +8,7 @@ import Check from "../Core/Check.js";
*/
function AnchorPointDirect(options) {
//>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("options.position", options.property);
+ Check.typeOf.object("options.position", options.position);
Check.typeOf.object("options.adjustmentParams", options.adjustmentParams);
//>>includeEnd('debug');
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js
index c70996f33485..f0102db32943 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js
@@ -1,4 +1,4 @@
-import Check from "../Core/Check.js";
+import Check from "../../../../Core/Check.js";
/**
* Metadata for one stored anchor point.
@@ -8,7 +8,7 @@ import Check from "../Core/Check.js";
*/
function AnchorPointIndirect(options) {
//>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("options.position", options.property);
+ Check.typeOf.object("options.position", options.position);
Check.typeOf.object("options.adjustmentParams", options.adjustmentParams);
Check.typeOf.object("options.covarianceMatrix", options.covarianceMatrix);
//>>includeEnd('debug');
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js
index e535ea6a43a2..cc82812aa608 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js
@@ -1,4 +1,4 @@
-import Check from "../Core/Check.js";
+import Check from "../../../../Core/Check.js";
/**
* Metadata identifying parameters using same correlation modeling and
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js
index 016c27bf81cb..f6b9e4aab5df 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js
@@ -1,7 +1,7 @@
-import defined from "../Core/defined.js";
-import Check from "../Core/Check.js";
+import defined from "../../../../Core/defined.js";
+import Check from "../../../../Core/Check.js";
+import RuntimeError from "../../../../Core/RuntimeError.js";
import StorageType from "./StorageType.js";
-import RuntimeError from "../Core/RuntimeError.js";
/**
* The GPM metadata for a Ground-Space Indirect implementation stored
@@ -12,7 +12,7 @@ import RuntimeError from "../Core/RuntimeError.js";
*/
function GltfGpmLocal(options) {
//>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("options.storageType", options.storageType);
+ Check.typeOf.string("options.storageType", options.storageType);
//>>includeEnd('debug');
this._storageType = options.storageType;
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
index 26f0d152284a..de255f5b6dd9 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
@@ -1,4 +1,4 @@
-import Check from "../Core/Check.js";
+import Check from "../../../../Core/Check.js";
/**
* Metadata related to the stored PPE data.
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
index 07d2fb5b6be8..5214a6e34ac6 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
@@ -1,4 +1,4 @@
-import Check from "../Core/Check.js";
+import Check from "../../../../Core/Check.js";
/**
* PPE (Per-Point Error) texture in `NGA_gpm_local`.
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js
index 548752d533e4..7687ed32ed8d 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js
@@ -1,4 +1,4 @@
-import Check from "../Core/Check.js";
+import Check from "../../../../Core/Check.js";
/**
* Variables for a Strictly Positive-Definite Correlation Function.
From e09cb04035f4e654249cccab80e582f5aac0f222 Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Wed, 18 Sep 2024 18:32:04 +0200
Subject: [PATCH 03/38] Start wiring in GPM loader
---
packages/engine/Source/Scene/GltfGpmLoader.js | 466 +++++-------------
packages/engine/Source/Scene/GltfLoader.js | 105 ++++
.../Scene/GltfMeshPrimitiveGpmLoader.js | 465 +++++++++++++++++
packages/engine/Source/Scene/Model/Model.js | 18 +
.../Source/Scene/Model/Model3DTileContent.js | 10 +-
.../engine/Source/Scene/ModelComponents.js | 6 +
6 files changed, 737 insertions(+), 333 deletions(-)
create mode 100644 packages/engine/Source/Scene/GltfMeshPrimitiveGpmLoader.js
diff --git a/packages/engine/Source/Scene/GltfGpmLoader.js b/packages/engine/Source/Scene/GltfGpmLoader.js
index b3463abb8054..4fe1cf50c46b 100644
--- a/packages/engine/Source/Scene/GltfGpmLoader.js
+++ b/packages/engine/Source/Scene/GltfGpmLoader.js
@@ -1,24 +1,23 @@
+import Cartesian3 from "../Core/Cartesian3.js";
import Check from "../Core/Check.js";
import defaultValue from "../Core/defaultValue.js";
import defined from "../Core/defined.js";
-import ResourceCache from "./ResourceCache.js";
+import Matrix3 from "../Core/Matrix3.js";
+import AnchorPointDirect from "./Model/Extensions/Gpm/AnchorPointDirect.js";
+import AnchorPointIndirect from "./Model/Extensions/Gpm/AnchorPointIndirect.js";
+import CorrelationGroup from "./Model/Extensions/Gpm/CorrelationGroup.js";
+import GltfGpmLocal from "./Model/Extensions/Gpm/GltfGpmLocal.js";
+import Spdcf from "./Model/Extensions/Gpm/Spdcf.js";
+import StorageType from "./Model/Extensions/Gpm/StorageType.js";
import ResourceLoader from "./ResourceLoader.js";
import ResourceLoaderState from "./ResourceLoaderState.js";
-import PropertyTexture from "./PropertyTexture.js";
-import StructuralMetadata from "./StructuralMetadata.js";
-import MetadataSchema from "./MetadataSchema.js";
/**
- * Loads glTF NGA_gpm_local
+ * Loads glTF NGA_gpm_local from the root of a glTF object
*
* Implements the {@link ResourceLoader} interface.
*
- * Implementation note: This is an experimental implementation. It is based
- * on a GltfStructuralMetadataLoader, by removing everything that is not
- * related to property textures, and translating the "ppeTextures" of
- * the NGA_gpm_local extension into property textures. These will be
- * returned as part of a `StructuralMetadata` object, which may override
- * any `StructuralMetadata` that was read directly from the glTF.
+ * Implementation note: This is an experimental implementation.
*
* @alias GltfGpmLoader
* @constructor
@@ -29,8 +28,6 @@ import MetadataSchema from "./MetadataSchema.js";
* @param {string} [options.extension] The NGA_gpm_local
extension object.
* @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
* @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
- * @param {SupportedImageFormats} options.supportedImageFormats The supported image formats.
- * @param {FrameState} options.frameState The frame state.
* @param {string} [options.cacheKey] The cache key of the resource.
* @param {boolean} [options.asynchronous=true] Determines if WebGL resource creation will be spread out over several frames or block until all WebGL resources are created.
*
@@ -43,8 +40,6 @@ function GltfGpmLoader(options) {
const extension = options.extension;
const gltfResource = options.gltfResource;
const baseResource = options.baseResource;
- const supportedImageFormats = options.supportedImageFormats;
- const frameState = options.frameState;
const cacheKey = options.cacheKey;
const asynchronous = defaultValue(options.asynchronous, true);
@@ -53,22 +48,19 @@ function GltfGpmLoader(options) {
Check.typeOf.object("options.extension", extension);
Check.typeOf.object("options.gltfResource", gltfResource);
Check.typeOf.object("options.baseResource", baseResource);
- Check.typeOf.object("options.supportedImageFormats", supportedImageFormats);
- Check.typeOf.object("options.frameState", frameState);
//>>includeEnd('debug');
this._gltfResource = gltfResource;
this._baseResource = baseResource;
this._gltf = gltf;
this._extension = extension;
- this._supportedImageFormats = supportedImageFormats;
- this._frameState = frameState;
this._cacheKey = cacheKey;
this._asynchronous = asynchronous;
- this._textureLoaders = [];
- this._textureIds = [];
- this._structuralMetadata = undefined;
- this._state = ResourceLoaderState.UNLOADED;
+ this._gltfGpmLocal = undefined;
+
+ // Immediately go into the "LOADED" state, since there
+ // are no resources to wait for
+ this._state = ResourceLoaderState.LOADED;
this._promise = undefined;
}
@@ -93,46 +85,21 @@ Object.defineProperties(GltfGpmLoader.prototype, {
},
},
/**
- * The parsed structural metadata
+ * The parsed GltfGpmLocal object
*
* @memberof GltfGpmLoader.prototype
*
- * @type {StructuralMetadata}
+ * @type {GltfGpmLocal}
* @readonly
* @private
*/
- structuralMetadata: {
+ gltfGpmLocal: {
get: function () {
- return this._structuralMetadata;
+ return this._gltfGpmLocal;
},
},
});
-async function loadResources(loader) {
- try {
- const texturesPromise = loadTextures(loader);
- await texturesPromise;
-
- if (loader.isDestroyed()) {
- return;
- }
-
- loader._gltf = undefined; // No longer need to hold onto the glTF
-
- loader._state = ResourceLoaderState.LOADED;
- return loader;
- } catch (error) {
- if (loader.isDestroyed()) {
- return;
- }
-
- loader.unload();
- loader._state = ResourceLoaderState.FAILED;
- const errorMessage = "Failed to load GPM data";
- throw loader.getError(errorMessage, error);
- }
-}
-
/**
* Loads the resource.
* @returns {Promise} A promise which resolves to the loader when the resource loading is completed.
@@ -142,211 +109,32 @@ GltfGpmLoader.prototype.load = function () {
if (defined(this._promise)) {
return this._promise;
}
-
- this._state = ResourceLoaderState.LOADING;
- this._promise = loadResources(this);
+ this._promise = Promise.resolve(this);
return this._promise;
};
-function gatherUsedTextureIds(gpmExtension) {
- // Gather the used textures
- const textureIds = {};
- const ppeTextures = gpmExtension.ppeTextures;
- if (defined(ppeTextures)) {
- for (let i = 0; i < ppeTextures.length; i++) {
- const ppeTexture = ppeTextures[i];
- // The texture is a valid textureInfo.
- textureIds[ppeTexture.index] = ppeTexture;
- }
- }
- return textureIds;
-}
-
-function loadTextures(gpmLoader) {
- let textureIds;
- if (defined(gpmLoader._extension)) {
- textureIds = gatherUsedTextureIds(gpmLoader._extension);
- }
-
- const gltf = gpmLoader._gltf;
- const gltfResource = gpmLoader._gltfResource;
- const baseResource = gpmLoader._baseResource;
- const supportedImageFormats = gpmLoader._supportedImageFormats;
- const frameState = gpmLoader._frameState;
- const asynchronous = gpmLoader._asynchronous;
-
- // Load the textures
- const texturePromises = [];
- for (const textureId in textureIds) {
- if (textureIds.hasOwnProperty(textureId)) {
- const textureLoader = ResourceCache.getTextureLoader({
- gltf: gltf,
- textureInfo: textureIds[textureId],
- gltfResource: gltfResource,
- baseResource: baseResource,
- supportedImageFormats: supportedImageFormats,
- frameState: frameState,
- asynchronous: asynchronous,
- });
- gpmLoader._textureLoaders.push(textureLoader);
- gpmLoader._textureIds.push(textureId);
- texturePromises.push(textureLoader.load());
- }
- }
-
- return Promise.all(texturePromises);
-}
-
-/**
- * A static mapping from PPE texture property identifier keys
- * to `MetadataSchema` instances. This is used to create each
- * schema (with a certain structure) only ONCE in
- * obtainPpeTexturesMetadataSchema
- *
- * @private
- */
-GltfGpmLoader.ppeTexturesMetadataSchemaCache = new Map();
-
-/**
- * Create the JSON description of a metadata class that treats
- * the given PPE texture as a property texture property(!).
- *
- * @param {any} ppeTexture - The PPE texture
- * @param {number} index - The index of the texture in the extension
- * @returns The class JSON
- */
-GltfGpmLoader.prototype.createPpeTextureClassJson = function (
- ppeTexture,
- index
-) {
- const traits = ppeTexture.traits;
- const ppePropertyName = traits.source;
-
- // XXX_UNCERTAINTY: The ppeTexture will have a structure
- // like this:
- //
- //"ppeTextures" : [
- // {
- // "traits" : {
- // "source" : "SIGZ",
- // "min" : 0.0,
- // "max" : 16.0
- // },
- // "index" : 2,
- // "noData" : 255,
- // "offset" : 0.0,
- // "scale" : 0.06274509803921569,
- // "texCoord" : 1
- // },
- //
- // Note that in GPM 1.2d, the min/max should be part of the
- // texture, but in the actual data (GPM 1.2i), they are in
- // the traits (ppeMetadata). And there, they/ seem to denote
- // the min/max values that actually appear in the texture.
- // So they are integrated into the 'scale' factor here:
- const min = traits.min ?? 0;
- const max = traits.max ?? 255;
- const minMaxScale = 255.0 / (max - min);
- const offset = ppeTexture.offset;
- const scale = ppeTexture.scale * minMaxScale;
- const classJson = {
- name: `PPE texture class ${index}`,
- properties: {
- [ppePropertyName]: {
- name: "PPE",
- type: "SCALAR",
- componentType: "UINT8",
- normalized: true,
- offset: offset,
- scale: scale,
- },
- },
- };
- return classJson;
-};
-
/**
- * Returns the `MetadataSchema` for the PPE textures in this instance.
- *
- * This method will return a (statically/globally) cached metadata
- * schema that reflects the structure of the PPE textures in this
- * instance, creating and caching it if necessary.
+ * Creates a Matrix3 that describes a covariance matrix (which is
+ * symmetric) from the array containing the upper triangle, in
+ * column-major order.
*
- * For details on the cache key, see `collectPpeTexturePropertyIdentifiers`
- *
- * @returns The `MetadataSchema`
+ * @param {number[]} array The input array
+ * @returns The Matrix3
*/
-GltfGpmLoader.prototype.obtainPpeTexturesMetadataSchema = function () {
- const ppeTexturePropertyIdentifiers = this.collectPpeTexturePropertyIdentifiers();
- const key = ppeTexturePropertyIdentifiers.toString();
- let ppeTexturesMetadataSchema = GltfGpmLoader.ppeTexturesMetadataSchemaCache.get(
- key
- );
- if (defined(ppeTexturesMetadataSchema)) {
- // XXX_UNCERTAINTY Debug log
- //console.log(`Using cached schema for GPM PPE textures with key ${key}`);
- return ppeTexturesMetadataSchema;
- }
-
- // XXX_UNCERTAINTY Debug log - if caching works, this should be printed only ONCE!
- console.log(`Creating schema for GPM PPE textures with key ${key}`);
- const schemaId = `PPE_TEXTURE_SCHEMA_${GltfGpmLoader.ppeTexturesMetadataSchemaCache.size}`;
- const ppeTexturesMetadataSchemaJson = {
- id: schemaId,
- classes: {},
- };
-
- const extension = this._extension;
- if (defined(extension.ppeTextures)) {
- for (let i = 0; i < extension.ppeTextures.length; i++) {
- const ppeTexture = extension.ppeTextures[i];
- const classId = `ppeTexture_${i}`;
- const classJson = this.createPpeTextureClassJson(ppeTexture, i);
- ppeTexturesMetadataSchemaJson.classes[classId] = classJson;
- }
- }
-
- ppeTexturesMetadataSchema = MetadataSchema.fromJson(
- ppeTexturesMetadataSchemaJson
+function createCovarianceMatrixFromUpperTriangle(array) {
+ const covarianceMatrix = new Matrix3(
+ array[0],
+ array[1],
+ array[3],
+ array[1],
+ array[2],
+ array[4],
+ array[3],
+ array[4],
+ array[5]
);
- GltfGpmLoader.ppeTexturesMetadataSchemaCache.set(
- key,
- ppeTexturesMetadataSchema
- );
- return ppeTexturesMetadataSchema;
-};
-
-/**
- * Creates an array of strings that serve as identifiers for PPE textures.
- *
- * Each glTF may define multiple `ppeTexture` objects within the
- * `NGA_gpm_local` extensions. Each of these textures corresponds
- * to one 'property texture property(!)' in a metadata schema.
- *
- * This method will create an array where each element is a (JSON)
- * string representation of the parts of a GPM PPE texture definition
- * that are relevant for distinguishing two PPE textures in terms
- * of their structure within a `StructuralMetadata`.
- *
- * @returns The identifiers
- */
-GltfGpmLoader.prototype.collectPpeTexturePropertyIdentifiers = function () {
- const extension = this._extension;
- const ppeTexturePropertyIdentifiers = [];
- if (defined(extension.ppeTextures)) {
- for (let i = 0; i < extension.ppeTextures.length; i++) {
- const ppeTexture = extension.ppeTextures[i];
- // The following will create an identifier that can be used
- // to define two PPE textures as "representing the same
- // property texture property" within a structural metadata
- // schema.
- const classJson = this.createPpeTextureClassJson(ppeTexture, i);
- const ppeTexturePropertyIdentifier = JSON.stringify(classJson);
- ppeTexturePropertyIdentifiers.push(ppeTexturePropertyIdentifier);
- }
- }
- return ppeTexturePropertyIdentifiers;
-};
+ return covarianceMatrix;
+}
/**
* Processes the resource until it becomes ready.
@@ -362,108 +150,122 @@ GltfGpmLoader.prototype.process = function (frameState) {
if (this._state === ResourceLoaderState.READY) {
return true;
}
-
+ if (this._state === ResourceLoaderState.FAILED) {
+ return true;
+ }
if (this._state !== ResourceLoaderState.LOADED) {
return false;
}
- const textureLoaders = this._textureLoaders;
- const textureLoadersLength = textureLoaders.length;
- let ready = true;
- for (let i = 0; i < textureLoadersLength; ++i) {
- const textureLoader = textureLoaders[i];
- const textureReady = textureLoader.process(frameState);
- ready = ready && textureReady;
- }
+ console.log("PARSE AND STORE HERE! ", this._extension);
- if (!ready) {
- return false;
- }
+ const extensionJson = this._extension;
- const textures = {};
- for (let i = 0; i < this._textureIds.length; ++i) {
- const textureId = this._textureIds[i];
- const textureLoader = textureLoaders[i];
- if (!textureLoader.isDestroyed()) {
- textures[textureId] = textureLoader.texture;
+ const storageType = extensionJson.storageType;
+ if (storageType === StorageType.Direct) {
+ const anchorPointsDirect = [];
+ const anchorPointsDirectJson = extensionJson.anchorPointsDirect;
+ for (const anchorPointDirectJson of anchorPointsDirectJson) {
+ const position = Cartesian3.fromArray(
+ anchorPointDirectJson.position,
+ 0,
+ new Cartesian3()
+ );
+ const adjustmentParams = Cartesian3.fromArray(
+ anchorPointDirectJson.adjustmentParams,
+ 0,
+ new Cartesian3()
+ );
+ const anchorPointDirect = new AnchorPointDirect({
+ position: position,
+ adjustmentParams: adjustmentParams,
+ });
+ anchorPointsDirect.push(anchorPointDirect);
}
+ const covarianceDirect = createCovarianceMatrixFromUpperTriangle(
+ extensionJson.covarianceDirectUpperTriangle
+ );
+
+ this._gltfGpmLocal = new GltfGpmLocal({
+ storageType: storageType,
+ anchorPointsDirect: anchorPointsDirect,
+ covarianceDirect: covarianceDirect,
+ });
+ this._state = ResourceLoaderState.READY;
+ return true;
}
-
- const ppeTexturesMetadataSchema = this.obtainPpeTexturesMetadataSchema();
- const extension = this._extension;
- const propertyTextures = [];
- if (defined(extension.ppeTextures)) {
- for (let i = 0; i < extension.ppeTextures.length; i++) {
- const ppeTexture = extension.ppeTextures[i];
- const classId = `ppeTexture_${i}`;
- const traits = ppeTexture.traits;
- const ppePropertyName = traits.source;
- const metadataClass = ppeTexturesMetadataSchema.classes[classId];
-
- // XXX_UNCERTAINTY Debug log
- //console.log(
- // `Creating property texture with class ${classId} and property ${ppePropertyName}`
- //);
-
- const ppeTextureAsPropertyTexture = {
- class: classId,
- properties: {
- [ppePropertyName]: {
- index: ppeTexture.index,
- texCoord: ppeTexture.texCoord,
- },
- },
- };
- propertyTextures.push(
- new PropertyTexture({
- id: i,
- name: ppeTexture.name,
- propertyTexture: ppeTextureAsPropertyTexture,
- class: metadataClass,
- textures: textures,
- })
+ if (storageType === StorageType.Indirect) {
+ const anchorPointsIndirect = [];
+ const anchorPointsIndirectJson = extensionJson.anchorPointsIndirect;
+ for (const anchorPointIndirectJson of anchorPointsIndirectJson) {
+ const position = Cartesian3.fromArray(
+ anchorPointIndirectJson.position,
+ 0,
+ new Cartesian3()
+ );
+ const adjustmentParams = Cartesian3.fromArray(
+ anchorPointIndirectJson.adjustmentParams,
+ 0,
+ new Cartesian3()
+ );
+ const covarianceMatrix = createCovarianceMatrixFromUpperTriangle(
+ anchorPointIndirectJson.covarianceMatrix
);
+ const anchorPointIndirect = new AnchorPointIndirect({
+ position: position,
+ adjustmentParams: adjustmentParams,
+ covarianceMatrix: covarianceMatrix,
+ });
+ anchorPointsIndirect.push(anchorPointIndirect);
}
- }
- const structuralMetadata = new StructuralMetadata({
- schema: ppeTexturesMetadataSchema,
- propertyTables: [],
- propertyTextures: propertyTextures,
- propertyAttributes: [],
- statistics: extension.statistics,
- extras: extension.extras,
- extensions: extension.extensions,
- });
- this._structuralMetadata = structuralMetadata;
+ const intraTileCorrelationGroupsJson =
+ extensionJson.intraTileCorrelationGroups;
+ const intraTileCorrelationGroups = [];
- this._state = ResourceLoaderState.READY;
- return true;
-};
+ for (const correlationGroupJson of intraTileCorrelationGroupsJson) {
+ const groupFlags = correlationGroupJson.groupFlags;
+ const rotationThetas = Cartesian3.fromArray(
+ correlationGroupJson.rotationThetas,
+ 0,
+ new Cartesian3()
+ );
+ const params = [];
+ for (const paramJson of correlationGroupJson.params) {
+ const param = new Spdcf({
+ A: paramJson.A,
+ alpha: paramJson.alpha,
+ beta: paramJson.beta,
+ T: paramJson.T,
+ });
+ params.push(param);
+ }
+ const correlationGroup = new CorrelationGroup({
+ groupFlags: groupFlags,
+ rotationThetas: rotationThetas,
+ params: params,
+ });
+ intraTileCorrelationGroups.push(correlationGroup);
+ }
-function unloadTextures(gpmLoader) {
- const textureLoaders = gpmLoader._textureLoaders;
- const textureLoadersLength = textureLoaders.length;
- for (let i = 0; i < textureLoadersLength; ++i) {
- ResourceCache.unload(textureLoaders[i]);
+ this._gltfGpmLocal = new GltfGpmLocal({
+ storageType: storageType,
+ anchorPointsIndirect: anchorPointsIndirect,
+ intraTileCorrelationGroups: intraTileCorrelationGroups,
+ });
+ this._state = ResourceLoaderState.READY;
+ return true;
}
- gpmLoader._textureLoaders.length = 0;
- gpmLoader._textureIds.length = 0;
-}
+ this._state = ResourceLoaderState.FAILED;
+ return false;
+};
/**
* Unloads the resource.
* @private
*/
GltfGpmLoader.prototype.unload = function () {
- unloadTextures(this);
-
- if (defined(this._schemaLoader)) {
- ResourceCache.unload(this._schemaLoader);
- }
- this._schemaLoader = undefined;
-
- this._structuralMetadata = undefined;
+ this._gltfGpmLocal = undefined;
};
export default GltfGpmLoader;
diff --git a/packages/engine/Source/Scene/GltfLoader.js b/packages/engine/Source/Scene/GltfLoader.js
index 18f825a6ae4e..490cbfb087af 100644
--- a/packages/engine/Source/Scene/GltfLoader.js
+++ b/packages/engine/Source/Scene/GltfLoader.js
@@ -29,6 +29,8 @@ import ResourceCache from "./ResourceCache.js";
import ResourceLoader from "./ResourceLoader.js";
import SupportedImageFormats from "./SupportedImageFormats.js";
import VertexAttributeSemantic from "./VertexAttributeSemantic.js";
+import GltfGpmLoader from "./GltfGpmLoader.js";
+import GltfMeshPrimitiveGpmLoader from "./GltfMeshPrimitiveGpmLoader.js";
const {
Attribute,
@@ -260,6 +262,8 @@ function GltfLoader(options) {
this._geometryLoaders = [];
this._geometryCallbacks = [];
this._structuralMetadataLoader = undefined;
+ this._gpmLoader = undefined;
+ this._meshPrimitiveGpmLoader = undefined;
this._loadResourcesPromise = undefined;
this._resourcesLoaded = false;
this._texturesLoaded = false;
@@ -471,6 +475,29 @@ function processLoaders(loader, frameState) {
ready = ready && metadataReady;
}
+ const gpmLoader = loader._gpmLoader;
+ if (defined(gpmLoader)) {
+ const gpmReady = gpmLoader.process(frameState);
+ if (gpmReady) {
+ // XXX
+ console.log("Got GPM data, storing ", gpmLoader._gltfGpmLocal);
+ loader._components.extensions["NGA_gpm_local"] = gpmLoader._gltfGpmLocal;
+ }
+ ready = ready && gpmReady;
+ }
+
+ const meshPrimitiveGpmLoader = loader._meshPrimitiveGpmLoader;
+ if (defined(meshPrimitiveGpmLoader)) {
+ const metadataReady = meshPrimitiveGpmLoader.process(frameState);
+ if (metadataReady) {
+ // XXX
+ console.log("Overwriting structural metadata with GPM data");
+ loader._components.structuralMetadata =
+ meshPrimitiveGpmLoader.structuralMetadata;
+ }
+ ready = ready && metadataReady;
+ }
+
if (ready) {
// Geometry requires further processing
loader._state = GltfLoaderState.POST_PROCESSING;
@@ -2453,6 +2480,32 @@ async function loadStructuralMetadata(
return structuralMetadataLoader.load();
}
+async function loadGpm(loader, gltf, extension) {
+ const gpmLoader = new GltfGpmLoader({
+ gltf: gltf,
+ extension: extension,
+ gltfResource: loader._gltfResource,
+ baseResource: loader._baseResource,
+ asynchronous: loader._asynchronous,
+ });
+ loader._gpmLoader = gpmLoader;
+ return gpmLoader.load();
+}
+
+async function loadMeshPrimitiveGpm(loader, gltf, extension, frameState) {
+ const meshPrimitiveGpmLoader = new GltfMeshPrimitiveGpmLoader({
+ gltf: gltf,
+ extension: extension,
+ gltfResource: loader._gltfResource,
+ baseResource: loader._baseResource,
+ supportedImageFormats: loader._supportedImageFormats,
+ frameState: frameState,
+ asynchronous: loader._asynchronous,
+ });
+ loader._meshPrimitiveGpmLoader = meshPrimitiveGpmLoader;
+ return meshPrimitiveGpmLoader.load();
+}
+
function loadAnimationSampler(loader, gltfSampler) {
const animationSampler = new AnimationSampler();
const accessors = loader.gltfJson.accessors;
@@ -2681,6 +2734,39 @@ function parse(loader, frameState) {
loader._loaderPromises.push(promise);
}
+ // Load NGA_gpm_local from root object
+ const gpmExtension = extensions.NGA_gpm_local;
+ if (defined(gpmExtension)) {
+ console.log("Loading GPM from root");
+ const promise = loadGpm(loader, gltf, gpmExtension);
+ loader._loaderPromises.push(promise);
+ }
+
+ // Load NGA_gpm_local from mesh primitives
+ const meshes = gltf.meshes;
+ if (defined(meshes)) {
+ for (const mesh of meshes) {
+ const primitives = mesh.primitives;
+ if (defined(primitives)) {
+ for (const primitive of primitives) {
+ const primitiveExtensions = primitive.extensions;
+ const meshPrimitiveGpmExtension = primitiveExtensions.NGA_gpm_local;
+ if (defined(meshPrimitiveGpmExtension)) {
+ // XXX
+ console.log("Loading GPM from mesh primitive");
+ const promise = loadMeshPrimitiveGpm(
+ loader,
+ gltf,
+ meshPrimitiveGpmExtension,
+ frameState
+ );
+ loader._loaderPromises.push(promise);
+ }
+ }
+ }
+ }
+ }
+
// Gather promises and handle any errors
const readyPromises = [];
readyPromises.push.apply(readyPromises, loader._loaderPromises);
@@ -2745,6 +2831,23 @@ function unloadStructuralMetadata(loader) {
}
}
+function unloadGpm(loader) {
+ if (defined(loader._gpmLoader) && !loader._gpmLoader.isDestroyed()) {
+ loader._gpmLoader.destroy();
+ loader._gpmLoader = undefined;
+ }
+}
+
+function unloadMeshPrimitiveGpm(loader) {
+ if (
+ defined(loader._meshPrimitiveGpmLoader) &&
+ !loader._meshPrimitiveGpmLoader.isDestroyed()
+ ) {
+ loader._meshPrimitiveGpmLoader.destroy();
+ loader._meshPrimitiveGpmLoader = undefined;
+ }
+}
+
/**
* Returns whether the resource has been unloaded.
* @private
@@ -2768,6 +2871,8 @@ GltfLoader.prototype.unload = function () {
unloadGeometry(this);
unloadGeneratedAttributes(this);
unloadStructuralMetadata(this);
+ unloadGpm(this);
+ unloadMeshPrimitiveGpm(this);
this._components = undefined;
this._typedArray = undefined;
diff --git a/packages/engine/Source/Scene/GltfMeshPrimitiveGpmLoader.js b/packages/engine/Source/Scene/GltfMeshPrimitiveGpmLoader.js
new file mode 100644
index 000000000000..724b1d8b1a47
--- /dev/null
+++ b/packages/engine/Source/Scene/GltfMeshPrimitiveGpmLoader.js
@@ -0,0 +1,465 @@
+import Check from "../Core/Check.js";
+import defaultValue from "../Core/defaultValue.js";
+import defined from "../Core/defined.js";
+import ResourceCache from "./ResourceCache.js";
+import ResourceLoader from "./ResourceLoader.js";
+import ResourceLoaderState from "./ResourceLoaderState.js";
+import PropertyTexture from "./PropertyTexture.js";
+import StructuralMetadata from "./StructuralMetadata.js";
+import MetadataSchema from "./MetadataSchema.js";
+
+/**
+ * Loads glTF NGA_gpm_local from a glTF mesh primitive.
+ *
+ * Implements the {@link ResourceLoader} interface.
+ *
+ * Implementation note: This is an experimental implementation. It is based
+ * on a GltfStructuralMetadataLoader, by removing everything that is not
+ * related to property textures, and translating the "ppeTextures" of
+ * the NGA_gpm_local extension into property texture properties. These will
+ * be returned as part of a `StructuralMetadata` object, which may override
+ * any `StructuralMetadata` that was read directly from the glTF.
+ *
+ * @alias GltfMeshPrimitiveGpmLoader
+ * @constructor
+ * @augments ResourceLoader
+ *
+ * @param {object} options Object with the following properties:
+ * @param {object} options.gltf The glTF JSON.
+ * @param {string} [options.extension] The NGA_gpm_local
extension object.
+ * @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
+ * @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
+ * @param {SupportedImageFormats} options.supportedImageFormats The supported image formats.
+ * @param {FrameState} options.frameState The frame state.
+ * @param {string} [options.cacheKey] The cache key of the resource.
+ * @param {boolean} [options.asynchronous=true] Determines if WebGL resource creation will be spread out over several frames or block until all WebGL resources are created.
+ *
+ * @private
+ * @experimental This feature is subject to change without Cesium's standard deprecation policy.
+ */
+function GltfMeshPrimitiveGpmLoader(options) {
+ options = defaultValue(options, defaultValue.EMPTY_OBJECT);
+ const gltf = options.gltf;
+ const extension = options.extension;
+ const gltfResource = options.gltfResource;
+ const baseResource = options.baseResource;
+ const supportedImageFormats = options.supportedImageFormats;
+ const frameState = options.frameState;
+ const cacheKey = options.cacheKey;
+ const asynchronous = defaultValue(options.asynchronous, true);
+
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.object("options.gltf", gltf);
+ Check.typeOf.object("options.extension", extension);
+ Check.typeOf.object("options.gltfResource", gltfResource);
+ Check.typeOf.object("options.baseResource", baseResource);
+ Check.typeOf.object("options.supportedImageFormats", supportedImageFormats);
+ Check.typeOf.object("options.frameState", frameState);
+ //>>includeEnd('debug');
+
+ this._gltfResource = gltfResource;
+ this._baseResource = baseResource;
+ this._gltf = gltf;
+ this._extension = extension;
+ this._supportedImageFormats = supportedImageFormats;
+ this._frameState = frameState;
+ this._cacheKey = cacheKey;
+ this._asynchronous = asynchronous;
+ this._textureLoaders = [];
+ this._textureIds = [];
+ this._structuralMetadata = undefined;
+ this._state = ResourceLoaderState.UNLOADED;
+ this._promise = undefined;
+}
+
+if (defined(Object.create)) {
+ GltfMeshPrimitiveGpmLoader.prototype = Object.create(
+ ResourceLoader.prototype
+ );
+ GltfMeshPrimitiveGpmLoader.prototype.constructor = GltfMeshPrimitiveGpmLoader;
+}
+
+Object.defineProperties(GltfMeshPrimitiveGpmLoader.prototype, {
+ /**
+ * The cache key of the resource.
+ *
+ * @memberof GltfMeshPrimitiveGpmLoader.prototype
+ *
+ * @type {string}
+ * @readonly
+ * @private
+ */
+ cacheKey: {
+ get: function () {
+ return this._cacheKey;
+ },
+ },
+ /**
+ * The parsed structural metadata
+ *
+ * @memberof GltfMeshPrimitiveGpmLoader.prototype
+ *
+ * @type {StructuralMetadata}
+ * @readonly
+ * @private
+ */
+ structuralMetadata: {
+ get: function () {
+ return this._structuralMetadata;
+ },
+ },
+});
+
+async function loadResources(loader) {
+ try {
+ const texturesPromise = loadTextures(loader);
+ await texturesPromise;
+
+ if (loader.isDestroyed()) {
+ return;
+ }
+
+ loader._gltf = undefined; // No longer need to hold onto the glTF
+
+ loader._state = ResourceLoaderState.LOADED;
+ return loader;
+ } catch (error) {
+ if (loader.isDestroyed()) {
+ return;
+ }
+
+ loader.unload();
+ loader._state = ResourceLoaderState.FAILED;
+ const errorMessage = "Failed to load GPM data";
+ throw loader.getError(errorMessage, error);
+ }
+}
+
+/**
+ * Loads the resource.
+ * @returns {Promise} A promise which resolves to the loader when the resource loading is completed.
+ * @private
+ */
+GltfMeshPrimitiveGpmLoader.prototype.load = function () {
+ if (defined(this._promise)) {
+ return this._promise;
+ }
+
+ this._state = ResourceLoaderState.LOADING;
+ this._promise = loadResources(this);
+ return this._promise;
+};
+
+function gatherUsedTextureIds(gpmExtension) {
+ // Gather the used textures
+ const textureIds = {};
+ const ppeTextures = gpmExtension.ppeTextures;
+ if (defined(ppeTextures)) {
+ for (let i = 0; i < ppeTextures.length; i++) {
+ const ppeTexture = ppeTextures[i];
+ // The texture is a valid textureInfo.
+ textureIds[ppeTexture.index] = ppeTexture;
+ }
+ }
+ return textureIds;
+}
+
+function loadTextures(meshPrimitiveGpmLoader) {
+ let textureIds;
+ if (defined(meshPrimitiveGpmLoader._extension)) {
+ textureIds = gatherUsedTextureIds(meshPrimitiveGpmLoader._extension);
+ }
+
+ const gltf = meshPrimitiveGpmLoader._gltf;
+ const gltfResource = meshPrimitiveGpmLoader._gltfResource;
+ const baseResource = meshPrimitiveGpmLoader._baseResource;
+ const supportedImageFormats = meshPrimitiveGpmLoader._supportedImageFormats;
+ const frameState = meshPrimitiveGpmLoader._frameState;
+ const asynchronous = meshPrimitiveGpmLoader._asynchronous;
+
+ // Load the textures
+ const texturePromises = [];
+ for (const textureId in textureIds) {
+ if (textureIds.hasOwnProperty(textureId)) {
+ const textureLoader = ResourceCache.getTextureLoader({
+ gltf: gltf,
+ textureInfo: textureIds[textureId],
+ gltfResource: gltfResource,
+ baseResource: baseResource,
+ supportedImageFormats: supportedImageFormats,
+ frameState: frameState,
+ asynchronous: asynchronous,
+ });
+ meshPrimitiveGpmLoader._textureLoaders.push(textureLoader);
+ meshPrimitiveGpmLoader._textureIds.push(textureId);
+ texturePromises.push(textureLoader.load());
+ }
+ }
+
+ return Promise.all(texturePromises);
+}
+
+/**
+ * A static mapping from PPE texture property identifier keys
+ * to `MetadataSchema` instances. This is used to create each
+ * schema (with a certain structure) only ONCE in
+ * obtainPpeTexturesMetadataSchema
+ *
+ * @private
+ */
+GltfMeshPrimitiveGpmLoader.ppeTexturesMetadataSchemaCache = new Map();
+
+/**
+ * Create the JSON description of a metadata class that treats
+ * the given PPE texture as a property texture property(!).
+ *
+ * @param {any} ppeTexture - The PPE texture
+ * @param {number} index - The index of the texture in the extension
+ * @returns The class JSON
+ */
+GltfMeshPrimitiveGpmLoader.prototype.createPpeTextureClassJson = function (
+ ppeTexture,
+ index
+) {
+ const traits = ppeTexture.traits;
+ const ppePropertyName = traits.source;
+
+ // XXX_UNCERTAINTY: The ppeTexture will have a structure
+ // like this:
+ //
+ //"ppeTextures" : [
+ // {
+ // "traits" : {
+ // "source" : "SIGZ",
+ // "min" : 0.0,
+ // "max" : 16.0
+ // },
+ // "index" : 2,
+ // "noData" : 255,
+ // "offset" : 0.0,
+ // "scale" : 0.06274509803921569,
+ // "texCoord" : 1
+ // },
+ //
+ // Note that in GPM 1.2d, the min/max should be part of the
+ // texture, but in the actual data (GPM 1.2i), they are in
+ // the traits (ppeMetadata). And there, they/ seem to denote
+ // the min/max values that actually appear in the texture.
+ // So they are integrated into the 'scale' factor here:
+ const min = traits.min ?? 0;
+ const max = traits.max ?? 255;
+ const minMaxScale = 255.0 / (max - min);
+ const offset = ppeTexture.offset;
+ const scale = ppeTexture.scale * minMaxScale;
+ const classJson = {
+ name: `PPE texture class ${index}`,
+ properties: {
+ [ppePropertyName]: {
+ name: "PPE",
+ type: "SCALAR",
+ componentType: "UINT8",
+ normalized: true,
+ offset: offset,
+ scale: scale,
+ },
+ },
+ };
+ return classJson;
+};
+
+/**
+ * Returns the `MetadataSchema` for the PPE textures in this instance.
+ *
+ * This method will return a (statically/globally) cached metadata
+ * schema that reflects the structure of the PPE textures in this
+ * instance, creating and caching it if necessary.
+ *
+ * For details on the cache key, see `collectPpeTexturePropertyIdentifiers`
+ *
+ * @returns The `MetadataSchema`
+ */
+GltfMeshPrimitiveGpmLoader.prototype.obtainPpeTexturesMetadataSchema = function () {
+ const ppeTexturePropertyIdentifiers = this.collectPpeTexturePropertyIdentifiers();
+ const key = ppeTexturePropertyIdentifiers.toString();
+ let ppeTexturesMetadataSchema = GltfMeshPrimitiveGpmLoader.ppeTexturesMetadataSchemaCache.get(
+ key
+ );
+ if (defined(ppeTexturesMetadataSchema)) {
+ // XXX_UNCERTAINTY Debug log
+ //console.log(`Using cached schema for GPM PPE textures with key ${key}`);
+ return ppeTexturesMetadataSchema;
+ }
+
+ // XXX_UNCERTAINTY Debug log - if caching works, this should be printed only ONCE!
+ console.log(`Creating schema for GPM PPE textures with key ${key}`);
+ const schemaId = `PPE_TEXTURE_SCHEMA_${GltfMeshPrimitiveGpmLoader.ppeTexturesMetadataSchemaCache.size}`;
+ const ppeTexturesMetadataSchemaJson = {
+ id: schemaId,
+ classes: {},
+ };
+
+ const extension = this._extension;
+ if (defined(extension.ppeTextures)) {
+ for (let i = 0; i < extension.ppeTextures.length; i++) {
+ const ppeTexture = extension.ppeTextures[i];
+ const classId = `ppeTexture_${i}`;
+ const classJson = this.createPpeTextureClassJson(ppeTexture, i);
+ ppeTexturesMetadataSchemaJson.classes[classId] = classJson;
+ }
+ }
+
+ ppeTexturesMetadataSchema = MetadataSchema.fromJson(
+ ppeTexturesMetadataSchemaJson
+ );
+ GltfMeshPrimitiveGpmLoader.ppeTexturesMetadataSchemaCache.set(
+ key,
+ ppeTexturesMetadataSchema
+ );
+ return ppeTexturesMetadataSchema;
+};
+
+/**
+ * Creates an array of strings that serve as identifiers for PPE textures.
+ *
+ * Each glTF may define multiple `ppeTexture` objects within the
+ * `NGA_gpm_local` extensions. Each of these textures corresponds
+ * to one 'property texture property(!)' in a metadata schema.
+ *
+ * This method will create an array where each element is a (JSON)
+ * string representation of the parts of a GPM PPE texture definition
+ * that are relevant for distinguishing two PPE textures in terms
+ * of their structure within a `StructuralMetadata`.
+ *
+ * @returns The identifiers
+ */
+GltfMeshPrimitiveGpmLoader.prototype.collectPpeTexturePropertyIdentifiers = function () {
+ const extension = this._extension;
+ const ppeTexturePropertyIdentifiers = [];
+ if (defined(extension.ppeTextures)) {
+ for (let i = 0; i < extension.ppeTextures.length; i++) {
+ const ppeTexture = extension.ppeTextures[i];
+ // The following will create an identifier that can be used
+ // to define two PPE textures as "representing the same
+ // property texture property" within a structural metadata
+ // schema.
+ const classJson = this.createPpeTextureClassJson(ppeTexture, i);
+ const ppeTexturePropertyIdentifier = JSON.stringify(classJson);
+ ppeTexturePropertyIdentifiers.push(ppeTexturePropertyIdentifier);
+ }
+ }
+ return ppeTexturePropertyIdentifiers;
+};
+
+/**
+ * Processes the resource until it becomes ready.
+ *
+ * @param {FrameState} frameState The frame state.
+ * @private
+ */
+GltfMeshPrimitiveGpmLoader.prototype.process = function (frameState) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.object("frameState", frameState);
+ //>>includeEnd('debug');
+
+ if (this._state === ResourceLoaderState.READY) {
+ return true;
+ }
+
+ if (this._state !== ResourceLoaderState.LOADED) {
+ return false;
+ }
+
+ const textureLoaders = this._textureLoaders;
+ const textureLoadersLength = textureLoaders.length;
+ let ready = true;
+ for (let i = 0; i < textureLoadersLength; ++i) {
+ const textureLoader = textureLoaders[i];
+ const textureReady = textureLoader.process(frameState);
+ ready = ready && textureReady;
+ }
+
+ if (!ready) {
+ return false;
+ }
+
+ const textures = {};
+ for (let i = 0; i < this._textureIds.length; ++i) {
+ const textureId = this._textureIds[i];
+ const textureLoader = textureLoaders[i];
+ if (!textureLoader.isDestroyed()) {
+ textures[textureId] = textureLoader.texture;
+ }
+ }
+
+ const ppeTexturesMetadataSchema = this.obtainPpeTexturesMetadataSchema();
+ const extension = this._extension;
+ const propertyTextures = [];
+ if (defined(extension.ppeTextures)) {
+ for (let i = 0; i < extension.ppeTextures.length; i++) {
+ const ppeTexture = extension.ppeTextures[i];
+ const classId = `ppeTexture_${i}`;
+ const traits = ppeTexture.traits;
+ const ppePropertyName = traits.source;
+ const metadataClass = ppeTexturesMetadataSchema.classes[classId];
+
+ // XXX_UNCERTAINTY Debug log
+ //console.log(
+ // `Creating property texture with class ${classId} and property ${ppePropertyName}`
+ //);
+
+ const ppeTextureAsPropertyTexture = {
+ class: classId,
+ properties: {
+ [ppePropertyName]: {
+ index: ppeTexture.index,
+ texCoord: ppeTexture.texCoord,
+ },
+ },
+ };
+ propertyTextures.push(
+ new PropertyTexture({
+ id: i,
+ name: ppeTexture.name,
+ propertyTexture: ppeTextureAsPropertyTexture,
+ class: metadataClass,
+ textures: textures,
+ })
+ );
+ }
+ }
+
+ const structuralMetadata = new StructuralMetadata({
+ schema: ppeTexturesMetadataSchema,
+ propertyTables: [],
+ propertyTextures: propertyTextures,
+ propertyAttributes: [],
+ statistics: extension.statistics,
+ extras: extension.extras,
+ extensions: extension.extensions,
+ });
+ this._structuralMetadata = structuralMetadata;
+
+ this._state = ResourceLoaderState.READY;
+ return true;
+};
+
+function unloadTextures(meshPrimitiveGpmLoader) {
+ const textureLoaders = meshPrimitiveGpmLoader._textureLoaders;
+ const textureLoadersLength = textureLoaders.length;
+ for (let i = 0; i < textureLoadersLength; ++i) {
+ ResourceCache.unload(textureLoaders[i]);
+ }
+ meshPrimitiveGpmLoader._textureLoaders.length = 0;
+ meshPrimitiveGpmLoader._textureIds.length = 0;
+}
+
+/**
+ * Unloads the resource.
+ * @private
+ */
+GltfMeshPrimitiveGpmLoader.prototype.unload = function () {
+ unloadTextures(this);
+ this._structuralMetadata = undefined;
+};
+
+export default GltfMeshPrimitiveGpmLoader;
diff --git a/packages/engine/Source/Scene/Model/Model.js b/packages/engine/Source/Scene/Model/Model.js
index e5415a11587c..7d481d2088d1 100644
--- a/packages/engine/Source/Scene/Model/Model.js
+++ b/packages/engine/Source/Scene/Model/Model.js
@@ -1772,6 +1772,24 @@ Model.prototype.applyArticulations = function () {
this._sceneGraph.applyArticulations();
};
+/**
+ * XXX_TODO_COMMENT
+ *
+ * @exception {DeveloperError} The model is not loaded. Use Model.readyEvent or wait for Model.ready to be true.
+ */
+Model.prototype.getExtension = function (extensionName) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.string("extensionName", extensionName);
+ if (!this._ready) {
+ throw new DeveloperError(
+ "The model is not loaded. Use Model.readyEvent or wait for Model.ready to be true."
+ );
+ }
+ //>>includeEnd('debug');
+ const components = this._loader.components;
+ return components.extensions[extensionName];
+};
+
/**
* Marks the model's {@link Model#style} as dirty, which forces all features
* to re-evaluate the style in the next frame the model is visible.
diff --git a/packages/engine/Source/Scene/Model/Model3DTileContent.js b/packages/engine/Source/Scene/Model/Model3DTileContent.js
index a32206d3dba6..f2240619e744 100644
--- a/packages/engine/Source/Scene/Model/Model3DTileContent.js
+++ b/packages/engine/Source/Scene/Model/Model3DTileContent.js
@@ -152,6 +152,12 @@ Object.defineProperties(Model3DTileContent.prototype, {
},
});
+Model3DTileContent.prototype.getExtension = function (extensionName) {
+ const model = this._model;
+ const extension = model.getExtension(extensionName);
+ return extension;
+};
+
Model3DTileContent.prototype.getFeature = function (featureId) {
const model = this._model;
const featureTableId = model.featureTableId;
@@ -468,9 +474,11 @@ Model3DTileContent.prototype.pick = function (ray, frameState, result) {
};
function makeModelOptions(tileset, tile, content, additionalOptions) {
+ console.log("XXX KEEPING glTF in Model3DTileContent");
const mainOptions = {
cull: false, // The model is already culled by 3D Tiles
- releaseGltfJson: true, // Models are unique and will not benefit from caching so save memory
+ //releaseGltfJson: true, // Models are unique and will not benefit from caching so save memory
+ releaseGltfJson: false,
opaquePass: Pass.CESIUM_3D_TILE, // Draw opaque portions of the model during the 3D Tiles pass
modelMatrix: tile.computedTransform,
upAxis: tileset._modelUpAxis,
diff --git a/packages/engine/Source/Scene/ModelComponents.js b/packages/engine/Source/Scene/ModelComponents.js
index 42b3834c6db7..428e410dd8ac 100644
--- a/packages/engine/Source/Scene/ModelComponents.js
+++ b/packages/engine/Source/Scene/ModelComponents.js
@@ -1141,6 +1141,12 @@ function Components() {
* @private
*/
this.transform = Matrix4.clone(Matrix4.IDENTITY);
+
+ /**
+ * A mapping from extension names like `"EXT_example_extension"` to
+ * the object that was created from the extension input
+ */
+ this.extensions = {};
}
/**
From 7e1479105782cf4b385acdbe4b877abe1aa1d14b Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Thu, 19 Sep 2024 13:49:18 +0200
Subject: [PATCH 04/38] Move loaders to extension directory
---
packages/engine/Source/Scene/GltfLoader.js | 4 +--
.../Extensions/Gpm}/GltfGpmLoader.js | 26 +++++++++----------
.../Gpm}/GltfMeshPrimitiveGpmLoader.js | 18 ++++++-------
3 files changed, 24 insertions(+), 24 deletions(-)
rename packages/engine/Source/Scene/{ => Model/Extensions/Gpm}/GltfGpmLoader.js (90%)
rename packages/engine/Source/Scene/{ => Model/Extensions/Gpm}/GltfMeshPrimitiveGpmLoader.js (96%)
diff --git a/packages/engine/Source/Scene/GltfLoader.js b/packages/engine/Source/Scene/GltfLoader.js
index 490cbfb087af..bb25a498d4d1 100644
--- a/packages/engine/Source/Scene/GltfLoader.js
+++ b/packages/engine/Source/Scene/GltfLoader.js
@@ -29,8 +29,8 @@ import ResourceCache from "./ResourceCache.js";
import ResourceLoader from "./ResourceLoader.js";
import SupportedImageFormats from "./SupportedImageFormats.js";
import VertexAttributeSemantic from "./VertexAttributeSemantic.js";
-import GltfGpmLoader from "./GltfGpmLoader.js";
-import GltfMeshPrimitiveGpmLoader from "./GltfMeshPrimitiveGpmLoader.js";
+import GltfGpmLoader from "./Model/Extensions/Gpm/GltfGpmLoader.js";
+import GltfMeshPrimitiveGpmLoader from "./Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js";
const {
Attribute,
diff --git a/packages/engine/Source/Scene/GltfGpmLoader.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
similarity index 90%
rename from packages/engine/Source/Scene/GltfGpmLoader.js
rename to packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
index 4fe1cf50c46b..520a96b44769 100644
--- a/packages/engine/Source/Scene/GltfGpmLoader.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
@@ -1,16 +1,16 @@
-import Cartesian3 from "../Core/Cartesian3.js";
-import Check from "../Core/Check.js";
-import defaultValue from "../Core/defaultValue.js";
-import defined from "../Core/defined.js";
-import Matrix3 from "../Core/Matrix3.js";
-import AnchorPointDirect from "./Model/Extensions/Gpm/AnchorPointDirect.js";
-import AnchorPointIndirect from "./Model/Extensions/Gpm/AnchorPointIndirect.js";
-import CorrelationGroup from "./Model/Extensions/Gpm/CorrelationGroup.js";
-import GltfGpmLocal from "./Model/Extensions/Gpm/GltfGpmLocal.js";
-import Spdcf from "./Model/Extensions/Gpm/Spdcf.js";
-import StorageType from "./Model/Extensions/Gpm/StorageType.js";
-import ResourceLoader from "./ResourceLoader.js";
-import ResourceLoaderState from "./ResourceLoaderState.js";
+import Cartesian3 from "../../../../Core/Cartesian3.js";
+import Check from "../../../../Core/Check.js";
+import defaultValue from "../../../../Core/defaultValue.js";
+import defined from "../../../../Core/defined.js";
+import Matrix3 from "../../../../Core/Matrix3.js";
+import ResourceLoader from "./../../../ResourceLoader.js";
+import ResourceLoaderState from "./../../../ResourceLoaderState.js";
+import AnchorPointDirect from "./AnchorPointDirect.js";
+import AnchorPointIndirect from "./AnchorPointIndirect.js";
+import CorrelationGroup from "./CorrelationGroup.js";
+import GltfGpmLocal from "./GltfGpmLocal.js";
+import Spdcf from "./Spdcf.js";
+import StorageType from "./StorageType.js";
/**
* Loads glTF NGA_gpm_local from the root of a glTF object
diff --git a/packages/engine/Source/Scene/GltfMeshPrimitiveGpmLoader.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
similarity index 96%
rename from packages/engine/Source/Scene/GltfMeshPrimitiveGpmLoader.js
rename to packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
index 724b1d8b1a47..0668183ea0f7 100644
--- a/packages/engine/Source/Scene/GltfMeshPrimitiveGpmLoader.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
@@ -1,12 +1,12 @@
-import Check from "../Core/Check.js";
-import defaultValue from "../Core/defaultValue.js";
-import defined from "../Core/defined.js";
-import ResourceCache from "./ResourceCache.js";
-import ResourceLoader from "./ResourceLoader.js";
-import ResourceLoaderState from "./ResourceLoaderState.js";
-import PropertyTexture from "./PropertyTexture.js";
-import StructuralMetadata from "./StructuralMetadata.js";
-import MetadataSchema from "./MetadataSchema.js";
+import Check from "../../../../Core/Check.js";
+import defaultValue from "../../../../Core/defaultValue.js";
+import defined from "../../../../Core/defined.js";
+import ResourceCache from "../../../ResourceCache.js";
+import ResourceLoader from "../../../ResourceLoader.js";
+import ResourceLoaderState from "../../../ResourceLoaderState.js";
+import PropertyTexture from "../../../PropertyTexture.js";
+import StructuralMetadata from "../../../StructuralMetadata.js";
+import MetadataSchema from "../../../MetadataSchema.js";
/**
* Loads glTF NGA_gpm_local from a glTF mesh primitive.
From 6ee73444dbe75acd6a9b7e1450af023c4a297ec8 Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Thu, 19 Sep 2024 15:16:48 +0200
Subject: [PATCH 05/38] Added implementation note in GltfGpmLoader
---
.../Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
index 520a96b44769..3091184142a3 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
@@ -19,6 +19,13 @@ import StorageType from "./StorageType.js";
*
* Implementation note: This is an experimental implementation.
*
+ * TODO This implements ResourceLoader, even though it does not really
+ * load other resources (in contrast to GltfMeshPrimitiveGpmLoader,
+ * which loads textures). Parsing the JSON into a GltfGpmLocal
+ * could be done directly (synchronously in the GltfLoader class).
+ * But it should be carved out into a dedicated class, regardless
+ * of how this is eventually USED from the GltfLoader.
+ *
* @alias GltfGpmLoader
* @constructor
* @augments ResourceLoader
From c2a064c9bb2ebd7ab610f683a7dadc511fd7ae61 Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Thu, 19 Sep 2024 15:17:18 +0200
Subject: [PATCH 06/38] Fix handling of min, max, offset, scale for PPE
textures
---
.../Gpm/GltfMeshPrimitiveGpmLoader.js | 34 +++++++++++--------
1 file changed, 20 insertions(+), 14 deletions(-)
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
index 0668183ea0f7..c97ae55d7c61 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
@@ -224,8 +224,7 @@ GltfMeshPrimitiveGpmLoader.prototype.createPpeTextureClassJson = function (
const traits = ppeTexture.traits;
const ppePropertyName = traits.source;
- // XXX_UNCERTAINTY: The ppeTexture will have a structure
- // like this:
+ // The ppeTexture will have a structure like this:
//
//"ppeTextures" : [
// {
@@ -241,16 +240,16 @@ GltfMeshPrimitiveGpmLoader.prototype.createPpeTextureClassJson = function (
// "texCoord" : 1
// },
//
- // Note that in GPM 1.2d, the min/max should be part of the
- // texture, but in the actual data (GPM 1.2i), they are in
- // the traits (ppeMetadata). And there, they/ seem to denote
- // the min/max values that actually appear in the texture.
- // So they are integrated into the 'scale' factor here:
- const min = traits.min ?? 0;
- const max = traits.max ?? 255;
- const minMaxScale = 255.0 / (max - min);
- const offset = ppeTexture.offset;
- const scale = ppeTexture.scale * minMaxScale;
+ // This is translated into a single class property here, that defines
+ // the structure of the property texture property.
+ //
+ // Given that `offset` and `scale` may only be applied to integer
+ // property values when they are `normalized`, the values will be
+ // declared as `normalized` here.
+ // The and the normalization factor will later have to be
+ // cancelled out, when integrating the `scale` into the
+ // actual property texture property. In the property texture
+ // property, the `scale` has to be multiplied by 255.
const classJson = {
name: `PPE texture class ${index}`,
properties: {
@@ -259,8 +258,8 @@ GltfMeshPrimitiveGpmLoader.prototype.createPpeTextureClassJson = function (
type: "SCALAR",
componentType: "UINT8",
normalized: true,
- offset: offset,
- scale: scale,
+ min: traits.min,
+ max: traits.max,
},
},
};
@@ -407,12 +406,19 @@ GltfMeshPrimitiveGpmLoader.prototype.process = function (frameState) {
// `Creating property texture with class ${classId} and property ${ppePropertyName}`
//);
+ // The class property has been declared as `normalized`, so
+ // that `offset` and `scale` can be applied. The normalization
+ // factor has to be cancelled out here, by multiplying the
+ // `scale` with 255.
+ const scale = ppeTexture.scale * 255.0;
const ppeTextureAsPropertyTexture = {
class: classId,
properties: {
[ppePropertyName]: {
index: ppeTexture.index,
texCoord: ppeTexture.texCoord,
+ offset: ppeTexture.offset,
+ scale: scale,
},
},
};
From 50b072702973c8ca5b2dc39476509331b44db5e1 Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Sat, 21 Sep 2024 17:27:19 +0200
Subject: [PATCH 07/38] Enable releaseGltfJson
---
packages/engine/Source/Scene/Model/Model3DTileContent.js | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/packages/engine/Source/Scene/Model/Model3DTileContent.js b/packages/engine/Source/Scene/Model/Model3DTileContent.js
index f2240619e744..1a1b8a1aceaf 100644
--- a/packages/engine/Source/Scene/Model/Model3DTileContent.js
+++ b/packages/engine/Source/Scene/Model/Model3DTileContent.js
@@ -474,11 +474,9 @@ Model3DTileContent.prototype.pick = function (ray, frameState, result) {
};
function makeModelOptions(tileset, tile, content, additionalOptions) {
- console.log("XXX KEEPING glTF in Model3DTileContent");
const mainOptions = {
cull: false, // The model is already culled by 3D Tiles
- //releaseGltfJson: true, // Models are unique and will not benefit from caching so save memory
- releaseGltfJson: false,
+ releaseGltfJson: true, // Models are unique and will not benefit from caching so save memory
opaquePass: Pass.CESIUM_3D_TILE, // Draw opaque portions of the model during the 3D Tiles pass
modelMatrix: tile.computedTransform,
upAxis: tileset._modelUpAxis,
From cac091f95a14e28d762c38b2848873309f5b7ef7 Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Sat, 21 Sep 2024 17:27:54 +0200
Subject: [PATCH 08/38] Let GltfGpmLoader not extend ResourceLoader
---
packages/engine/Source/Scene/GltfLoader.js | 36 +-
.../Model/Extensions/Gpm/GltfGpmLoader.js | 372 ++++++++----------
2 files changed, 167 insertions(+), 241 deletions(-)
diff --git a/packages/engine/Source/Scene/GltfLoader.js b/packages/engine/Source/Scene/GltfLoader.js
index bb25a498d4d1..d7abc6d3fee0 100644
--- a/packages/engine/Source/Scene/GltfLoader.js
+++ b/packages/engine/Source/Scene/GltfLoader.js
@@ -262,7 +262,6 @@ function GltfLoader(options) {
this._geometryLoaders = [];
this._geometryCallbacks = [];
this._structuralMetadataLoader = undefined;
- this._gpmLoader = undefined;
this._meshPrimitiveGpmLoader = undefined;
this._loadResourcesPromise = undefined;
this._resourcesLoaded = false;
@@ -475,17 +474,6 @@ function processLoaders(loader, frameState) {
ready = ready && metadataReady;
}
- const gpmLoader = loader._gpmLoader;
- if (defined(gpmLoader)) {
- const gpmReady = gpmLoader.process(frameState);
- if (gpmReady) {
- // XXX
- console.log("Got GPM data, storing ", gpmLoader._gltfGpmLocal);
- loader._components.extensions["NGA_gpm_local"] = gpmLoader._gltfGpmLocal;
- }
- ready = ready && gpmReady;
- }
-
const meshPrimitiveGpmLoader = loader._meshPrimitiveGpmLoader;
if (defined(meshPrimitiveGpmLoader)) {
const metadataReady = meshPrimitiveGpmLoader.process(frameState);
@@ -2480,18 +2468,6 @@ async function loadStructuralMetadata(
return structuralMetadataLoader.load();
}
-async function loadGpm(loader, gltf, extension) {
- const gpmLoader = new GltfGpmLoader({
- gltf: gltf,
- extension: extension,
- gltfResource: loader._gltfResource,
- baseResource: loader._baseResource,
- asynchronous: loader._asynchronous,
- });
- loader._gpmLoader = gpmLoader;
- return gpmLoader.load();
-}
-
async function loadMeshPrimitiveGpm(loader, gltf, extension, frameState) {
const meshPrimitiveGpmLoader = new GltfMeshPrimitiveGpmLoader({
gltf: gltf,
@@ -2738,8 +2714,8 @@ function parse(loader, frameState) {
const gpmExtension = extensions.NGA_gpm_local;
if (defined(gpmExtension)) {
console.log("Loading GPM from root");
- const promise = loadGpm(loader, gltf, gpmExtension);
- loader._loaderPromises.push(promise);
+ const gltfGpmLocal = GltfGpmLoader.load(gpmExtension);
+ loader._components.extensions["NGA_gpm_local"] = gltfGpmLocal;
}
// Load NGA_gpm_local from mesh primitives
@@ -2831,13 +2807,6 @@ function unloadStructuralMetadata(loader) {
}
}
-function unloadGpm(loader) {
- if (defined(loader._gpmLoader) && !loader._gpmLoader.isDestroyed()) {
- loader._gpmLoader.destroy();
- loader._gpmLoader = undefined;
- }
-}
-
function unloadMeshPrimitiveGpm(loader) {
if (
defined(loader._meshPrimitiveGpmLoader) &&
@@ -2871,7 +2840,6 @@ GltfLoader.prototype.unload = function () {
unloadGeometry(this);
unloadGeneratedAttributes(this);
unloadStructuralMetadata(this);
- unloadGpm(this);
unloadMeshPrimitiveGpm(this);
this._components = undefined;
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
index 3091184142a3..c3a1a0c0bbb9 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
@@ -1,10 +1,7 @@
import Cartesian3 from "../../../../Core/Cartesian3.js";
import Check from "../../../../Core/Check.js";
-import defaultValue from "../../../../Core/defaultValue.js";
-import defined from "../../../../Core/defined.js";
+import DeveloperError from "../../../../Core/DeveloperError.js";
import Matrix3 from "../../../../Core/Matrix3.js";
-import ResourceLoader from "./../../../ResourceLoader.js";
-import ResourceLoaderState from "./../../../ResourceLoaderState.js";
import AnchorPointDirect from "./AnchorPointDirect.js";
import AnchorPointIndirect from "./AnchorPointIndirect.js";
import CorrelationGroup from "./CorrelationGroup.js";
@@ -15,110 +12,19 @@ import StorageType from "./StorageType.js";
/**
* Loads glTF NGA_gpm_local from the root of a glTF object
*
- * Implements the {@link ResourceLoader} interface.
- *
* Implementation note: This is an experimental implementation.
*
- * TODO This implements ResourceLoader, even though it does not really
- * load other resources (in contrast to GltfMeshPrimitiveGpmLoader,
- * which loads textures). Parsing the JSON into a GltfGpmLocal
- * could be done directly (synchronously in the GltfLoader class).
- * But it should be carved out into a dedicated class, regardless
- * of how this is eventually USED from the GltfLoader.
- *
* @alias GltfGpmLoader
* @constructor
- * @augments ResourceLoader
*
* @param {object} options Object with the following properties:
* @param {object} options.gltf The glTF JSON.
* @param {string} [options.extension] The NGA_gpm_local
extension object.
- * @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
- * @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
- * @param {string} [options.cacheKey] The cache key of the resource.
- * @param {boolean} [options.asynchronous=true] Determines if WebGL resource creation will be spread out over several frames or block until all WebGL resources are created.
*
* @private
* @experimental This feature is subject to change without Cesium's standard deprecation policy.
*/
-function GltfGpmLoader(options) {
- options = defaultValue(options, defaultValue.EMPTY_OBJECT);
- const gltf = options.gltf;
- const extension = options.extension;
- const gltfResource = options.gltfResource;
- const baseResource = options.baseResource;
- const cacheKey = options.cacheKey;
- const asynchronous = defaultValue(options.asynchronous, true);
-
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("options.gltf", gltf);
- Check.typeOf.object("options.extension", extension);
- Check.typeOf.object("options.gltfResource", gltfResource);
- Check.typeOf.object("options.baseResource", baseResource);
- //>>includeEnd('debug');
-
- this._gltfResource = gltfResource;
- this._baseResource = baseResource;
- this._gltf = gltf;
- this._extension = extension;
- this._cacheKey = cacheKey;
- this._asynchronous = asynchronous;
- this._gltfGpmLocal = undefined;
-
- // Immediately go into the "LOADED" state, since there
- // are no resources to wait for
- this._state = ResourceLoaderState.LOADED;
- this._promise = undefined;
-}
-
-if (defined(Object.create)) {
- GltfGpmLoader.prototype = Object.create(ResourceLoader.prototype);
- GltfGpmLoader.prototype.constructor = GltfGpmLoader;
-}
-
-Object.defineProperties(GltfGpmLoader.prototype, {
- /**
- * The cache key of the resource.
- *
- * @memberof GltfGpmLoader.prototype
- *
- * @type {string}
- * @readonly
- * @private
- */
- cacheKey: {
- get: function () {
- return this._cacheKey;
- },
- },
- /**
- * The parsed GltfGpmLocal object
- *
- * @memberof GltfGpmLoader.prototype
- *
- * @type {GltfGpmLocal}
- * @readonly
- * @private
- */
- gltfGpmLocal: {
- get: function () {
- return this._gltfGpmLocal;
- },
- },
-});
-
-/**
- * Loads the resource.
- * @returns {Promise} A promise which resolves to the loader when the resource loading is completed.
- * @private
- */
-GltfGpmLoader.prototype.load = function () {
- if (defined(this._promise)) {
- return this._promise;
- }
- this._promise = Promise.resolve(this);
- return this._promise;
-};
+function GltfGpmLoader() {}
/**
* Creates a Matrix3 that describes a covariance matrix (which is
@@ -144,135 +50,187 @@ function createCovarianceMatrixFromUpperTriangle(array) {
}
/**
- * Processes the resource until it becomes ready.
+ * Creates an `AnchorPointDirect` from the given JSON representation
*
- * @param {FrameState} frameState The frame state.
+ * @param {object} anchorPointDirectJson The input JSON
+ * @returns The `AnchorPointDirect`
+ */
+function createAnchorPointDirect(anchorPointDirectJson) {
+ const position = Cartesian3.fromArray(
+ anchorPointDirectJson.position,
+ 0,
+ new Cartesian3()
+ );
+ const adjustmentParams = Cartesian3.fromArray(
+ anchorPointDirectJson.adjustmentParams,
+ 0,
+ new Cartesian3()
+ );
+ const anchorPointDirect = new AnchorPointDirect({
+ position: position,
+ adjustmentParams: adjustmentParams,
+ });
+ return anchorPointDirect;
+}
+
+/**
+ * Creates an `AnchorPointIndirect` from the given JSON representation
+ *
+ * @param {object} anchorPointIndirectJson The input JSON
+ * @returns The `AnchorPointIndirect`
+ */
+function createAnchorPointIndirect(anchorPointIndirectJson) {
+ const position = Cartesian3.fromArray(
+ anchorPointIndirectJson.position,
+ 0,
+ new Cartesian3()
+ );
+ const adjustmentParams = Cartesian3.fromArray(
+ anchorPointIndirectJson.adjustmentParams,
+ 0,
+ new Cartesian3()
+ );
+ const covarianceMatrix = createCovarianceMatrixFromUpperTriangle(
+ anchorPointIndirectJson.covarianceMatrix
+ );
+ const anchorPointIndirect = new AnchorPointIndirect({
+ position: position,
+ adjustmentParams: adjustmentParams,
+ covarianceMatrix: covarianceMatrix,
+ });
+ return anchorPointIndirect;
+}
+
+/**
+ * Creates a `CorrelationGroup` from the given JSON representation
+ *
+ * @param {object} correlationGroupJson The input JSON
+ * @returns The `CorrelationGroup`
+ */
+function createCorrelationGroup(correlationGroupJson) {
+ const groupFlags = correlationGroupJson.groupFlags;
+ const rotationThetas = Cartesian3.fromArray(
+ correlationGroupJson.rotationThetas,
+ 0,
+ new Cartesian3()
+ );
+ const params = [];
+ for (const paramJson of correlationGroupJson.params) {
+ const param = new Spdcf({
+ A: paramJson.A,
+ alpha: paramJson.alpha,
+ beta: paramJson.beta,
+ T: paramJson.T,
+ });
+ params.push(param);
+ }
+ const correlationGroup = new CorrelationGroup({
+ groupFlags: groupFlags,
+ rotationThetas: rotationThetas,
+ params: params,
+ });
+ return correlationGroup;
+}
+
+/**
+ * Loads the GPM data from the given JSON that was found as the
+ * `NGA_gpm_local` extension object in the root of the glTF.
+ *
+ * @param {object} gltfGpmLocalJson The extension object
+ * @returns {GltfGpmLocal} The parsed object
* @private
+ * @throws DeveloperError When the given object is `undefined`
+ * or contains invalid structures
*/
-GltfGpmLoader.prototype.process = function (frameState) {
+GltfGpmLoader.load = function (gltfGpmLocalJson) {
//>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("frameState", frameState);
+ Check.typeOf.object("gltfGpmLocalJson", gltfGpmLocalJson);
//>>includeEnd('debug');
- if (this._state === ResourceLoaderState.READY) {
- return true;
+ const storageType = gltfGpmLocalJson.storageType;
+ if (storageType === StorageType.Direct) {
+ return GltfGpmLoader.loadDirect(gltfGpmLocalJson);
}
- if (this._state === ResourceLoaderState.FAILED) {
- return true;
+ if (storageType === StorageType.Indirect) {
+ return GltfGpmLoader.loadIndirect(gltfGpmLocalJson);
}
- if (this._state !== ResourceLoaderState.LOADED) {
- return false;
+ throw new DeveloperError(
+ `Invalid storage type in NGA_gpm_local - expected 'Direct' or 'Indirect', but found ${storageType}`
+ );
+};
+
+/**
+ * Loads the GPM data from the given JSON that was found as the
+ * `NGA_gpm_local` extension object in the root of the glTF,
+ * assuming that the `storageType` of the given object is
+ * `StorageType.Direct`.
+ *
+ * @param {object} gltfGpmLocalJson The extension object
+ * @returns {GltfGpmLocal} The parsed object
+ * @private
+ */
+GltfGpmLoader.loadDirect = function (gltfGpmLocalJson) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.object("gltfGpmLocalJson", gltfGpmLocalJson);
+ //>>includeEnd('debug');
+
+ const anchorPointsDirect = [];
+ const anchorPointsDirectJson = gltfGpmLocalJson.anchorPointsDirect;
+ for (const anchorPointDirectJson of anchorPointsDirectJson) {
+ const anchorPointDirect = createAnchorPointDirect(anchorPointDirectJson);
+ anchorPointsDirect.push(anchorPointDirect);
}
+ const covarianceDirect = createCovarianceMatrixFromUpperTriangle(
+ gltfGpmLocalJson.covarianceDirectUpperTriangle
+ );
- console.log("PARSE AND STORE HERE! ", this._extension);
+ const gltfGpmLocal = new GltfGpmLocal({
+ storageType: StorageType.Direct,
+ anchorPointsDirect: anchorPointsDirect,
+ covarianceDirect: covarianceDirect,
+ });
+ return gltfGpmLocal;
+};
- const extensionJson = this._extension;
+/**
+ * Loads the GPM data from the given JSON that was found as the
+ * `NGA_gpm_local` extension object in the root of the glTF,
+ * assuming that the `storageType` of the given object is
+ * `StorageType.Indirect`.
+ *
+ * @param {object} gltfGpmLocalJson The extension object
+ * @returns {GltfGpmLocal} The parsed object
+ * @private
+ */
+GltfGpmLoader.loadIndirect = function (gltfGpmLocalJson) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.object("gltfGpmLocalJson", gltfGpmLocalJson);
+ //>>includeEnd('debug');
- const storageType = extensionJson.storageType;
- if (storageType === StorageType.Direct) {
- const anchorPointsDirect = [];
- const anchorPointsDirectJson = extensionJson.anchorPointsDirect;
- for (const anchorPointDirectJson of anchorPointsDirectJson) {
- const position = Cartesian3.fromArray(
- anchorPointDirectJson.position,
- 0,
- new Cartesian3()
- );
- const adjustmentParams = Cartesian3.fromArray(
- anchorPointDirectJson.adjustmentParams,
- 0,
- new Cartesian3()
- );
- const anchorPointDirect = new AnchorPointDirect({
- position: position,
- adjustmentParams: adjustmentParams,
- });
- anchorPointsDirect.push(anchorPointDirect);
- }
- const covarianceDirect = createCovarianceMatrixFromUpperTriangle(
- extensionJson.covarianceDirectUpperTriangle
+ const anchorPointsIndirect = [];
+ const anchorPointsIndirectJson = gltfGpmLocalJson.anchorPointsIndirect;
+ for (const anchorPointIndirectJson of anchorPointsIndirectJson) {
+ const anchorPointIndirect = createAnchorPointIndirect(
+ anchorPointIndirectJson
);
-
- this._gltfGpmLocal = new GltfGpmLocal({
- storageType: storageType,
- anchorPointsDirect: anchorPointsDirect,
- covarianceDirect: covarianceDirect,
- });
- this._state = ResourceLoaderState.READY;
- return true;
+ anchorPointsIndirect.push(anchorPointIndirect);
}
- if (storageType === StorageType.Indirect) {
- const anchorPointsIndirect = [];
- const anchorPointsIndirectJson = extensionJson.anchorPointsIndirect;
- for (const anchorPointIndirectJson of anchorPointsIndirectJson) {
- const position = Cartesian3.fromArray(
- anchorPointIndirectJson.position,
- 0,
- new Cartesian3()
- );
- const adjustmentParams = Cartesian3.fromArray(
- anchorPointIndirectJson.adjustmentParams,
- 0,
- new Cartesian3()
- );
- const covarianceMatrix = createCovarianceMatrixFromUpperTriangle(
- anchorPointIndirectJson.covarianceMatrix
- );
- const anchorPointIndirect = new AnchorPointIndirect({
- position: position,
- adjustmentParams: adjustmentParams,
- covarianceMatrix: covarianceMatrix,
- });
- anchorPointsIndirect.push(anchorPointIndirect);
- }
- const intraTileCorrelationGroupsJson =
- extensionJson.intraTileCorrelationGroups;
- const intraTileCorrelationGroups = [];
+ const intraTileCorrelationGroupsJson =
+ gltfGpmLocalJson.intraTileCorrelationGroups;
+ const intraTileCorrelationGroups = [];
- for (const correlationGroupJson of intraTileCorrelationGroupsJson) {
- const groupFlags = correlationGroupJson.groupFlags;
- const rotationThetas = Cartesian3.fromArray(
- correlationGroupJson.rotationThetas,
- 0,
- new Cartesian3()
- );
- const params = [];
- for (const paramJson of correlationGroupJson.params) {
- const param = new Spdcf({
- A: paramJson.A,
- alpha: paramJson.alpha,
- beta: paramJson.beta,
- T: paramJson.T,
- });
- params.push(param);
- }
- const correlationGroup = new CorrelationGroup({
- groupFlags: groupFlags,
- rotationThetas: rotationThetas,
- params: params,
- });
- intraTileCorrelationGroups.push(correlationGroup);
- }
-
- this._gltfGpmLocal = new GltfGpmLocal({
- storageType: storageType,
- anchorPointsIndirect: anchorPointsIndirect,
- intraTileCorrelationGroups: intraTileCorrelationGroups,
- });
- this._state = ResourceLoaderState.READY;
- return true;
+ for (const correlationGroupJson of intraTileCorrelationGroupsJson) {
+ const correlationGroup = createCorrelationGroup(correlationGroupJson);
+ intraTileCorrelationGroups.push(correlationGroup);
}
- this._state = ResourceLoaderState.FAILED;
- return false;
-};
-/**
- * Unloads the resource.
- * @private
- */
-GltfGpmLoader.prototype.unload = function () {
- this._gltfGpmLocal = undefined;
+ const gltfGpmLocal = new GltfGpmLocal({
+ storageType: StorageType.Indirect,
+ anchorPointsIndirect: anchorPointsIndirect,
+ intraTileCorrelationGroups: intraTileCorrelationGroups,
+ });
+ return gltfGpmLocal;
};
export default GltfGpmLoader;
From 1cc38faedcf3772c804589a05150182d43a2fee1 Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Sat, 21 Sep 2024 17:28:06 +0200
Subject: [PATCH 09/38] Minor cleanup and comments
---
.../Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
index c97ae55d7c61..485caae1f808 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
@@ -246,10 +246,10 @@ GltfMeshPrimitiveGpmLoader.prototype.createPpeTextureClassJson = function (
// Given that `offset` and `scale` may only be applied to integer
// property values when they are `normalized`, the values will be
// declared as `normalized` here.
- // The and the normalization factor will later have to be
- // cancelled out, when integrating the `scale` into the
- // actual property texture property. In the property texture
- // property, the `scale` has to be multiplied by 255.
+ // The normalization factor will later have to be cancelled out,
+ // when integrating the `scale` into the actual property texture
+ // property. In the property texture property, the `scale` has to
+ // be multiplied by 255.
const classJson = {
name: `PPE texture class ${index}`,
properties: {
@@ -410,7 +410,7 @@ GltfMeshPrimitiveGpmLoader.prototype.process = function (frameState) {
// that `offset` and `scale` can be applied. The normalization
// factor has to be cancelled out here, by multiplying the
// `scale` with 255.
- const scale = ppeTexture.scale * 255.0;
+ const scale = (ppeTexture.scale ?? 1.0) * 255.0;
const ppeTextureAsPropertyTexture = {
class: classId,
properties: {
@@ -465,6 +465,8 @@ function unloadTextures(meshPrimitiveGpmLoader) {
*/
GltfMeshPrimitiveGpmLoader.prototype.unload = function () {
unloadTextures(this);
+ this._gltf = undefined;
+ this._extension = undefined;
this._structuralMetadata = undefined;
};
From 4e6d501af04672d5d339765049236877574a45fa Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Sat, 21 Sep 2024 18:06:28 +0200
Subject: [PATCH 10/38] Fix type checks
---
.../engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js | 2 +-
packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
index de255f5b6dd9..66d38ef40cb8 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
@@ -8,7 +8,7 @@ import Check from "../../../../Core/Check.js";
*/
function PpeMetadata(options) {
//>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("options.source", options.source);
+ Check.typeOf.string("options.source", options.source);
//>>includeEnd('debug');
this._min = options.min;
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
index 5214a6e34ac6..8b352956758d 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
@@ -13,7 +13,7 @@ import Check from "../../../../Core/Check.js";
function PpeTexture(options) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("options.traits", options.traits);
- Check.typeOf.object("options.index", options.index);
+ Check.typeOf.number.greaterThanOrEquals("options.index", options.index, 0);
//>>includeEnd('debug');
this._traits = options.traits;
From 9e7bfcf0aee24f1d84b23ac57fba20ab1a23ad28 Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Sat, 21 Sep 2024 18:06:50 +0200
Subject: [PATCH 11/38] Explicit conversion of PPE into structural metadata
---
.../Gpm/GltfMeshPrimitiveGpmLoader.js | 288 +++++++++++-------
1 file changed, 177 insertions(+), 111 deletions(-)
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
index 485caae1f808..e8d52cb72997 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
@@ -7,18 +7,20 @@ import ResourceLoaderState from "../../../ResourceLoaderState.js";
import PropertyTexture from "../../../PropertyTexture.js";
import StructuralMetadata from "../../../StructuralMetadata.js";
import MetadataSchema from "../../../MetadataSchema.js";
+import PpeTexture from "./PpeTexture.js";
+import PpeMetadata from "./PpeMetadata.js";
+import MeshPrimitiveGpmLocal from "./MeshPrimitiveGpmLocal.js";
/**
* Loads glTF NGA_gpm_local from a glTF mesh primitive.
*
* Implements the {@link ResourceLoader} interface.
*
- * Implementation note: This is an experimental implementation. It is based
- * on a GltfStructuralMetadataLoader, by removing everything that is not
- * related to property textures, and translating the "ppeTextures" of
- * the NGA_gpm_local extension into property texture properties. These will
- * be returned as part of a `StructuralMetadata` object, which may override
- * any `StructuralMetadata` that was read directly from the glTF.
+ * This loads the "ppeTextures" of the NGA_gpm_local extension of a mesh primitive
+ * and stores them in a `MeshPrimitiveGpmLocal` object.
+ *
+ * This object will be converted into a `StructuralMetadata` object, which may
+ * override any `StructuralMetadata` that was read directly from the glTF.
*
* @alias GltfMeshPrimitiveGpmLoader
* @constructor
@@ -67,6 +69,7 @@ function GltfMeshPrimitiveGpmLoader(options) {
this._asynchronous = asynchronous;
this._textureLoaders = [];
this._textureIds = [];
+ this._meshPrimitiveGpmLocal = undefined;
this._structuralMetadata = undefined;
this._state = ResourceLoaderState.UNLOADED;
this._promise = undefined;
@@ -110,30 +113,30 @@ Object.defineProperties(GltfMeshPrimitiveGpmLoader.prototype, {
},
});
-async function loadResources(loader) {
+GltfMeshPrimitiveGpmLoader.prototype.loadResources = async function () {
try {
- const texturesPromise = loadTextures(loader);
+ const texturesPromise = this.loadTextures();
await texturesPromise;
- if (loader.isDestroyed()) {
+ if (this.isDestroyed()) {
return;
}
- loader._gltf = undefined; // No longer need to hold onto the glTF
+ this._gltf = undefined; // No longer need to hold onto the glTF
- loader._state = ResourceLoaderState.LOADED;
- return loader;
+ this._state = ResourceLoaderState.LOADED;
+ return this;
} catch (error) {
- if (loader.isDestroyed()) {
+ if (this.isDestroyed()) {
return;
}
- loader.unload();
- loader._state = ResourceLoaderState.FAILED;
+ this.unload();
+ this._state = ResourceLoaderState.FAILED;
const errorMessage = "Failed to load GPM data";
- throw loader.getError(errorMessage, error);
+ throw this.getError(errorMessage, error);
}
-}
+};
/**
* Loads the resource.
@@ -146,7 +149,7 @@ GltfMeshPrimitiveGpmLoader.prototype.load = function () {
}
this._state = ResourceLoaderState.LOADING;
- this._promise = loadResources(this);
+ this._promise = this.loadResources(this);
return this._promise;
};
@@ -164,18 +167,18 @@ function gatherUsedTextureIds(gpmExtension) {
return textureIds;
}
-function loadTextures(meshPrimitiveGpmLoader) {
+GltfMeshPrimitiveGpmLoader.prototype.loadTextures = function () {
let textureIds;
- if (defined(meshPrimitiveGpmLoader._extension)) {
- textureIds = gatherUsedTextureIds(meshPrimitiveGpmLoader._extension);
+ if (defined(this._extension)) {
+ textureIds = gatherUsedTextureIds(this._extension);
}
- const gltf = meshPrimitiveGpmLoader._gltf;
- const gltfResource = meshPrimitiveGpmLoader._gltfResource;
- const baseResource = meshPrimitiveGpmLoader._baseResource;
- const supportedImageFormats = meshPrimitiveGpmLoader._supportedImageFormats;
- const frameState = meshPrimitiveGpmLoader._frameState;
- const asynchronous = meshPrimitiveGpmLoader._asynchronous;
+ const gltf = this._gltf;
+ const gltfResource = this._gltfResource;
+ const baseResource = this._baseResource;
+ const supportedImageFormats = this._supportedImageFormats;
+ const frameState = this._frameState;
+ const asynchronous = this._asynchronous;
// Load the textures
const texturePromises = [];
@@ -190,14 +193,14 @@ function loadTextures(meshPrimitiveGpmLoader) {
frameState: frameState,
asynchronous: asynchronous,
});
- meshPrimitiveGpmLoader._textureLoaders.push(textureLoader);
- meshPrimitiveGpmLoader._textureIds.push(textureId);
+ this._textureLoaders.push(textureLoader);
+ this._textureIds.push(textureId);
texturePromises.push(textureLoader.load());
}
}
return Promise.all(texturePromises);
-}
+};
/**
* A static mapping from PPE texture property identifier keys
@@ -217,7 +220,7 @@ GltfMeshPrimitiveGpmLoader.ppeTexturesMetadataSchemaCache = new Map();
* @param {number} index - The index of the texture in the extension
* @returns The class JSON
*/
-GltfMeshPrimitiveGpmLoader.prototype.createPpeTextureClassJson = function (
+GltfMeshPrimitiveGpmLoader.createPpeTextureClassJson = function (
ppeTexture,
index
) {
@@ -267,18 +270,24 @@ GltfMeshPrimitiveGpmLoader.prototype.createPpeTextureClassJson = function (
};
/**
- * Returns the `MetadataSchema` for the PPE textures in this instance.
+ * Returns the `MetadataSchema` for the PPE textures in the given
+ * `MeshPrimitiveGpmLocal` instance.
*
* This method will return a (statically/globally) cached metadata
- * schema that reflects the structure of the PPE textures in this
- * instance, creating and caching it if necessary.
+ * schema that reflects the structure of the PPE textures in the
+ * given instance, creating and caching it if necessary.
*
* For details on the cache key, see `collectPpeTexturePropertyIdentifiers`
*
+ * @param {MeshPrimitiveGpmLocal} meshPrimitiveGpmLocal The extension object
* @returns The `MetadataSchema`
*/
-GltfMeshPrimitiveGpmLoader.prototype.obtainPpeTexturesMetadataSchema = function () {
- const ppeTexturePropertyIdentifiers = this.collectPpeTexturePropertyIdentifiers();
+GltfMeshPrimitiveGpmLoader.obtainPpeTexturesMetadataSchema = function (
+ meshPrimitiveGpmLocal
+) {
+ const ppeTexturePropertyIdentifiers = GltfMeshPrimitiveGpmLoader.collectPpeTexturePropertyIdentifiers(
+ meshPrimitiveGpmLocal
+ );
const key = ppeTexturePropertyIdentifiers.toString();
let ppeTexturesMetadataSchema = GltfMeshPrimitiveGpmLoader.ppeTexturesMetadataSchemaCache.get(
key
@@ -297,14 +306,15 @@ GltfMeshPrimitiveGpmLoader.prototype.obtainPpeTexturesMetadataSchema = function
classes: {},
};
- const extension = this._extension;
- if (defined(extension.ppeTextures)) {
- for (let i = 0; i < extension.ppeTextures.length; i++) {
- const ppeTexture = extension.ppeTextures[i];
- const classId = `ppeTexture_${i}`;
- const classJson = this.createPpeTextureClassJson(ppeTexture, i);
- ppeTexturesMetadataSchemaJson.classes[classId] = classJson;
- }
+ const ppeTextures = meshPrimitiveGpmLocal.ppeTextures;
+ for (let i = 0; i < ppeTextures.length; i++) {
+ const ppeTexture = ppeTextures[i];
+ const classId = `ppeTexture_${i}`;
+ const classJson = GltfMeshPrimitiveGpmLoader.createPpeTextureClassJson(
+ ppeTexture,
+ i
+ );
+ ppeTexturesMetadataSchemaJson.classes[classId] = classJson;
}
ppeTexturesMetadataSchema = MetadataSchema.fromJson(
@@ -329,26 +339,98 @@ GltfMeshPrimitiveGpmLoader.prototype.obtainPpeTexturesMetadataSchema = function
* that are relevant for distinguishing two PPE textures in terms
* of their structure within a `StructuralMetadata`.
*
+ * @param {MeshPrimitiveGpmLocal} meshPrimitiveGpmLocal The extension object
* @returns The identifiers
*/
-GltfMeshPrimitiveGpmLoader.prototype.collectPpeTexturePropertyIdentifiers = function () {
- const extension = this._extension;
+GltfMeshPrimitiveGpmLoader.collectPpeTexturePropertyIdentifiers = function (
+ meshPrimitiveGpmLocal
+) {
const ppeTexturePropertyIdentifiers = [];
- if (defined(extension.ppeTextures)) {
- for (let i = 0; i < extension.ppeTextures.length; i++) {
- const ppeTexture = extension.ppeTextures[i];
- // The following will create an identifier that can be used
- // to define two PPE textures as "representing the same
- // property texture property" within a structural metadata
- // schema.
- const classJson = this.createPpeTextureClassJson(ppeTexture, i);
- const ppeTexturePropertyIdentifier = JSON.stringify(classJson);
- ppeTexturePropertyIdentifiers.push(ppeTexturePropertyIdentifier);
- }
+ const ppeTextures = meshPrimitiveGpmLocal.ppeTextures;
+ for (let i = 0; i < ppeTextures.length; i++) {
+ const ppeTexture = ppeTextures[i];
+ // The following will create an identifier that can be used
+ // to define two PPE textures as "representing the same
+ // property texture property" within a structural metadata
+ // schema.
+ const classJson = GltfMeshPrimitiveGpmLoader.createPpeTextureClassJson(
+ ppeTexture,
+ i
+ );
+ const ppeTexturePropertyIdentifier = JSON.stringify(classJson);
+ ppeTexturePropertyIdentifiers.push(ppeTexturePropertyIdentifier);
}
return ppeTexturePropertyIdentifiers;
};
+/**
+ * Converts the given `MeshPrimitiveGpmLocal` object into a `StructuralMetadata`
+ * object.
+ *
+ * This will translate the PPE textures from the given object into property
+ * texture properties. The schema will be created based on the the structure
+ * of the PPE textures.
+ *
+ * @param {MeshPrimitiveGpmLocal} meshPrimitiveGpmLocal The extension object
+ * @param {object} textures The mapping from texture ID to texture objects
+ * @returns The `StructuralMetadata` object
+ */
+GltfMeshPrimitiveGpmLoader.convertToStructuralMetadata = function (
+ meshPrimitiveGpmLocal,
+ textures
+) {
+ const propertyTextures = [];
+ const ppeTexturesMetadataSchema = GltfMeshPrimitiveGpmLoader.obtainPpeTexturesMetadataSchema(
+ meshPrimitiveGpmLocal
+ );
+ const ppeTextures = meshPrimitiveGpmLocal.ppeTextures;
+ for (let i = 0; i < ppeTextures.length; i++) {
+ const ppeTexture = ppeTextures[i];
+ const classId = `ppeTexture_${i}`;
+ const traits = ppeTexture.traits;
+ const ppePropertyName = traits.source;
+ const metadataClass = ppeTexturesMetadataSchema.classes[classId];
+
+ // XXX_UNCERTAINTY Debug log
+ //console.log(
+ // `Creating property texture with class ${classId} and property ${ppePropertyName}`
+ //);
+
+ // The class property has been declared as `normalized`, so
+ // that `offset` and `scale` can be applied. The normalization
+ // factor has to be cancelled out here, by multiplying the
+ // `scale` with 255.
+ const scale = (ppeTexture.scale ?? 1.0) * 255.0;
+ const ppeTextureAsPropertyTexture = {
+ class: classId,
+ properties: {
+ [ppePropertyName]: {
+ index: ppeTexture.index,
+ texCoord: ppeTexture.texCoord,
+ offset: ppeTexture.offset,
+ scale: scale,
+ },
+ },
+ };
+ propertyTextures.push(
+ new PropertyTexture({
+ id: i,
+ name: ppeTexture.name,
+ propertyTexture: ppeTextureAsPropertyTexture,
+ class: metadataClass,
+ textures: textures,
+ })
+ );
+ }
+ const structuralMetadata = new StructuralMetadata({
+ schema: ppeTexturesMetadataSchema,
+ propertyTables: [],
+ propertyTextures: propertyTextures,
+ propertyAttributes: [],
+ });
+ return structuralMetadata;
+};
+
/**
* Processes the resource until it becomes ready.
*
@@ -368,6 +450,8 @@ GltfMeshPrimitiveGpmLoader.prototype.process = function (frameState) {
return false;
}
+ // The standard process of loading textures
+ // (from GltfStructuralMetadataLoader)
const textureLoaders = this._textureLoaders;
const textureLoadersLength = textureLoaders.length;
let ready = true;
@@ -381,6 +465,8 @@ GltfMeshPrimitiveGpmLoader.prototype.process = function (frameState) {
return false;
}
+ // More of the standard process of loading textures
+ // (from GltfStructuralMetadataLoader)
const textures = {};
for (let i = 0; i < this._textureIds.length; ++i) {
const textureId = this._textureIds[i];
@@ -390,81 +476,61 @@ GltfMeshPrimitiveGpmLoader.prototype.process = function (frameState) {
}
}
- const ppeTexturesMetadataSchema = this.obtainPpeTexturesMetadataSchema();
+ // Convert the JSON representation of the `ppeTextures` that
+ // are found in the extensjon JSON into `PpeTexture` objects
+ const ppeTextures = [];
const extension = this._extension;
- const propertyTextures = [];
if (defined(extension.ppeTextures)) {
- for (let i = 0; i < extension.ppeTextures.length; i++) {
- const ppeTexture = extension.ppeTextures[i];
- const classId = `ppeTexture_${i}`;
- const traits = ppeTexture.traits;
- const ppePropertyName = traits.source;
- const metadataClass = ppeTexturesMetadataSchema.classes[classId];
-
- // XXX_UNCERTAINTY Debug log
- //console.log(
- // `Creating property texture with class ${classId} and property ${ppePropertyName}`
- //);
-
- // The class property has been declared as `normalized`, so
- // that `offset` and `scale` can be applied. The normalization
- // factor has to be cancelled out here, by multiplying the
- // `scale` with 255.
- const scale = (ppeTexture.scale ?? 1.0) * 255.0;
- const ppeTextureAsPropertyTexture = {
- class: classId,
- properties: {
- [ppePropertyName]: {
- index: ppeTexture.index,
- texCoord: ppeTexture.texCoord,
- offset: ppeTexture.offset,
- scale: scale,
- },
- },
- };
- propertyTextures.push(
- new PropertyTexture({
- id: i,
- name: ppeTexture.name,
- propertyTexture: ppeTextureAsPropertyTexture,
- class: metadataClass,
- textures: textures,
- })
- );
+ const ppeTexturesJson = extension.ppeTextures;
+ for (const ppeTextureJson of ppeTexturesJson) {
+ const traitsJson = ppeTextureJson.traits;
+ const traits = new PpeMetadata({
+ min: traitsJson.min,
+ max: traitsJson.max,
+ source: traitsJson.source,
+ });
+ const ppeTexture = new PpeTexture({
+ traits: traits,
+ noData: ppeTextureJson.noData,
+ offset: ppeTextureJson.offset,
+ scale: ppeTextureJson.scale,
+ index: ppeTextureJson.index,
+ texCoord: ppeTextureJson.texCoord,
+ });
+ ppeTextures.push(ppeTexture);
}
}
-
- const structuralMetadata = new StructuralMetadata({
- schema: ppeTexturesMetadataSchema,
- propertyTables: [],
- propertyTextures: propertyTextures,
- propertyAttributes: [],
- statistics: extension.statistics,
- extras: extension.extras,
- extensions: extension.extensions,
+ const meshPrimitiveGpmLocal = new MeshPrimitiveGpmLocal({
+ ppeTextures: ppeTextures,
});
+ this._meshPrimitiveGpmLocal = meshPrimitiveGpmLocal;
+
+ const structuralMetadata = GltfMeshPrimitiveGpmLoader.convertToStructuralMetadata(
+ meshPrimitiveGpmLocal,
+ textures
+ );
this._structuralMetadata = structuralMetadata;
this._state = ResourceLoaderState.READY;
return true;
};
-function unloadTextures(meshPrimitiveGpmLoader) {
- const textureLoaders = meshPrimitiveGpmLoader._textureLoaders;
+GltfMeshPrimitiveGpmLoader.prototype.unloadTextures = function () {
+ const textureLoaders = this._textureLoaders;
const textureLoadersLength = textureLoaders.length;
for (let i = 0; i < textureLoadersLength; ++i) {
ResourceCache.unload(textureLoaders[i]);
}
- meshPrimitiveGpmLoader._textureLoaders.length = 0;
- meshPrimitiveGpmLoader._textureIds.length = 0;
-}
+ this._textureLoaders.length = 0;
+ this._textureIds.length = 0;
+};
/**
* Unloads the resource.
* @private
*/
GltfMeshPrimitiveGpmLoader.prototype.unload = function () {
- unloadTextures(this);
+ this.unloadTextures();
this._gltf = undefined;
this._extension = undefined;
this._structuralMetadata = undefined;
From 5110166947f0cd46c7be4fdb37fb9a006bdfd95f Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Tue, 24 Sep 2024 22:36:46 +0200
Subject: [PATCH 12/38] Remove debug logs
---
packages/engine/Source/Scene/GltfLoader.js | 11 +++++++----
.../Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js | 9 ---------
2 files changed, 7 insertions(+), 13 deletions(-)
diff --git a/packages/engine/Source/Scene/GltfLoader.js b/packages/engine/Source/Scene/GltfLoader.js
index d7abc6d3fee0..c6733177bdd0 100644
--- a/packages/engine/Source/Scene/GltfLoader.js
+++ b/packages/engine/Source/Scene/GltfLoader.js
@@ -31,6 +31,7 @@ import SupportedImageFormats from "./SupportedImageFormats.js";
import VertexAttributeSemantic from "./VertexAttributeSemantic.js";
import GltfGpmLoader from "./Model/Extensions/Gpm/GltfGpmLoader.js";
import GltfMeshPrimitiveGpmLoader from "./Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js";
+import oneTimeWarning from "../Core/oneTimeWarning.js";
const {
Attribute,
@@ -478,8 +479,12 @@ function processLoaders(loader, frameState) {
if (defined(meshPrimitiveGpmLoader)) {
const metadataReady = meshPrimitiveGpmLoader.process(frameState);
if (metadataReady) {
- // XXX
- console.log("Overwriting structural metadata with GPM data");
+ if (defined(loader._components.structuralMetadata)) {
+ oneTimeWarning(
+ "structural-metadata-gpm",
+ "Structural metadata is replaced with GPM data"
+ );
+ }
loader._components.structuralMetadata =
meshPrimitiveGpmLoader.structuralMetadata;
}
@@ -2728,8 +2733,6 @@ function parse(loader, frameState) {
const primitiveExtensions = primitive.extensions;
const meshPrimitiveGpmExtension = primitiveExtensions.NGA_gpm_local;
if (defined(meshPrimitiveGpmExtension)) {
- // XXX
- console.log("Loading GPM from mesh primitive");
const promise = loadMeshPrimitiveGpm(
loader,
gltf,
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
index e8d52cb72997..c207a962a70c 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
@@ -293,13 +293,9 @@ GltfMeshPrimitiveGpmLoader.obtainPpeTexturesMetadataSchema = function (
key
);
if (defined(ppeTexturesMetadataSchema)) {
- // XXX_UNCERTAINTY Debug log
- //console.log(`Using cached schema for GPM PPE textures with key ${key}`);
return ppeTexturesMetadataSchema;
}
- // XXX_UNCERTAINTY Debug log - if caching works, this should be printed only ONCE!
- console.log(`Creating schema for GPM PPE textures with key ${key}`);
const schemaId = `PPE_TEXTURE_SCHEMA_${GltfMeshPrimitiveGpmLoader.ppeTexturesMetadataSchemaCache.size}`;
const ppeTexturesMetadataSchemaJson = {
id: schemaId,
@@ -391,11 +387,6 @@ GltfMeshPrimitiveGpmLoader.convertToStructuralMetadata = function (
const ppePropertyName = traits.source;
const metadataClass = ppeTexturesMetadataSchema.classes[classId];
- // XXX_UNCERTAINTY Debug log
- //console.log(
- // `Creating property texture with class ${classId} and property ${ppePropertyName}`
- //);
-
// The class property has been declared as `normalized`, so
// that `offset` and `scale` can be applied. The normalization
// factor has to be cancelled out here, by multiplying the
From 323f4f01afff34610875ea433c5705668ec1061e Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Tue, 24 Sep 2024 22:36:59 +0200
Subject: [PATCH 13/38] Additional type checks
---
.../Scene/Model/Extensions/Gpm/GltfGpmLoader.js | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
index c3a1a0c0bbb9..730aca143994 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
@@ -172,6 +172,14 @@ GltfGpmLoader.load = function (gltfGpmLocalJson) {
GltfGpmLoader.loadDirect = function (gltfGpmLocalJson) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("gltfGpmLocalJson", gltfGpmLocalJson);
+ Check.typeOf.object(
+ "gltfGpmLocalJson.anchorPointsDirect",
+ gltfGpmLocalJson.anchorPointsDirect
+ );
+ Check.typeOf.object(
+ "gltfGpmLocalJson.covarianceDirectUpperTriangle",
+ gltfGpmLocalJson.covarianceDirectUpperTriangle
+ );
//>>includeEnd('debug');
const anchorPointsDirect = [];
@@ -205,6 +213,14 @@ GltfGpmLoader.loadDirect = function (gltfGpmLocalJson) {
GltfGpmLoader.loadIndirect = function (gltfGpmLocalJson) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("gltfGpmLocalJson", gltfGpmLocalJson);
+ Check.typeOf.object(
+ "gltfGpmLocalJson.anchorPointsIndirect",
+ gltfGpmLocalJson.anchorPointsIndirect
+ );
+ Check.typeOf.object(
+ "gltfGpmLocalJson.intraTileCorrelationGroups",
+ gltfGpmLocalJson.intraTileCorrelationGroups
+ );
//>>includeEnd('debug');
const anchorPointsIndirect = [];
From 6326d40261ce405f5f6c4fe6a0bd901f1d3b988f Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Tue, 24 Sep 2024 22:37:18 +0200
Subject: [PATCH 14/38] Added JSDoc comment
---
packages/engine/Source/Scene/Model/Model.js | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/packages/engine/Source/Scene/Model/Model.js b/packages/engine/Source/Scene/Model/Model.js
index 7d481d2088d1..c68109d60937 100644
--- a/packages/engine/Source/Scene/Model/Model.js
+++ b/packages/engine/Source/Scene/Model/Model.js
@@ -1773,9 +1773,20 @@ Model.prototype.applyArticulations = function () {
};
/**
- * XXX_TODO_COMMENT
+ * Returns the object that was created for the given extension.
*
+ * The given name may be the name of a glTF extension, like `"EXT_example_extension"`.
+ * If the specified extension was present in the root of the underlying glTF asset,
+ * and a loder for the specified extension has processed the extension data, then
+ * this will return the model representation of the extension.
+ *
+ * @param {string} extensionName The name of the extension
+ * @returns The object, or `undefined`
* @exception {DeveloperError} The model is not loaded. Use Model.readyEvent or wait for Model.ready to be true.
+ *
+ * @private
+ * @experimental This feature is subject to change without Cesium's standard deprecation policy.
+ *
*/
Model.prototype.getExtension = function (extensionName) {
//>>includeStart('debug', pragmas.debug);
From eaf6112903870dc7553275d9ec9574a7b65303e4 Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Tue, 24 Sep 2024 22:37:56 +0200
Subject: [PATCH 15/38] First part of GPM loading specs
---
.../Model/Extensions/Gpm/GltfGpmLoaderSpec.js | 201 ++++++++++++++++++
1 file changed, 201 insertions(+)
create mode 100644 packages/engine/Specs/Scene/Model/Extensions/Gpm/GltfGpmLoaderSpec.js
diff --git a/packages/engine/Specs/Scene/Model/Extensions/Gpm/GltfGpmLoaderSpec.js b/packages/engine/Specs/Scene/Model/Extensions/Gpm/GltfGpmLoaderSpec.js
new file mode 100644
index 000000000000..c8920fb2831b
--- /dev/null
+++ b/packages/engine/Specs/Scene/Model/Extensions/Gpm/GltfGpmLoaderSpec.js
@@ -0,0 +1,201 @@
+import Cartesian3 from "../../../../../Source/Core/Cartesian3.js";
+import CesiumMath from "../../../../../Source/Core/Math.js";
+import Matrix3 from "../../../../../Source/Core/Matrix3.js";
+import GltfGpmLoader from "../../../../../Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js";
+
+describe("Scene/Model/Extensions/Gpm/GltfGpmLoader", function () {
+ it("load throws with invalid storageType", async function () {
+ const gltfGpmLocalJson = {
+ storageType: "INVALID",
+ };
+ expect(function () {
+ GltfGpmLoader.load(gltfGpmLocalJson);
+ }).toThrowDeveloperError();
+ });
+
+ it("load throws for storageType Direct without anchorPointsDirect", async function () {
+ const gltfGpmLocalJson = {
+ storageType: "Direct",
+ };
+ expect(function () {
+ GltfGpmLoader.load(gltfGpmLocalJson);
+ }).toThrowDeveloperError();
+ });
+
+ it("load throws for storageType Direct without covarianceDirectUpperTriangle", async function () {
+ const gltfGpmLocalJson = {
+ storageType: "Direct",
+ anchorPointsDirect: [
+ {
+ position: [1.0, 2.0, 3.0],
+ adjustmentParams: [0.1, 0.2, 0.3],
+ },
+ ],
+ };
+ expect(function () {
+ GltfGpmLoader.load(gltfGpmLocalJson);
+ }).toThrowDeveloperError();
+ });
+
+ it("load returns result for valid JSON for storageType Direct", async function () {
+ const gltfGpmLocalJson = {
+ storageType: "Direct",
+ anchorPointsDirect: [
+ {
+ position: [1.0, 2.0, 3.0],
+ adjustmentParams: [0.1, 0.2, 0.3],
+ },
+ ],
+ covarianceDirectUpperTriangle: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6],
+ };
+
+ const result = GltfGpmLoader.load(gltfGpmLocalJson);
+ expect(result).toBeDefined();
+ expect(result.anchorPointsDirect.length).toBe(1);
+
+ const actualAnchorPoint = result.anchorPointsDirect[0];
+
+ const expectedPosition = new Cartesian3(1.0, 2.0, 3.0);
+ expect(
+ Cartesian3.equalsEpsilon(
+ actualAnchorPoint.position,
+ expectedPosition,
+ CesiumMath.EPSILON6
+ )
+ ).toBeTrue();
+
+ const expectedAdjustmentParams = new Cartesian3(0.1, 0.2, 0.3);
+ expect(
+ Cartesian3.equalsEpsilon(
+ actualAnchorPoint.adjustmentParams,
+ expectedAdjustmentParams,
+ CesiumMath.EPSILON6
+ )
+ ).toBeTrue();
+
+ const expectedCovarianceDirect = Matrix3.fromArray(
+ [0.1, 0.2, 0.4, 0.2, 0.3, 0.5, 0.4, 0.5, 0.6],
+ 0,
+ new Matrix3()
+ );
+ expect(
+ Matrix3.equalsEpsilon(
+ result.covarianceDirect,
+ expectedCovarianceDirect,
+ CesiumMath.EPSILON6
+ )
+ ).toBeTrue();
+ });
+
+ it("load throws for storageType Indirect without anchorPointsIndirect", async function () {
+ const gltfGpmLocalJson = {
+ storageType: "Indirect",
+ };
+ expect(function () {
+ GltfGpmLoader.load(gltfGpmLocalJson);
+ }).toThrowDeveloperError();
+ });
+
+ it("load throws for storageType Indirect without intraTileCorrelationGroups", async function () {
+ const gltfGpmLocalJson = {
+ storageType: "Indirect",
+ anchorPointsIndirect: [
+ {
+ position: [1.0, 2.0, 3.0],
+ adjustmentParams: [0.1, 0.2, 0.3],
+ },
+ ],
+ };
+ expect(function () {
+ GltfGpmLoader.load(gltfGpmLocalJson);
+ }).toThrowDeveloperError();
+ });
+
+ it("load returns result for valid JSON for storageType Indirect", async function () {
+ const gltfGpmLocalJson = {
+ storageType: "Indirect",
+ anchorPointsIndirect: [
+ {
+ position: [1.0, 2.0, 3.0],
+ adjustmentParams: [0.1, 0.2, 0.3],
+ covarianceMatrix: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6],
+ },
+ ],
+ intraTileCorrelationGroups: [
+ {
+ groupFlags: [true, true, true],
+ rotationThetas: [0.1, 0.2, 0.3],
+ params: [
+ {
+ A: 0.1,
+ alpha: 0.2,
+ beta: 0.3,
+ T: 0.4,
+ },
+ ],
+ },
+ ],
+ };
+
+ const result = GltfGpmLoader.load(gltfGpmLocalJson);
+ expect(result).toBeDefined();
+
+ expect(result.anchorPointsIndirect.length).toBe(1);
+
+ const actualAnchorPoint = result.anchorPointsIndirect[0];
+
+ const expectedPosition = new Cartesian3(1.0, 2.0, 3.0);
+ expect(
+ Cartesian3.equalsEpsilon(
+ actualAnchorPoint.position,
+ expectedPosition,
+ CesiumMath.EPSILON6
+ )
+ ).toBeTrue();
+
+ const expectedAdjustmentParams = new Cartesian3(0.1, 0.2, 0.3);
+ expect(
+ Cartesian3.equalsEpsilon(
+ actualAnchorPoint.adjustmentParams,
+ expectedAdjustmentParams,
+ CesiumMath.EPSILON6
+ )
+ ).toBeTrue();
+
+ const expectedCovarianceMatrix = Matrix3.fromArray(
+ [0.1, 0.2, 0.4, 0.2, 0.3, 0.5, 0.4, 0.5, 0.6],
+ 0,
+ new Matrix3()
+ );
+ expect(
+ Matrix3.equalsEpsilon(
+ actualAnchorPoint.covarianceMatrix,
+ expectedCovarianceMatrix,
+ CesiumMath.EPSILON6
+ )
+ ).toBeTrue();
+
+ expect(result.intraTileCorrelationGroups.length).toBe(1);
+
+ const correlationGroup = result.intraTileCorrelationGroups[0];
+ const groupFlags = correlationGroup.groupFlags;
+ expect(groupFlags).toEqual([true, true, true]);
+
+ const expectedRotationThetas = new Cartesian3(0.1, 0.2, 0.3);
+ expect(
+ Cartesian3.equalsEpsilon(
+ correlationGroup.rotationThetas,
+ expectedRotationThetas,
+ CesiumMath.EPSILON6
+ )
+ ).toBeTrue();
+
+ const params = correlationGroup.params;
+ expect(params.length).toBe(1);
+ const param = params[0];
+ expect(param.A).toBe(0.1);
+ expect(param.alpha).toBe(0.2);
+ expect(param.beta).toBe(0.3);
+ expect(param.T).toBe(0.4);
+ });
+});
From 9dbd45ec7029e62cbe01e829c2070ab6c0b1ed3c Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Wed, 25 Sep 2024 15:02:46 +0200
Subject: [PATCH 16/38] Proper imports for spec file
---
.../Scene/Model/Extensions/Gpm/GltfGpmLoaderSpec.js | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/packages/engine/Specs/Scene/Model/Extensions/Gpm/GltfGpmLoaderSpec.js b/packages/engine/Specs/Scene/Model/Extensions/Gpm/GltfGpmLoaderSpec.js
index c8920fb2831b..b4381d5aad9a 100644
--- a/packages/engine/Specs/Scene/Model/Extensions/Gpm/GltfGpmLoaderSpec.js
+++ b/packages/engine/Specs/Scene/Model/Extensions/Gpm/GltfGpmLoaderSpec.js
@@ -1,7 +1,9 @@
-import Cartesian3 from "../../../../../Source/Core/Cartesian3.js";
-import CesiumMath from "../../../../../Source/Core/Math.js";
-import Matrix3 from "../../../../../Source/Core/Matrix3.js";
-import GltfGpmLoader from "../../../../../Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js";
+import {
+ Matrix3,
+ Math as CesiumMath,
+ Cartesian3,
+ GltfGpmLoader,
+} from "../../../../../index.js";
describe("Scene/Model/Extensions/Gpm/GltfGpmLoader", function () {
it("load throws with invalid storageType", async function () {
From 6e290c8a84101a83982ee6d4ada11664f2ed3e8e Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Wed, 25 Sep 2024 15:03:07 +0200
Subject: [PATCH 17/38] Explicitly offer parsed GPM data
---
.../Gpm/GltfMeshPrimitiveGpmLoader.js | 21 ++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
index c207a962a70c..9fc96bb907e7 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
@@ -97,8 +97,27 @@ Object.defineProperties(GltfMeshPrimitiveGpmLoader.prototype, {
return this._cacheKey;
},
},
+
/**
- * The parsed structural metadata
+ * The parsed GPM extension information from the mesh primitive
+ *
+ * @memberof GltfMeshPrimitiveGpmLoader.prototype
+ *
+ * @type {MeshPrimitiveGpmLocal}
+ * @readonly
+ * @private
+ */
+ meshPrimitiveGpmLocal: {
+ get: function () {
+ return this._meshPrimitiveGpmLocal;
+ },
+ },
+
+ /**
+ * Returns the result of converting the parsed 'MeshPrimitiveGpmLocal'
+ * into a 'StructuralMetadata'.
+ *
+ * Some details about the translation are intentionally not specified here.
*
* @memberof GltfMeshPrimitiveGpmLoader.prototype
*
From 6e41b365ba55fb875da9e5c5e1563ec6db22b8ac Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Wed, 25 Sep 2024 15:03:26 +0200
Subject: [PATCH 18/38] Add specs for mesh primitive GPM data
---
.../Gpm/GltfMeshPrimitiveGpmLoaderSpec.js | 429 ++++++++++++++++++
1 file changed, 429 insertions(+)
create mode 100644 packages/engine/Specs/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoaderSpec.js
diff --git a/packages/engine/Specs/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoaderSpec.js b/packages/engine/Specs/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoaderSpec.js
new file mode 100644
index 000000000000..81591889fbdc
--- /dev/null
+++ b/packages/engine/Specs/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoaderSpec.js
@@ -0,0 +1,429 @@
+import {
+ GltfTextureLoader,
+ Resource,
+ ResourceCache,
+ SupportedImageFormats,
+ defined,
+ GltfMeshPrimitiveGpmLoader,
+} from "../../../../../index.js";
+import createScene from "../../../../../../../Specs/createScene.js";
+import loaderProcess from "../../../../../../../Specs/loaderProcess.js";
+import waitForLoaderProcess from "../../../../../../../Specs/waitForLoaderProcess.js";
+
+/**
+ * The JSON representation of the NGA_gpm_local extension object
+ * that will be inserted into the mesh primitive
+ */
+const ngaGpmLocalExtension = {
+ ppeTextures: [
+ {
+ traits: {
+ source: "SIGZ",
+ min: 0.0,
+ max: 16.0,
+ },
+ index: 0,
+ noData: 255,
+ offset: 0.0,
+ scale: 0.06274509803921569,
+ texCoord: 0,
+ },
+ ],
+};
+
+/**
+ * Creates an embedded glTF with a single mesh primitive.
+ *
+ * The mesh primitive is a single unit square with normals and texture
+ * coordinates in [(0,0)-(1.1)]. The glTF defines a single texture,
+ * with an image that is stored as an embdedded 16x16 PNG file
+ * where the red channel contains values in [0,256] (and the alpha
+ * channels contains 255).
+ *
+ * If the given 'gpmExtension' object is defined, then it will be
+ * inserted as the "NGA_gpm_local" extension in the mesh primitive,
+ * and "NGA_gpm_local" will be added to the 'extensionsUsed'.
+ *
+ * @param {object} gpmExtension The NGA_gpm_local extension JSON object
+ * @returns The glTF
+ */
+function createEmbeddedGltf(gpmExtension) {
+ let meshPrimitiveExtensions;
+ let extensionsUsed;
+
+ if (defined(gpmExtension)) {
+ meshPrimitiveExtensions = {
+ NGA_gpm_local: gpmExtension,
+ };
+ extensionsUsed = ["NGA_gpm_local"];
+ }
+
+ const gltf = {
+ accessors: [
+ {
+ bufferView: 0,
+ byteOffset: 0,
+ componentType: 5123,
+ count: 6,
+ type: "SCALAR",
+ max: [3],
+ min: [0],
+ },
+ {
+ bufferView: 1,
+ byteOffset: 0,
+ componentType: 5126,
+ count: 4,
+ type: "VEC3",
+ max: [1.0, 1.0, 0.0],
+ min: [0.0, 0.0, 0.0],
+ },
+ {
+ bufferView: 1,
+ byteOffset: 48,
+ componentType: 5126,
+ count: 4,
+ type: "VEC3",
+ max: [0.0, 0.0, 1.0],
+ min: [0.0, 0.0, 1.0],
+ },
+ {
+ bufferView: 1,
+ byteOffset: 96,
+ componentType: 5126,
+ count: 4,
+ type: "VEC2",
+ max: [1.0, 1.0],
+ min: [0.0, 0.0],
+ },
+ ],
+ asset: {
+ generator: "JglTF from https://github.com/javagl/JglTF",
+ version: "2.0",
+ },
+ buffers: [
+ {
+ uri:
+ "data:application/gltf-buffer;base64,AAABAAIAAQADAAIAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAA",
+ byteLength: 156,
+ },
+ ],
+ bufferViews: [
+ {
+ buffer: 0,
+ byteOffset: 0,
+ byteLength: 12,
+ target: 34963,
+ },
+ {
+ buffer: 0,
+ byteOffset: 12,
+ byteLength: 144,
+ byteStride: 12,
+ target: 34962,
+ },
+ ],
+ images: [
+ {
+ uri:
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABs0lEQVR42hXMUwCWBwBA0b8Wlo1lLHNt2a4tLZtbrdZatm1jWcu2bSxrtWq1Zds438O5jzcUCoU+hSEsXxCO8EQgIl8SichEISrRiE4MQjElFrGJQ1ziEZ8EJOQrEpGYJCQlGcmDQQpJSSpS8zVpSEs60pOBjGQiM1nISrZgkF2+IQff8h05yUVu8pCXfOSnAAUpROFgUESKUozilKAkpShNGcryPT9QjvJUoGIwqCQ/UpkqVKUa1alBTWpRmzrUpR71aRAMGkojGtOEn/iZpjTjF5rTgl9pyW+04vdg0Fra0JZ2tKcDHelEZ7rQlW50pwc96RUMeksf+tKP/gxgIIMYzBCGMozhjGAko4LBaBnDWMYxnglMZBJ/MJkpTGUa05nBzGAwS2Yzh7n8yTzms4CFLGIxS1jKMpazIhislFWsZg1rWcd6NrCRTWxmC1vZxnZ2BIOdsovd7GEv+9jPAQ5yiMMc4Sh/cYzjweCEnOQUpznDWc5xngv8zUUu8Q+XucLVYPCvXOM6//E/N7jJLW5zh7vc4z4PeMijYPBYnvCUZzznBS95xWve8JZ3vOcDH/nEZ7gvfpBCxLDKAAAAAElFTkSuQmCC",
+ mimeType: "image/png",
+ },
+ ],
+ meshes: [
+ {
+ primitives: [
+ {
+ attributes: {
+ POSITION: 1,
+ NORMAL: 2,
+ TEXCOORD_0: 3,
+ },
+ indices: 0,
+ mode: 4,
+ extensions: meshPrimitiveExtensions,
+ },
+ ],
+ },
+ ],
+ nodes: [
+ {
+ mesh: 0,
+ },
+ ],
+ samplers: [
+ {
+ magFilter: 9728,
+ minFilter: 9728,
+ wrapS: 33071,
+ wrapT: 33071,
+ },
+ ],
+ scene: 0,
+ scenes: [
+ {
+ nodes: [0],
+ },
+ ],
+ textures: [
+ {
+ sampler: 0,
+ source: 0,
+ },
+ ],
+ extensionsUsed: extensionsUsed,
+ };
+ return gltf;
+}
+
+// NOTE: Much of this was taken from 'GltfSructuralMetadataLoaderSpec.js'.
+// I don't know what things like the 'mockFrameState' are.
+// I don't know how much of the 'Resource'-specific testing belongs here.
+// I don't know what 'resolveAfterDestroy' is actually testing.
+// Otherwise, I would have added comments...
+describe(
+ "Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader",
+ function () {
+ const gltfUri = "https://example.com/model.glb";
+ const gltfResource = new Resource({
+ url: gltfUri,
+ });
+
+ const mockFrameState = {
+ context: {
+ id: "01234",
+ },
+ };
+
+ let scene;
+
+ beforeAll(function () {
+ scene = createScene();
+ });
+
+ afterAll(function () {
+ scene.destroyForSpecs();
+ });
+
+ afterEach(function () {
+ ResourceCache.clearForSpecs();
+ });
+
+ it("throws if gltf is undefined", function () {
+ const extension = undefined;
+ const gltf = undefined;
+
+ expect(function () {
+ return new GltfMeshPrimitiveGpmLoader({
+ gltf: gltf,
+ extension: extension,
+ gltfResource: gltfResource,
+ baseResource: gltfResource,
+ supportedImageFormats: new SupportedImageFormats(),
+ frameState: mockFrameState,
+ });
+ }).toThrowDeveloperError();
+ });
+
+ it("throws if gltfResource is undefined", function () {
+ const extension = undefined;
+ const gltf = undefined;
+
+ expect(function () {
+ return new GltfMeshPrimitiveGpmLoader({
+ gltf: gltf,
+ extension: extension,
+ gltfResource: undefined,
+ baseResource: gltfResource,
+ supportedImageFormats: new SupportedImageFormats(),
+ frameState: mockFrameState,
+ });
+ }).toThrowDeveloperError();
+ });
+
+ it("throws if baseResource is undefined", function () {
+ const extension = undefined;
+ const gltf = undefined;
+
+ expect(function () {
+ return new GltfMeshPrimitiveGpmLoader({
+ gltf: gltf,
+ extension: extension,
+ gltfResource: gltfResource,
+ baseResource: undefined,
+ supportedImageFormats: new SupportedImageFormats(),
+ frameState: mockFrameState,
+ });
+ }).toThrowDeveloperError();
+ });
+
+ it("throws if supportedImageFormats is undefined", function () {
+ const extension = undefined;
+ const gltf = undefined;
+
+ expect(function () {
+ return new GltfMeshPrimitiveGpmLoader({
+ gltf: gltf,
+ extension: extension,
+ gltfResource: gltfResource,
+ baseResource: gltfResource,
+ supportedImageFormats: undefined,
+ frameState: mockFrameState,
+ });
+ }).toThrowDeveloperError();
+ });
+
+ it("throws if frameState is undefined", function () {
+ const extension = undefined;
+ const gltf = undefined;
+
+ expect(function () {
+ return new GltfMeshPrimitiveGpmLoader({
+ gltf: gltf,
+ extension: extension,
+ gltfResource: gltfResource,
+ baseResource: gltfResource,
+ supportedImageFormats: new SupportedImageFormats(),
+ frameState: undefined,
+ });
+ }).toThrowDeveloperError();
+ });
+
+ it("loads mesh primitive GPM extension data", async function () {
+ const extension = ngaGpmLocalExtension;
+ const gltf = createEmbeddedGltf(extension);
+
+ const loader = new GltfMeshPrimitiveGpmLoader({
+ gltf: gltf,
+ extension: extension,
+ gltfResource: gltfResource,
+ baseResource: gltfResource,
+ supportedImageFormats: new SupportedImageFormats(),
+ frameState: mockFrameState,
+ });
+
+ await loader.load();
+ await waitForLoaderProcess(loader, scene);
+ expect(() => loaderProcess(loader, scene)).not.toThrow();
+
+ const gpmData = loader.meshPrimitiveGpmLocal;
+ expect(gpmData).toBeDefined();
+
+ const ppeTextures = gpmData.ppeTextures;
+ expect(ppeTextures).toBeDefined();
+ expect(ppeTextures.length).toBe(1);
+
+ const ppeTexture = ppeTextures[0];
+ expect(ppeTexture.index).toBe(0);
+ expect(ppeTexture.texCoord).toBe(0);
+ expect(ppeTexture.noData).toBe(255);
+ expect(ppeTexture.offset).toBe(0.0);
+ expect(ppeTexture.scale).toBe(0.06274509803921569);
+
+ expect(ppeTexture.traits).toBeDefined();
+
+ const traits = ppeTexture.traits;
+ expect(traits.min).toBe(0);
+ expect(traits.max).toBe(16);
+ expect(traits.source).toBe("SIGZ");
+ });
+
+ it("converts mesh primitive GPM extension data into structural metadata", async function () {
+ const extension = ngaGpmLocalExtension;
+ const gltf = createEmbeddedGltf(extension);
+
+ const loader = new GltfMeshPrimitiveGpmLoader({
+ gltf: gltf,
+ extension: extension,
+ gltfResource: gltfResource,
+ baseResource: gltfResource,
+ supportedImageFormats: new SupportedImageFormats(),
+ frameState: mockFrameState,
+ });
+
+ await loader.load();
+ await waitForLoaderProcess(loader, scene);
+ expect(() => loaderProcess(loader, scene)).not.toThrow();
+
+ const structuralMetadata = loader.structuralMetadata;
+ expect(structuralMetadata).toBeDefined();
+
+ const ppePropertyTexture = structuralMetadata.getPropertyTexture(0);
+ expect(ppePropertyTexture.id).toBe(0);
+
+ const sigzProperty = ppePropertyTexture.getProperty("SIGZ");
+
+ expect(sigzProperty.textureReader.texture.width).toBe(16);
+ expect(sigzProperty.textureReader.texture.height).toBe(16);
+ });
+
+ it("destroys structural metadata", async function () {
+ const extension = ngaGpmLocalExtension;
+ const gltf = createEmbeddedGltf(extension);
+
+ const destroyTexture = spyOn(
+ GltfTextureLoader.prototype,
+ "destroy"
+ ).and.callThrough();
+
+ const loader = new GltfMeshPrimitiveGpmLoader({
+ gltf: gltf,
+ extension: extension,
+ gltfResource: gltfResource,
+ baseResource: gltfResource,
+ supportedImageFormats: new SupportedImageFormats(),
+ frameState: mockFrameState,
+ });
+
+ await loader.load();
+
+ await waitForLoaderProcess(loader, scene);
+ expect(loader.structuralMetadata).toBeDefined();
+ expect(loader.isDestroyed()).toBe(false);
+
+ loader.destroy();
+
+ expect(loader.structuralMetadata).not.toBeDefined();
+ expect(loader.isDestroyed()).toBe(true);
+
+ expect(destroyTexture.calls.count()).toBe(1);
+ });
+
+ async function resolveAfterDestroy(rejectPromise) {
+ const extension = ngaGpmLocalExtension;
+ const gltf = createEmbeddedGltf(extension);
+
+ const destroyTexture = spyOn(
+ GltfTextureLoader.prototype,
+ "destroy"
+ ).and.callThrough();
+
+ const loader = new GltfMeshPrimitiveGpmLoader({
+ gltf: gltf,
+ extension: extension,
+ gltfResource: gltfResource,
+ baseResource: gltfResource,
+ supportedImageFormats: new SupportedImageFormats(),
+ frameState: mockFrameState,
+ });
+ expect(loader.structuralMetadata).not.toBeDefined();
+ const promise = loader.load();
+ loader.destroy();
+
+ expect(loader.structuralMetadata).not.toBeDefined();
+ expect(loader.isDestroyed()).toBe(true);
+
+ expect(destroyTexture.calls.count()).toBe(1);
+ await expectAsync(promise).toBeResolved();
+ }
+
+ it("handles resolving resources after destroy", function () {
+ return resolveAfterDestroy(false);
+ });
+
+ it("handles rejecting resources after destroy", function () {
+ return resolveAfterDestroy(true);
+ });
+ },
+ "WebGL"
+);
From 616171f1fd26d38e9330e31daac0eb6f4765f04a Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Wed, 25 Sep 2024 15:18:03 +0200
Subject: [PATCH 19/38] Remove log. Check for definedness.
---
packages/engine/Source/Scene/GltfLoader.js | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/packages/engine/Source/Scene/GltfLoader.js b/packages/engine/Source/Scene/GltfLoader.js
index c6733177bdd0..ea4fa5303526 100644
--- a/packages/engine/Source/Scene/GltfLoader.js
+++ b/packages/engine/Source/Scene/GltfLoader.js
@@ -2718,7 +2718,6 @@ function parse(loader, frameState) {
// Load NGA_gpm_local from root object
const gpmExtension = extensions.NGA_gpm_local;
if (defined(gpmExtension)) {
- console.log("Loading GPM from root");
const gltfGpmLocal = GltfGpmLoader.load(gpmExtension);
loader._components.extensions["NGA_gpm_local"] = gltfGpmLocal;
}
@@ -2731,15 +2730,17 @@ function parse(loader, frameState) {
if (defined(primitives)) {
for (const primitive of primitives) {
const primitiveExtensions = primitive.extensions;
- const meshPrimitiveGpmExtension = primitiveExtensions.NGA_gpm_local;
- if (defined(meshPrimitiveGpmExtension)) {
- const promise = loadMeshPrimitiveGpm(
- loader,
- gltf,
- meshPrimitiveGpmExtension,
- frameState
- );
- loader._loaderPromises.push(promise);
+ if (defined(primitiveExtensions)) {
+ const meshPrimitiveGpmExtension = primitiveExtensions.NGA_gpm_local;
+ if (defined(meshPrimitiveGpmExtension)) {
+ const promise = loadMeshPrimitiveGpm(
+ loader,
+ gltf,
+ meshPrimitiveGpmExtension,
+ frameState
+ );
+ loader._loaderPromises.push(promise);
+ }
}
}
}
From 8c0f9263480991dded66326aa9be42c8ea1057bd Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Fri, 27 Sep 2024 20:44:48 +0200
Subject: [PATCH 20/38] Remove experimental tag for getExtensions
---
packages/engine/Source/Scene/Model/Model.js | 2 --
1 file changed, 2 deletions(-)
diff --git a/packages/engine/Source/Scene/Model/Model.js b/packages/engine/Source/Scene/Model/Model.js
index 942cbf6a3d3c..7e81d46aa9c6 100644
--- a/packages/engine/Source/Scene/Model/Model.js
+++ b/packages/engine/Source/Scene/Model/Model.js
@@ -1784,8 +1784,6 @@ Model.prototype.applyArticulations = function () {
* @exception {DeveloperError} The model is not loaded. Use Model.readyEvent or wait for Model.ready to be true.
*
* @private
- * @experimental This feature is subject to change without Cesium's standard deprecation policy.
- *
*/
Model.prototype.getExtension = function (extensionName) {
//>>includeStart('debug', pragmas.debug);
From 5723c8b9499e904968e358dab2221cf019c2ab68 Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Fri, 27 Sep 2024 20:46:21 +0200
Subject: [PATCH 21/38] Add return type to JSDoc
---
packages/engine/Source/Scene/Model/Model.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/engine/Source/Scene/Model/Model.js b/packages/engine/Source/Scene/Model/Model.js
index 7e81d46aa9c6..4c79779b66cd 100644
--- a/packages/engine/Source/Scene/Model/Model.js
+++ b/packages/engine/Source/Scene/Model/Model.js
@@ -1780,7 +1780,7 @@ Model.prototype.applyArticulations = function () {
* this will return the model representation of the extension.
*
* @param {string} extensionName The name of the extension
- * @returns The object, or `undefined`
+ * @returns {object|undefined} The object, or `undefined`
* @exception {DeveloperError} The model is not loaded. Use Model.readyEvent or wait for Model.ready to be true.
*
* @private
From bb74ec4b4e3c7ff517eef97141d9f3fa90cef2ad Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Fri, 27 Sep 2024 20:48:46 +0200
Subject: [PATCH 22/38] Add JSDoc for getExtension
---
.../engine/Source/Scene/Model/Model3DTileContent.js | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/packages/engine/Source/Scene/Model/Model3DTileContent.js b/packages/engine/Source/Scene/Model/Model3DTileContent.js
index 15b0e10f49e7..bdc0b3831a81 100644
--- a/packages/engine/Source/Scene/Model/Model3DTileContent.js
+++ b/packages/engine/Source/Scene/Model/Model3DTileContent.js
@@ -152,6 +152,19 @@ Object.defineProperties(Model3DTileContent.prototype, {
},
});
+/**
+ * Returns the object that was created for the given extension.
+ *
+ * The given name may be the name of a glTF extension, like `"EXT_example_extension"`.
+ * If the specified extension was present in the root of the underlying glTF asset,
+ * and a loder for the specified extension has processed the extension data, then
+ * this will return the model representation of the extension.
+ *
+ * @param {string} extensionName The name of the extension
+ * @returns {object|undefined} The object, or `undefined`
+ *
+ * @private
+ */
Model3DTileContent.prototype.getExtension = function (extensionName) {
const model = this._model;
const extension = model.getExtension(extensionName);
From 962a9864790a9bc224eb35fba9e3a9751c133fdc Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Fri, 27 Sep 2024 20:50:00 +0200
Subject: [PATCH 23/38] Add type tag to property
---
packages/engine/Source/Scene/ModelComponents.js | 3 +++
1 file changed, 3 insertions(+)
diff --git a/packages/engine/Source/Scene/ModelComponents.js b/packages/engine/Source/Scene/ModelComponents.js
index fa49d4111c2d..fc72bf5baac6 100644
--- a/packages/engine/Source/Scene/ModelComponents.js
+++ b/packages/engine/Source/Scene/ModelComponents.js
@@ -1145,6 +1145,9 @@ function Components() {
/**
* A mapping from extension names like `"EXT_example_extension"` to
* the object that was created from the extension input
+ *
+ * @type {object}
+ * @private
*/
this.extensions = {};
}
From 804fa0a68bfb38298b951fdba7549c13a2a29f95 Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Fri, 27 Sep 2024 20:57:31 +0200
Subject: [PATCH 24/38] More elaborate warning text
---
packages/engine/Source/Scene/GltfLoader.js | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/packages/engine/Source/Scene/GltfLoader.js b/packages/engine/Source/Scene/GltfLoader.js
index 739f129d0f95..d853d90d73dc 100644
--- a/packages/engine/Source/Scene/GltfLoader.js
+++ b/packages/engine/Source/Scene/GltfLoader.js
@@ -482,7 +482,10 @@ function processLoaders(loader, frameState) {
if (defined(loader._components.structuralMetadata)) {
oneTimeWarning(
"structural-metadata-gpm",
- "Structural metadata is replaced with GPM data",
+ "The model defines both the 'EXT_structural_metadata' extension and the " +
+ "'NGA_gpm_local' extension. The data from the 'EXT_structural_metadata' " +
+ "extension will be replaced with the data from the 'NGA_gpm_local' extension, " +
+ "and will no longer be available for styling and picking.",
);
}
loader._components.structuralMetadata =
From 905925a3df64452622a5cd54674fd4b46f6ff38c Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Fri, 27 Sep 2024 21:07:54 +0200
Subject: [PATCH 25/38] Removed obsolete part of JSDoc
---
.../engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js | 2 --
1 file changed, 2 deletions(-)
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
index b872a53c7c57..ab9322002a43 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
@@ -11,8 +11,6 @@ import StorageType from "./StorageType.js";
/**
* Loads glTF NGA_gpm_local from the root of a glTF object
- *
- * Implementation note: This is an experimental implementation.
*
* @alias GltfGpmLoader
* @constructor
From e887e538b87174b5bca84ace878bce6c11200136 Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Fri, 27 Sep 2024 21:14:25 +0200
Subject: [PATCH 26/38] Add JSDoc return type info
---
.../Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
index ab9322002a43..4d5a95cc965a 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
@@ -30,7 +30,7 @@ function GltfGpmLoader() {}
* column-major order.
*
* @param {number[]} array The input array
- * @returns The Matrix3
+ * @returns {Matrix3} The Matrix3
*/
function createCovarianceMatrixFromUpperTriangle(array) {
const covarianceMatrix = new Matrix3(
@@ -51,7 +51,7 @@ function createCovarianceMatrixFromUpperTriangle(array) {
* Creates an `AnchorPointDirect` from the given JSON representation
*
* @param {object} anchorPointDirectJson The input JSON
- * @returns The `AnchorPointDirect`
+ * @returns {AnchorPointDirect} The direct anchor point
*/
function createAnchorPointDirect(anchorPointDirectJson) {
const position = Cartesian3.fromArray(
@@ -75,7 +75,7 @@ function createAnchorPointDirect(anchorPointDirectJson) {
* Creates an `AnchorPointIndirect` from the given JSON representation
*
* @param {object} anchorPointIndirectJson The input JSON
- * @returns The `AnchorPointIndirect`
+ * @returns {AnchorPointIndirect} The indirect anchor point
*/
function createAnchorPointIndirect(anchorPointIndirectJson) {
const position = Cartesian3.fromArray(
@@ -103,7 +103,7 @@ function createAnchorPointIndirect(anchorPointIndirectJson) {
* Creates a `CorrelationGroup` from the given JSON representation
*
* @param {object} correlationGroupJson The input JSON
- * @returns The `CorrelationGroup`
+ * @returns {CorrelationGroup} The correlation group
*/
function createCorrelationGroup(correlationGroupJson) {
const groupFlags = correlationGroupJson.groupFlags;
From 13b2db09dc56712fac91bd0d73b96f8d2538c6af Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Fri, 27 Sep 2024 21:16:24 +0200
Subject: [PATCH 27/38] Change error type for load function
---
.../Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
index 4d5a95cc965a..25143d00ba25 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
@@ -1,7 +1,7 @@
import Cartesian3 from "../../../../Core/Cartesian3.js";
import Check from "../../../../Core/Check.js";
-import DeveloperError from "../../../../Core/DeveloperError.js";
import Matrix3 from "../../../../Core/Matrix3.js";
+import RuntimeError from "../../../../Core/RuntimeError.js";
import AnchorPointDirect from "./AnchorPointDirect.js";
import AnchorPointIndirect from "./AnchorPointIndirect.js";
import CorrelationGroup from "./CorrelationGroup.js";
@@ -136,9 +136,8 @@ function createCorrelationGroup(correlationGroupJson) {
*
* @param {object} gltfGpmLocalJson The extension object
* @returns {GltfGpmLocal} The parsed object
+ * @throws RuntimeError When the given object contains invalid storage types.
* @private
- * @throws DeveloperError When the given object is `undefined`
- * or contains invalid structures
*/
GltfGpmLoader.load = function (gltfGpmLocalJson) {
//>>includeStart('debug', pragmas.debug);
@@ -152,7 +151,7 @@ GltfGpmLoader.load = function (gltfGpmLocalJson) {
if (storageType === StorageType.Indirect) {
return GltfGpmLoader.loadIndirect(gltfGpmLocalJson);
}
- throw new DeveloperError(
+ throw new RuntimeError(
`Invalid storage type in NGA_gpm_local - expected 'Direct' or 'Indirect', but found ${storageType}`,
);
};
From ac78182077e17745236cd61b86ba8522c32f436b Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Fri, 27 Sep 2024 21:29:29 +0200
Subject: [PATCH 28/38] List supported extension in model documentation
---
packages/engine/Source/Scene/Model/Model.js | 3 +++
1 file changed, 3 insertions(+)
diff --git a/packages/engine/Source/Scene/Model/Model.js b/packages/engine/Source/Scene/Model/Model.js
index 4c79779b66cd..0892388a51a6 100644
--- a/packages/engine/Source/Scene/Model/Model.js
+++ b/packages/engine/Source/Scene/Model/Model.js
@@ -105,6 +105,9 @@ import pickModel from "./pickModel.js";
*
* {@link https://github.com/KhronosGroup/glTF/blob/main/extensions/1.0/Vendor/WEB3D_quantized_attributes/README.md|WEB3D_quantized_attributes}
*
+ *
+ * {@link https://nsgreg.nga.mil/csmwg.jsp|NGA_gpm_local}
+ *
*
*
*
From e61667c10f67ace80c730ab035f10d805be0163d Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Fri, 27 Sep 2024 21:32:06 +0200
Subject: [PATCH 29/38] Update CHANGES.md
---
CHANGES.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGES.md b/CHANGES.md
index bf6d8f4a47e6..3bf60ce39bbe 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -8,6 +8,7 @@
- Added `enableVerticalExaggeration` option to models. Set this value to `false` to prevent model exaggeration when `Scene.verticalExaggeration` is set to a value other than `1.0`. [#12141](https://github.com/CesiumGS/cesium/pull/12141)
- Added `CallbackPositionProperty` to allow lazy entity position evaluation. [#12170](https://github.com/CesiumGS/cesium/pull/12170)
+- Added experimental support for the `NGA_gpm_local` glTF extension, for GPM 1.2 [#12204](https://github.com/CesiumGS/cesium/pull/12204)
##### Fixes :wrench:
From e94ca56b6791b5783423392d99ea6c664d10d901 Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Sat, 28 Sep 2024 13:19:40 +0200
Subject: [PATCH 30/38] Try to clarify private and experimental
---
.../Model/Extensions/Gpm/AnchorPointDirect.js | 3 ---
.../Model/Extensions/Gpm/AnchorPointIndirect.js | 4 ----
.../Scene/Model/Extensions/Gpm/CorrelationGroup.js | 4 ----
.../Scene/Model/Extensions/Gpm/GltfGpmLoader.js | 1 -
.../Scene/Model/Extensions/Gpm/GltfGpmLocal.js | 14 ++++----------
.../Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js | 1 -
.../Model/Extensions/Gpm/MeshPrimitiveGpmLocal.js | 2 --
.../Scene/Model/Extensions/Gpm/PpeMetadata.js | 4 ----
.../Scene/Model/Extensions/Gpm/PpeTexture.js | 7 -------
.../Source/Scene/Model/Extensions/Gpm/Spdcf.js | 5 -----
packages/engine/Source/Scene/Model/Model.js | 4 ++--
11 files changed, 6 insertions(+), 43 deletions(-)
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js
index 903330dada7f..05bc225f9260 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js
@@ -3,7 +3,6 @@ import Check from "../../../../Core/Check.js";
/**
* Metadata for one stored anchor point using direct storage
*
- * @private
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function AnchorPointDirect(options) {
@@ -23,7 +22,6 @@ Object.defineProperties(AnchorPointDirect.prototype, {
* @memberof AnchorPointDirect.prototype
* @type {Cartesian3}
* @readonly
- * @private
*/
position: {
get: function () {
@@ -38,7 +36,6 @@ Object.defineProperties(AnchorPointDirect.prototype, {
* @memberof AnchorPointDirect.prototype
* @type {Cartesian3}
* @readonly
- * @private
*/
adjustmentParams: {
get: function () {
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js
index f0102db32943..03599b48ce8d 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js
@@ -3,7 +3,6 @@ import Check from "../../../../Core/Check.js";
/**
* Metadata for one stored anchor point.
*
- * @private
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function AnchorPointIndirect(options) {
@@ -25,7 +24,6 @@ Object.defineProperties(AnchorPointIndirect.prototype, {
* @memberof AnchorPointIndirect.prototype
* @type {Cartesian3}
* @readonly
- * @private
*/
position: {
get: function () {
@@ -40,7 +38,6 @@ Object.defineProperties(AnchorPointIndirect.prototype, {
* @memberof AnchorPointIndirect.prototype
* @type {Cartesian3}
* @readonly
- * @private
*/
adjustmentParams: {
get: function () {
@@ -54,7 +51,6 @@ Object.defineProperties(AnchorPointIndirect.prototype, {
* @memberof AnchorPointIndirect.prototype
* @type {Matrix3}
* @readonly
- * @private
*/
covarianceMatrix: {
get: function () {
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js
index cc82812aa608..23812c03871b 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js
@@ -4,7 +4,6 @@ import Check from "../../../../Core/Check.js";
* Metadata identifying parameters using same correlation modeling and
* associated correlation parameters.
*
- * @private
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function CorrelationGroup(options) {
@@ -27,7 +26,6 @@ Object.defineProperties(CorrelationGroup.prototype, {
* @memberof CorrelationGroup.prototype
* @type {boolean[]}
* @readonly
- * @private
*/
groupFlags: {
get: function () {
@@ -41,7 +39,6 @@ Object.defineProperties(CorrelationGroup.prototype, {
* @memberof CorrelationGroup.prototype
* @type {Cartesian3}
* @readonly
- * @private
*/
rotationThetas: {
get: function () {
@@ -55,7 +52,6 @@ Object.defineProperties(CorrelationGroup.prototype, {
* @memberof CorrelationGroup.prototype
* @type {Spdcf[]}
* @readonly
- * @private
*/
params: {
get: function () {
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
index 25143d00ba25..f3cd3e2dd2d7 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js
@@ -20,7 +20,6 @@ import StorageType from "./StorageType.js";
* @param {string} [options.extension] The NGA_gpm_local
extension object.
*
* @private
- * @experimental This feature is subject to change without Cesium's standard deprecation policy.
*/
function GltfGpmLoader() {}
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js
index 76878a9c4c78..73fc5789de13 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js
@@ -7,7 +7,6 @@ import StorageType from "./StorageType.js";
* The GPM metadata for a Ground-Space Indirect implementation stored
* locally (i.e. a tile and/or leaf node).
*
- * @private
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function GltfGpmLocal(options) {
@@ -76,7 +75,6 @@ Object.defineProperties(GltfGpmLocal.prototype, {
* @memberof GltfGpmLocal.prototype
* @type {StorageType}
* @readonly
- * @private
*/
storageType: {
get: function () {
@@ -88,9 +86,8 @@ Object.defineProperties(GltfGpmLocal.prototype, {
* Array of stored indirect anchor points
*
* @memberof GltfGpmLocal.prototype
- * @type {AnchorPointIndirect[]}
+ * @type {AnchorPointIndirect[]|undefined}
* @readonly
- * @private
*/
anchorPointsIndirect: {
get: function () {
@@ -102,9 +99,8 @@ Object.defineProperties(GltfGpmLocal.prototype, {
* Array of stored direct anchor points
*
* @memberof GltfGpmLocal.prototype
- * @type {AnchorPointDirect[]}
+ * @type {AnchorPointDirect[]|undefined}
* @readonly
- * @private
*/
anchorPointsDirect: {
get: function () {
@@ -117,9 +113,8 @@ Object.defineProperties(GltfGpmLocal.prototype, {
* associated correlation parameters
*
* @memberof GltfGpmLocal.prototype
- * @type {CorrelationGroup[]}
+ * @type {CorrelationGroup[]|undefined}
* @readonly
- * @private
*/
intraTileCorrelationGroups: {
get: function () {
@@ -131,9 +126,8 @@ Object.defineProperties(GltfGpmLocal.prototype, {
* The full covariance of anchor point parameters
*
* @memberof GltfGpmLocal.prototype
- * @type {Matrix3}
+ * @type {Matrix3|undefined}
* @readonly
- * @private
*/
covarianceDirect: {
get: function () {
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
index 76c860fe7ceb..b718ff49e504 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
@@ -37,7 +37,6 @@ import MeshPrimitiveGpmLocal from "./MeshPrimitiveGpmLocal.js";
* @param {boolean} [options.asynchronous=true] Determines if WebGL resource creation will be spread out over several frames or block until all WebGL resources are created.
*
* @private
- * @experimental This feature is subject to change without Cesium's standard deprecation policy.
*/
function GltfMeshPrimitiveGpmLoader(options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/MeshPrimitiveGpmLocal.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/MeshPrimitiveGpmLocal.js
index 1ca122137744..5cdf62f37943 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/MeshPrimitiveGpmLocal.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/MeshPrimitiveGpmLocal.js
@@ -1,7 +1,6 @@
/**
* Local Generic Point-cloud Model information about a glTF primitive.
*
- * @private
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function MeshPrimitiveGpmLocal(options) {
@@ -15,7 +14,6 @@ Object.defineProperties(MeshPrimitiveGpmLocal.prototype, {
* @memberof MeshPrimitiveGpmLocal.prototype
* @type {PpeTexture[]|undefined}
* @readonly
- * @private
*/
ppeTextures: {
get: function () {
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
index 66d38ef40cb8..457779cf4b40 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
@@ -3,7 +3,6 @@ import Check from "../../../../Core/Check.js";
/**
* Metadata related to the stored PPE data.
*
- * @private
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function PpeMetadata(options) {
@@ -25,7 +24,6 @@ Object.defineProperties(PpeMetadata.prototype, {
* @memberof PpeMetadata.prototype
* @type {number|undefined}
* @readonly
- * @private
*/
min: {
get: function () {
@@ -41,7 +39,6 @@ Object.defineProperties(PpeMetadata.prototype, {
* @memberof PpeMetadata.prototype
* @type {number|undefined}
* @readonly
- * @private
*/
max: {
get: function () {
@@ -55,7 +52,6 @@ Object.defineProperties(PpeMetadata.prototype, {
* @memberof PpeMetadata.prototype
* @type {PpeSource}
* @readonly
- * @private
*/
source: {
get: function () {
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
index 8b352956758d..f8b8109f773d 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
@@ -7,7 +7,6 @@ import Check from "../../../../Core/Check.js";
* and an optional `texCoord)`, with additional properties that
* describe the structure of the metdata that is stored in the texture.
*
- * @private
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function PpeTexture(options) {
@@ -32,7 +31,6 @@ Object.defineProperties(PpeTexture.prototype, {
* @memberof PpeTexture.prototype
* @type {PpeMetadata}
* @readonly
- * @private
*/
traits: {
get: function () {
@@ -47,7 +45,6 @@ Object.defineProperties(PpeTexture.prototype, {
* @memberof PpeTexture.prototype
* @type {number|undefined}
* @readonly
- * @private
*/
noData: {
get: function () {
@@ -61,7 +58,6 @@ Object.defineProperties(PpeTexture.prototype, {
* @memberof PpeTexture.prototype
* @type {number|undefined}
* @readonly
- * @private
*/
offset: {
get: function () {
@@ -75,7 +71,6 @@ Object.defineProperties(PpeTexture.prototype, {
* @memberof PpeTexture.prototype
* @type {number|undefined}
* @readonly
- * @private
*/
scale: {
get: function () {
@@ -89,7 +84,6 @@ Object.defineProperties(PpeTexture.prototype, {
* @memberof PpeTexture.prototype
* @type {number}
* @readonly
- * @private
*/
index: {
get: function () {
@@ -103,7 +97,6 @@ Object.defineProperties(PpeTexture.prototype, {
* @memberof PpeTexture.prototype
* @type {number|undefined}
* @readonly
- * @private
*/
texCoord: {
get: function () {
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js
index 7687ed32ed8d..237b34f6ac4e 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js
@@ -6,7 +6,6 @@ import Check from "../../../../Core/Check.js";
* Parameters (A, alpha, beta, T) used to describe the correlation decrease
* between points as a function of delta time.
*
- * @private
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function Spdcf(options) {
@@ -33,7 +32,6 @@ Object.defineProperties(Spdcf.prototype, {
* @memberof Spdcf.prototype
* @type {number}
* @readonly
- * @private
*/
A: {
get: function () {
@@ -47,7 +45,6 @@ Object.defineProperties(Spdcf.prototype, {
* @memberof Spdcf.prototype
* @type {number}
* @readonly
- * @private
*/
alpha: {
get: function () {
@@ -61,7 +58,6 @@ Object.defineProperties(Spdcf.prototype, {
* @memberof Spdcf.prototype
* @type {number}
* @readonly
- * @private
*/
beta: {
get: function () {
@@ -75,7 +71,6 @@ Object.defineProperties(Spdcf.prototype, {
* @memberof Spdcf.prototype
* @type {number}
* @readonly
- * @private
*/
T: {
get: function () {
diff --git a/packages/engine/Source/Scene/Model/Model.js b/packages/engine/Source/Scene/Model/Model.js
index 0892388a51a6..15474e5df2ea 100644
--- a/packages/engine/Source/Scene/Model/Model.js
+++ b/packages/engine/Source/Scene/Model/Model.js
@@ -106,7 +106,7 @@ import pickModel from "./pickModel.js";
* {@link https://github.com/KhronosGroup/glTF/blob/main/extensions/1.0/Vendor/WEB3D_quantized_attributes/README.md|WEB3D_quantized_attributes}
*
*
- * {@link https://nsgreg.nga.mil/csmwg.jsp|NGA_gpm_local}
+ * {@link https://nsgreg.nga.mil/csmwg.jsp|NGA_gpm_local (experimental)}
*
*
*
@@ -1786,7 +1786,7 @@ Model.prototype.applyArticulations = function () {
* @returns {object|undefined} The object, or `undefined`
* @exception {DeveloperError} The model is not loaded. Use Model.readyEvent or wait for Model.ready to be true.
*
- * @private
+ * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
Model.prototype.getExtension = function (extensionName) {
//>>includeStart('debug', pragmas.debug);
From 72414c50ffc0ce737e96d61a763460ffbd83547a Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Sat, 28 Sep 2024 13:52:13 +0200
Subject: [PATCH 31/38] Add links to GPM spec. Updated comments.
---
.../Model/Extensions/Gpm/AnchorPointDirect.js | 5 ++++-
.../Extensions/Gpm/AnchorPointIndirect.js | 3 +++
.../Model/Extensions/Gpm/CorrelationGroup.js | 3 +++
.../Model/Extensions/Gpm/GltfGpmLocal.js | 20 +++++++++++++++++++
.../Gpm/GltfMeshPrimitiveGpmLoader.js | 4 ++--
.../Scene/Model/Extensions/Gpm/PpeMetadata.js | 5 ++++-
.../Scene/Model/Extensions/Gpm/PpeSource.js | 5 ++++-
.../Scene/Model/Extensions/Gpm/PpeTexture.js | 3 +++
.../Scene/Model/Extensions/Gpm/Spdcf.js | 12 +++++++++--
.../Scene/Model/Extensions/Gpm/StorageType.js | 5 ++++-
10 files changed, 57 insertions(+), 8 deletions(-)
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js
index 05bc225f9260..430240fee98a 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js
@@ -1,7 +1,10 @@
import Check from "../../../../Core/Check.js";
/**
- * Metadata for one stored anchor point using direct storage
+ * Metadata for one stored anchor point using direct storage.
+ *
+ * This reflects the `anchronPointDirect` definition of the
+ * {@link https://nsgreg.nga.mil/csmwg.jsp|NGA_gpm_local} glTF extension.
*
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js
index 03599b48ce8d..7abe2db94046 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js
@@ -3,6 +3,9 @@ import Check from "../../../../Core/Check.js";
/**
* Metadata for one stored anchor point.
*
+ * This reflects the `anchronPointIndirect` definition of the
+ * {@link https://nsgreg.nga.mil/csmwg.jsp|NGA_gpm_local} glTF extension.
+ *
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function AnchorPointIndirect(options) {
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js
index 23812c03871b..abf0a4e1262d 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js
@@ -4,6 +4,9 @@ import Check from "../../../../Core/Check.js";
* Metadata identifying parameters using same correlation modeling and
* associated correlation parameters.
*
+ * This reflects the `correlationGroup` definition of the
+ * {@link https://nsgreg.nga.mil/csmwg.jsp|NGA_gpm_local} glTF extension.
+ *
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function CorrelationGroup(options) {
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js
index 73fc5789de13..84ae342bf56b 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js
@@ -7,6 +7,26 @@ import StorageType from "./StorageType.js";
* The GPM metadata for a Ground-Space Indirect implementation stored
* locally (i.e. a tile and/or leaf node).
*
+ * This reflects the root extension object of the {@link https://nsgreg.nga.mil/csmwg.jsp|NGA_gpm_local}
+ * glTF extension. When a model that contains this extension was loaded,
+ * then an object of this type can be obtained by calling
+ * ```
+ * const gltfGpmLocal = model.getExtension("NGA_gpm_local");
+ * ```
+ *
+ * The storage type determines the presence of the optional properties:
+ *
+ * -
+ * When the storage type is `StorageType.Indirect`, then the
+ * `anchorPointsIndirect` and `intraTileCorrelationGroups`
+ * are present.
+ *
+ * -
+ * When the storage type is `StorageType.Direct`, then the
+ * `anchorPointsDirect` and `covarianceDirect` are present.
+ *
+ *
+ *
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function GltfGpmLocal(options) {
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
index b718ff49e504..e16672669756 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
@@ -232,7 +232,7 @@ GltfMeshPrimitiveGpmLoader.ppeTexturesMetadataSchemaCache = new Map();
/**
* Create the JSON description of a metadata class that treats
- * the given PPE texture as a property texture property(!).
+ * the given PPE texture as a property texture property.
*
* @param {any} ppeTexture - The PPE texture
* @param {number} index - The index of the texture in the extension
@@ -346,7 +346,7 @@ GltfMeshPrimitiveGpmLoader.obtainPpeTexturesMetadataSchema = function (
*
* Each glTF may define multiple `ppeTexture` objects within the
* `NGA_gpm_local` extensions. Each of these textures corresponds
- * to one 'property texture property(!)' in a metadata schema.
+ * to one 'property texture property' in a metadata schema.
*
* This method will create an array where each element is a (JSON)
* string representation of the parts of a GPM PPE texture definition
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
index 457779cf4b40..46949992a3dc 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
@@ -1,7 +1,10 @@
import Check from "../../../../Core/Check.js";
/**
- * Metadata related to the stored PPE data.
+ * Metadata related to the stored PPE (Per-Point Error) data.
+ *
+ * This reflects the `ppeMetadata` definition of the
+ * {@link https://nsgreg.nga.mil/csmwg.jsp|NGA_gpm_local} glTF extension.
*
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeSource.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeSource.js
index d44acabe4e1c..db0f3676f278 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeSource.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeSource.js
@@ -1,5 +1,8 @@
/**
- * An enum of per-point error sources
+ * An enum of per-point error sources.
+ *
+ * This reflects the `ppeMetadata.source` definition of the
+ * {@link https://nsgreg.nga.mil/csmwg.jsp|NGA_gpm_local} glTF extension.
*
* @enum {string}
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
index f8b8109f773d..216764da2999 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
@@ -3,6 +3,9 @@ import Check from "../../../../Core/Check.js";
/**
* PPE (Per-Point Error) texture in `NGA_gpm_local`.
*
+ * This reflects the `ppeTexture` definition of the
+ * {@link https://nsgreg.nga.mil/csmwg.jsp|NGA_gpm_local} glTF extension.
+ *
* This is a valid glTF `TextureInfo` object (with a required `index`
* and an optional `texCoord)`, with additional properties that
* describe the structure of the metdata that is stored in the texture.
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js
index 237b34f6ac4e..74ae2c607c80 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js
@@ -3,8 +3,16 @@ import Check from "../../../../Core/Check.js";
/**
* Variables for a Strictly Positive-Definite Correlation Function.
*
- * Parameters (A, alpha, beta, T) used to describe the correlation decrease
- * between points as a function of delta time.
+ * This reflects the `spdcf` definition of the
+ * {@link https://nsgreg.nga.mil/csmwg.jsp|NGA_gpm_local} glTF extension.
+ * Instances of this type are stored as the parameters within a
+ * `CorrelationGroup`.
+ *
+ * Parameters (A, alpha, beta, T) describe the correlation decrease
+ * between points as a function of delta time:
+ * ```
+ * spdcf(delta_t) = A_t * (alpha_t + ((1 - alpha_t)(1 + beta_t)) / (beta_t + e^(delta_t/T_t)))
+ * ```
*
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/StorageType.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/StorageType.js
index f706c32b63e1..94a864b6be38 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/StorageType.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/StorageType.js
@@ -1,5 +1,8 @@
/**
- * An enum of storage types for covariance information
+ * An enum of storage types for covariance information.
+ *
+ * This reflects the `gltfGpmLocal.storageType` definition of the
+ * {@link https://nsgreg.nga.mil/csmwg.jsp|NGA_gpm_local} glTF extension.
*
* @enum {string}
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
From 55df6c9b8fe2d145f66061bd0546e3b9931a914b Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Sat, 28 Sep 2024 14:29:38 +0200
Subject: [PATCH 32/38] Document constructor options
---
.../Model/Extensions/Gpm/GltfGpmLocal.js | 19 +++++++++++++++++++
.../Scene/Model/Extensions/Gpm/PpeMetadata.js | 12 ++++++++++++
.../Scene/Model/Extensions/Gpm/PpeTexture.js | 15 +++++++++++++++
3 files changed, 46 insertions(+)
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js
index 84ae342bf56b..f58aa27fd361 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js
@@ -3,6 +3,23 @@ import Check from "../../../../Core/Check.js";
import RuntimeError from "../../../../Core/RuntimeError.js";
import StorageType from "./StorageType.js";
+/**
+ * @typedef {object} GltfGpmLocal.ConstructorOptions
+ *
+ * Initialization options for the GltfGpmLocal constructor
+ *
+ * @property {string} storageType The storage type.
+ * This must be one of the `StorageType` constants, i.e. `Direct` or `Indirect`.
+ * @property {AnchorPointIndirect[]|undefined} [anchorPointsIndirect] The indirect anchor points.
+ * This must be present if and only if the storage type is `Indirect`.
+ * @property {CorrelationGroup[]|undefined} [intraTileCorrelationGroups] The intra-tile correlation groups.
+ * This must be present if and only if the storage type is `Indirect`.
+ * @property {AnchorPointDirect[]|undefined} [anchorPointsDirect] The direct anchor points.
+ * This must be present if and only if the storage type is `Direct`.
+ * @property {Matrix3|undefined} [covarianceDirect] The covariance of anchor point parameters.
+ * This must be present if and only if the storage type is `Direct`.
+ */
+
/**
* The GPM metadata for a Ground-Space Indirect implementation stored
* locally (i.e. a tile and/or leaf node).
@@ -27,6 +44,8 @@ import StorageType from "./StorageType.js";
*
*
*
+ * @param {GltfGpmLocal.ConstructorOptions} options An object describing initialization options
+ *
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function GltfGpmLocal(options) {
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
index 46949992a3dc..88bcb70ebee9 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
@@ -1,11 +1,23 @@
import Check from "../../../../Core/Check.js";
+/**
+ * @typedef {object} PpeMetadata.ConstructorOptions
+ *
+ * Initialization options for the PpeMetadata constructor
+ *
+ * @property {PpeSource} source The source of the error data
+ * @property {number|undefined} [min] Minimum allowed value for the property.
+ * @property {number|undefined} [max] Maximum allowed value for the property.
+ */
+
/**
* Metadata related to the stored PPE (Per-Point Error) data.
*
* This reflects the `ppeMetadata` definition of the
* {@link https://nsgreg.nga.mil/csmwg.jsp|NGA_gpm_local} glTF extension.
*
+ * @param {PpeMetadata.ConstructorOptions} options An object describing initialization options
+ *
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function PpeMetadata(options) {
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
index 216764da2999..7588fd2a4ed0 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
@@ -1,5 +1,18 @@
import Check from "../../../../Core/Check.js";
+/**
+ * @typedef {object} PpeTexture.ConstructorOptions
+ *
+ * Initialization options for the PpeTexture constructor
+ *
+ * @property {PpeMetadata} traits The traits that indicate which data is stored in this texture
+ * @property {number} index The index of the texture inside the glTF textures array
+ * @property {number|undefined} [texCoord] The optional set index for the TEXCOORD attribute
+ * @property {number|undefined} [noData] The value to represent missing data
+ * @property {number|undefined} [offset] An offset to apply to property values.
+ * @property {number|undefined} [scale] A scale to apply to property values.
+ */
+
/**
* PPE (Per-Point Error) texture in `NGA_gpm_local`.
*
@@ -10,6 +23,8 @@ import Check from "../../../../Core/Check.js";
* and an optional `texCoord)`, with additional properties that
* describe the structure of the metdata that is stored in the texture.
*
+ * @param {PpeTexture.ConstructorOptions} options An object describing initialization options
+ *
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function PpeTexture(options) {
From b8b5445903bb9fb9b3a9d4c3a55f58dfa38bb47c Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Sat, 28 Sep 2024 14:30:02 +0200
Subject: [PATCH 33/38] Avoid unnecessary constructor options
---
.../Scene/Model/Extensions/Gpm/MeshPrimitiveGpmLocal.js | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/MeshPrimitiveGpmLocal.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/MeshPrimitiveGpmLocal.js
index 5cdf62f37943..c8b76f25b0de 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/MeshPrimitiveGpmLocal.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/MeshPrimitiveGpmLocal.js
@@ -1,10 +1,12 @@
/**
* Local Generic Point-cloud Model information about a glTF primitive.
*
- * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
+ * @param {PpeTexture[]} ppeTextures The Per-Point Error textures
+ *
+ * @private
*/
-function MeshPrimitiveGpmLocal(options) {
- this._ppeTextures = options.ppeTextures;
+function MeshPrimitiveGpmLocal(ppeTextures) {
+ this._ppeTextures = ppeTextures;
}
Object.defineProperties(MeshPrimitiveGpmLocal.prototype, {
From e4efa515554dcb2b203bf7bd00e9114711218ab2 Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Sat, 28 Sep 2024 14:30:23 +0200
Subject: [PATCH 34/38] Add underscore to internal functions
---
.../Gpm/GltfMeshPrimitiveGpmLoader.js | 38 +++++++++----------
1 file changed, 18 insertions(+), 20 deletions(-)
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
index e16672669756..7be022144311 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js
@@ -131,9 +131,9 @@ Object.defineProperties(GltfMeshPrimitiveGpmLoader.prototype, {
},
});
-GltfMeshPrimitiveGpmLoader.prototype.loadResources = async function () {
+GltfMeshPrimitiveGpmLoader.prototype._loadResources = async function () {
try {
- const texturesPromise = this.loadTextures();
+ const texturesPromise = this._loadTextures();
await texturesPromise;
if (this.isDestroyed()) {
@@ -167,7 +167,7 @@ GltfMeshPrimitiveGpmLoader.prototype.load = function () {
}
this._state = ResourceLoaderState.LOADING;
- this._promise = this.loadResources(this);
+ this._promise = this._loadResources(this);
return this._promise;
};
@@ -185,7 +185,7 @@ function gatherUsedTextureIds(gpmExtension) {
return textureIds;
}
-GltfMeshPrimitiveGpmLoader.prototype.loadTextures = function () {
+GltfMeshPrimitiveGpmLoader.prototype._loadTextures = function () {
let textureIds;
if (defined(this._extension)) {
textureIds = gatherUsedTextureIds(this._extension);
@@ -224,7 +224,7 @@ GltfMeshPrimitiveGpmLoader.prototype.loadTextures = function () {
* A static mapping from PPE texture property identifier keys
* to `MetadataSchema` instances. This is used to create each
* schema (with a certain structure) only ONCE in
- * obtainPpeTexturesMetadataSchema
+ * _obtainPpeTexturesMetadataSchema
*
* @private
*/
@@ -238,7 +238,7 @@ GltfMeshPrimitiveGpmLoader.ppeTexturesMetadataSchemaCache = new Map();
* @param {number} index - The index of the texture in the extension
* @returns The class JSON
*/
-GltfMeshPrimitiveGpmLoader.createPpeTextureClassJson = function (
+GltfMeshPrimitiveGpmLoader._createPpeTextureClassJson = function (
ppeTexture,
index,
) {
@@ -295,16 +295,16 @@ GltfMeshPrimitiveGpmLoader.createPpeTextureClassJson = function (
* schema that reflects the structure of the PPE textures in the
* given instance, creating and caching it if necessary.
*
- * For details on the cache key, see `collectPpeTexturePropertyIdentifiers`
+ * For details on the cache key, see `_collectPpeTexturePropertyIdentifiers`
*
* @param {MeshPrimitiveGpmLocal} meshPrimitiveGpmLocal The extension object
* @returns The `MetadataSchema`
*/
-GltfMeshPrimitiveGpmLoader.obtainPpeTexturesMetadataSchema = function (
+GltfMeshPrimitiveGpmLoader._obtainPpeTexturesMetadataSchema = function (
meshPrimitiveGpmLocal,
) {
const ppeTexturePropertyIdentifiers =
- GltfMeshPrimitiveGpmLoader.collectPpeTexturePropertyIdentifiers(
+ GltfMeshPrimitiveGpmLoader._collectPpeTexturePropertyIdentifiers(
meshPrimitiveGpmLocal,
);
const key = ppeTexturePropertyIdentifiers.toString();
@@ -324,7 +324,7 @@ GltfMeshPrimitiveGpmLoader.obtainPpeTexturesMetadataSchema = function (
for (let i = 0; i < ppeTextures.length; i++) {
const ppeTexture = ppeTextures[i];
const classId = `ppeTexture_${i}`;
- const classJson = GltfMeshPrimitiveGpmLoader.createPpeTextureClassJson(
+ const classJson = GltfMeshPrimitiveGpmLoader._createPpeTextureClassJson(
ppeTexture,
i,
);
@@ -356,7 +356,7 @@ GltfMeshPrimitiveGpmLoader.obtainPpeTexturesMetadataSchema = function (
* @param {MeshPrimitiveGpmLocal} meshPrimitiveGpmLocal The extension object
* @returns The identifiers
*/
-GltfMeshPrimitiveGpmLoader.collectPpeTexturePropertyIdentifiers = function (
+GltfMeshPrimitiveGpmLoader._collectPpeTexturePropertyIdentifiers = function (
meshPrimitiveGpmLocal,
) {
const ppeTexturePropertyIdentifiers = [];
@@ -367,7 +367,7 @@ GltfMeshPrimitiveGpmLoader.collectPpeTexturePropertyIdentifiers = function (
// to define two PPE textures as "representing the same
// property texture property" within a structural metadata
// schema.
- const classJson = GltfMeshPrimitiveGpmLoader.createPpeTextureClassJson(
+ const classJson = GltfMeshPrimitiveGpmLoader._createPpeTextureClassJson(
ppeTexture,
i,
);
@@ -389,13 +389,13 @@ GltfMeshPrimitiveGpmLoader.collectPpeTexturePropertyIdentifiers = function (
* @param {object} textures The mapping from texture ID to texture objects
* @returns The `StructuralMetadata` object
*/
-GltfMeshPrimitiveGpmLoader.convertToStructuralMetadata = function (
+GltfMeshPrimitiveGpmLoader._convertToStructuralMetadata = function (
meshPrimitiveGpmLocal,
textures,
) {
const propertyTextures = [];
const ppeTexturesMetadataSchema =
- GltfMeshPrimitiveGpmLoader.obtainPpeTexturesMetadataSchema(
+ GltfMeshPrimitiveGpmLoader._obtainPpeTexturesMetadataSchema(
meshPrimitiveGpmLocal,
);
const ppeTextures = meshPrimitiveGpmLocal.ppeTextures;
@@ -510,13 +510,11 @@ GltfMeshPrimitiveGpmLoader.prototype.process = function (frameState) {
ppeTextures.push(ppeTexture);
}
}
- const meshPrimitiveGpmLocal = new MeshPrimitiveGpmLocal({
- ppeTextures: ppeTextures,
- });
+ const meshPrimitiveGpmLocal = new MeshPrimitiveGpmLocal(ppeTextures);
this._meshPrimitiveGpmLocal = meshPrimitiveGpmLocal;
const structuralMetadata =
- GltfMeshPrimitiveGpmLoader.convertToStructuralMetadata(
+ GltfMeshPrimitiveGpmLoader._convertToStructuralMetadata(
meshPrimitiveGpmLocal,
textures,
);
@@ -526,7 +524,7 @@ GltfMeshPrimitiveGpmLoader.prototype.process = function (frameState) {
return true;
};
-GltfMeshPrimitiveGpmLoader.prototype.unloadTextures = function () {
+GltfMeshPrimitiveGpmLoader.prototype._unloadTextures = function () {
const textureLoaders = this._textureLoaders;
const textureLoadersLength = textureLoaders.length;
for (let i = 0; i < textureLoadersLength; ++i) {
@@ -541,7 +539,7 @@ GltfMeshPrimitiveGpmLoader.prototype.unloadTextures = function () {
* @private
*/
GltfMeshPrimitiveGpmLoader.prototype.unload = function () {
- this.unloadTextures();
+ this._unloadTextures();
this._gltf = undefined;
this._extension = undefined;
this._structuralMetadata = undefined;
From 860b05b25271607755173654600974b3ee9065f6 Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Sat, 28 Sep 2024 14:39:53 +0200
Subject: [PATCH 35/38] Further clarification for private
---
.../engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js | 2 +-
packages/engine/Source/Scene/Model/Extensions/Gpm/PpeSource.js | 2 +-
packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
index 88bcb70ebee9..e5289c2ef94f 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
@@ -18,7 +18,7 @@ import Check from "../../../../Core/Check.js";
*
* @param {PpeMetadata.ConstructorOptions} options An object describing initialization options
*
- * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
+ * @private
*/
function PpeMetadata(options) {
//>>includeStart('debug', pragmas.debug);
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeSource.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeSource.js
index db0f3676f278..92d1bbedd815 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeSource.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeSource.js
@@ -5,7 +5,7 @@
* {@link https://nsgreg.nga.mil/csmwg.jsp|NGA_gpm_local} glTF extension.
*
* @enum {string}
- * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
+ * @private
*/
const PpeSource = {
/**
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
index 7588fd2a4ed0..24fac262afdf 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
@@ -25,7 +25,7 @@ import Check from "../../../../Core/Check.js";
*
* @param {PpeTexture.ConstructorOptions} options An object describing initialization options
*
- * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
+ * @private
*/
function PpeTexture(options) {
//>>includeStart('debug', pragmas.debug);
From 9bfe61afc1827a6ad9032138f5ffdcc8cbe77d38 Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Sat, 28 Sep 2024 15:13:16 +0200
Subject: [PATCH 36/38] Update spec for changed error type
---
.../Specs/Scene/Model/Extensions/Gpm/GltfGpmLoaderSpec.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/packages/engine/Specs/Scene/Model/Extensions/Gpm/GltfGpmLoaderSpec.js b/packages/engine/Specs/Scene/Model/Extensions/Gpm/GltfGpmLoaderSpec.js
index e6f35b16e09e..ddaf8ddfb390 100644
--- a/packages/engine/Specs/Scene/Model/Extensions/Gpm/GltfGpmLoaderSpec.js
+++ b/packages/engine/Specs/Scene/Model/Extensions/Gpm/GltfGpmLoaderSpec.js
@@ -12,7 +12,7 @@ describe("Scene/Model/Extensions/Gpm/GltfGpmLoader", function () {
};
expect(function () {
GltfGpmLoader.load(gltfGpmLocalJson);
- }).toThrowDeveloperError();
+ }).toThrowError();
});
it("load throws for storageType Direct without anchorPointsDirect", async function () {
@@ -21,7 +21,7 @@ describe("Scene/Model/Extensions/Gpm/GltfGpmLoader", function () {
};
expect(function () {
GltfGpmLoader.load(gltfGpmLocalJson);
- }).toThrowDeveloperError();
+ }).toThrowError();
});
it("load throws for storageType Direct without covarianceDirectUpperTriangle", async function () {
@@ -36,7 +36,7 @@ describe("Scene/Model/Extensions/Gpm/GltfGpmLoader", function () {
};
expect(function () {
GltfGpmLoader.load(gltfGpmLocalJson);
- }).toThrowDeveloperError();
+ }).toThrowError();
});
it("load returns result for valid JSON for storageType Direct", async function () {
From 9805652f03e8ad24895a78929713e1bfd8b8710b Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Sat, 28 Sep 2024 15:13:37 +0200
Subject: [PATCH 37/38] Further options- and constructor documentation
---
.../Model/Extensions/Gpm/AnchorPointDirect.js | 11 +++++++++++
.../Model/Extensions/Gpm/AnchorPointIndirect.js | 12 ++++++++++++
.../Model/Extensions/Gpm/CorrelationGroup.js | 15 +++++++++++++++
.../Scene/Model/Extensions/Gpm/GltfGpmLocal.js | 1 +
.../Model/Extensions/Gpm/MeshPrimitiveGpmLocal.js | 1 +
.../Scene/Model/Extensions/Gpm/PpeMetadata.js | 1 +
.../Scene/Model/Extensions/Gpm/PpeTexture.js | 1 +
.../Source/Scene/Model/Extensions/Gpm/Spdcf.js | 13 +++++++++++++
8 files changed, 55 insertions(+)
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js
index 430240fee98a..7f20273f7a90 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointDirect.js
@@ -1,11 +1,22 @@
import Check from "../../../../Core/Check.js";
+/**
+ * @typedef {object} AnchorPointDirect.ConstructorOptions
+ *
+ * Initialization options for the AnchorPointDirect constructor
+ *
+ * @property {Cartesian3} position Anchor point geographic coordinates
+ * @property {Cartesian3} adjustmentParams The adjustment values in meters
+ */
+
/**
* Metadata for one stored anchor point using direct storage.
*
* This reflects the `anchronPointDirect` definition of the
* {@link https://nsgreg.nga.mil/csmwg.jsp|NGA_gpm_local} glTF extension.
*
+ * @constructor
+ * @param {AnchorPointDirect.ConstructorOptions} options An object describing initialization options
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function AnchorPointDirect(options) {
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js
index 7abe2db94046..b7f368b6d859 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/AnchorPointIndirect.js
@@ -1,11 +1,23 @@
import Check from "../../../../Core/Check.js";
+/**
+ * @typedef {object} AnchorPointIndirect.ConstructorOptions
+ *
+ * Initialization options for the AnchorPointIndirect constructor
+ *
+ * @property {Cartesian3} position Anchor point geographic coordinates
+ * @property {Cartesian3} adjustmentParams The adjustment values in meters
+ * @property {Matrix3} covarianceMatrix The 3x3 covariance matrix
+ */
+
/**
* Metadata for one stored anchor point.
*
* This reflects the `anchronPointIndirect` definition of the
* {@link https://nsgreg.nga.mil/csmwg.jsp|NGA_gpm_local} glTF extension.
*
+ * @constructor
+ * @param {AnchorPointIndirect.ConstructorOptions} options An object describing initialization options
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function AnchorPointIndirect(options) {
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js
index abf0a4e1262d..919ef9ed9991 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/CorrelationGroup.js
@@ -1,5 +1,18 @@
import Check from "../../../../Core/Check.js";
+/**
+ * @typedef {object} CorrelationGroup.ConstructorOptions
+ *
+ * Initialization options for the CorrelationGroup constructor
+ *
+ * @property {boolean[]} groupFlags Array of 3 booleans indicating if
+ * parameters delta-x delta-y delta-z used in the correlation group
+ * @property {Cartesian3} rotationThetas Rotations in milliradians
+ * about X, Y, Z axes, respectively
+ * @property {Spdcf[]} params Array of `Spdcf` (Strictly Positive-Definite
+ * Correlation Function) parameters, for the U, V, W directions, respectively
+ */
+
/**
* Metadata identifying parameters using same correlation modeling and
* associated correlation parameters.
@@ -7,6 +20,8 @@ import Check from "../../../../Core/Check.js";
* This reflects the `correlationGroup` definition of the
* {@link https://nsgreg.nga.mil/csmwg.jsp|NGA_gpm_local} glTF extension.
*
+ * @constructor
+ * @param {CorrelationGroup.ConstructorOptions} options An object describing initialization options
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function CorrelationGroup(options) {
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js
index f58aa27fd361..80339c2247e6 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/GltfGpmLocal.js
@@ -44,6 +44,7 @@ import StorageType from "./StorageType.js";
*
*
*
+ * @constructor
* @param {GltfGpmLocal.ConstructorOptions} options An object describing initialization options
*
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/MeshPrimitiveGpmLocal.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/MeshPrimitiveGpmLocal.js
index c8b76f25b0de..aab7130e859f 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/MeshPrimitiveGpmLocal.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/MeshPrimitiveGpmLocal.js
@@ -3,6 +3,7 @@
*
* @param {PpeTexture[]} ppeTextures The Per-Point Error textures
*
+ * @constructor
* @private
*/
function MeshPrimitiveGpmLocal(ppeTextures) {
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
index e5289c2ef94f..d7c077fe603e 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeMetadata.js
@@ -16,6 +16,7 @@ import Check from "../../../../Core/Check.js";
* This reflects the `ppeMetadata` definition of the
* {@link https://nsgreg.nga.mil/csmwg.jsp|NGA_gpm_local} glTF extension.
*
+ * @constructor
* @param {PpeMetadata.ConstructorOptions} options An object describing initialization options
*
* @private
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
index 24fac262afdf..e81d7605448f 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/PpeTexture.js
@@ -23,6 +23,7 @@ import Check from "../../../../Core/Check.js";
* and an optional `texCoord)`, with additional properties that
* describe the structure of the metdata that is stored in the texture.
*
+ * @constructor
* @param {PpeTexture.ConstructorOptions} options An object describing initialization options
*
* @private
diff --git a/packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js b/packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js
index 74ae2c607c80..1cc01a96b536 100644
--- a/packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js
+++ b/packages/engine/Source/Scene/Model/Extensions/Gpm/Spdcf.js
@@ -1,5 +1,16 @@
import Check from "../../../../Core/Check.js";
+/**
+ * @typedef {object} Spdcf.ConstructorOptions
+ *
+ * Initialization options for the Spdcf constructor
+ *
+ * @property {number} A The factor A, in (0, 1]
+ * @property {number} alpha The alpha value, in [0, 1)
+ * @property {number} beta The beta value, in [0, 10]
+ * @property {number} T the tau value, in (0, +inf)
+ */
+
/**
* Variables for a Strictly Positive-Definite Correlation Function.
*
@@ -14,6 +25,8 @@ import Check from "../../../../Core/Check.js";
* spdcf(delta_t) = A_t * (alpha_t + ((1 - alpha_t)(1 + beta_t)) / (beta_t + e^(delta_t/T_t)))
* ```
*
+ * @constructor
+ * @param {Spdcf.ConstructorOptions} options An object describing initialization options
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function Spdcf(options) {
From c9100904dc03183ee37fe51b4d3f41cce99f76bf Mon Sep 17 00:00:00 2001
From: Marco Hutter
Date: Mon, 30 Sep 2024 16:03:43 +0200
Subject: [PATCH 38/38] Try to revert undesired formatting changes
---
.../3D Tiles Point Cloud Classification.html | 3 +-
.../gallery/3D Tiles Point Cloud Shading.html | 3 +-
.../3D Tiles Terrain Classification.html | 3 +-
.../Custom Per-Feature Post Process.html | 2 +-
.../gallery/Custom Post Process.html | 34 +++++-----
Apps/Sandcastle/gallery/Fog Post Process.html | 68 +++++++++----------
.../gallery/Google Earth Enterprise.html | 2 +-
Apps/Sandcastle/gallery/Materials.html | 22 +++---
.../Scene/ArcGisMapServerImageryProvider.js | 6 +-
.../Model/PrimitiveOutlineGeneratorSpec.js | 2 +-
.../Specs/Scene/Vector3DTilePointsSpec.js | 2 +-
11 files changed, 75 insertions(+), 72 deletions(-)
diff --git a/Apps/Sandcastle/gallery/3D Tiles Point Cloud Classification.html b/Apps/Sandcastle/gallery/3D Tiles Point Cloud Classification.html
index 13b15e133c6d..fedb3b12bb33 100644
--- a/Apps/Sandcastle/gallery/3D Tiles Point Cloud Classification.html
+++ b/Apps/Sandcastle/gallery/3D Tiles Point Cloud Classification.html
@@ -108,7 +108,8 @@
highlighted.feature = pickedFeature;
Cesium.Color.clone(pickedFeature.color, highlighted.originalColor);
pickedFeature.color = Cesium.Color.YELLOW.withAlpha(0.5);
- }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); //Sandcastle_End
+ }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+ //Sandcastle_End
};
if (typeof Cesium !== "undefined") {
window.startupCalled = true;
diff --git a/Apps/Sandcastle/gallery/3D Tiles Point Cloud Shading.html b/Apps/Sandcastle/gallery/3D Tiles Point Cloud Shading.html
index 2241bd0ea04e..3d3dc2a6c10b 100644
--- a/Apps/Sandcastle/gallery/3D Tiles Point Cloud Shading.html
+++ b/Apps/Sandcastle/gallery/3D Tiles Point Cloud Shading.html
@@ -345,7 +345,8 @@
if (Cesium.defined(viewModelTileset)) {
viewModelTileset.pointCloudShading.eyeDomeLighting = checked;
}
- }); //Sandcastle_End
+ });
+ //Sandcastle_End
};
if (typeof Cesium !== "undefined") {
window.startupCalled = true;
diff --git a/Apps/Sandcastle/gallery/3D Tiles Terrain Classification.html b/Apps/Sandcastle/gallery/3D Tiles Terrain Classification.html
index c336e6899595..581814432c70 100644
--- a/Apps/Sandcastle/gallery/3D Tiles Terrain Classification.html
+++ b/Apps/Sandcastle/gallery/3D Tiles Terrain Classification.html
@@ -80,7 +80,8 @@
highlighted.feature = pickedFeature;
Cesium.Color.clone(pickedFeature.color, highlighted.originalColor);
pickedFeature.color = Cesium.Color.YELLOW;
- }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); //Sandcastle_End
+ }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+ //Sandcastle_End
};
if (typeof Cesium !== "undefined") {
window.startupCalled = true;
diff --git a/Apps/Sandcastle/gallery/Custom Per-Feature Post Process.html b/Apps/Sandcastle/gallery/Custom Per-Feature Post Process.html
index 72cc3f2c001d..d08090d9378d 100644
--- a/Apps/Sandcastle/gallery/Custom Per-Feature Post Process.html
+++ b/Apps/Sandcastle/gallery/Custom Per-Feature Post Process.html
@@ -54,7 +54,7 @@
if (czm_selected()) {
vec3 highlighted = highlight.a * highlight.rgb + (1.0 - highlight.a) * color.rgb;
out_FragColor = vec4(highlighted, 1.0);
- } else {
+ } else {
out_FragColor = color;
}
}
diff --git a/Apps/Sandcastle/gallery/Custom Post Process.html b/Apps/Sandcastle/gallery/Custom Post Process.html
index 38eeaf856e9d..39f5450cb271 100644
--- a/Apps/Sandcastle/gallery/Custom Post Process.html
+++ b/Apps/Sandcastle/gallery/Custom Post Process.html
@@ -44,23 +44,23 @@
});
const fragmentShaderSource = `
- uniform sampler2D colorTexture;
- in vec2 v_textureCoordinates;
- const int KERNEL_WIDTH = 16;
- void main(void)
- {
- vec2 step = czm_pixelRatio / czm_viewport.zw;
- vec2 integralPos = v_textureCoordinates - mod(v_textureCoordinates, 8.0 * step);
- vec3 averageValue = vec3(0.0);
- for (int i = 0; i < KERNEL_WIDTH; i++)
- {
- for (int j = 0; j < KERNEL_WIDTH; j++)
- {
- averageValue += texture(colorTexture, integralPos + step * vec2(i, j)).rgb;
- }
- }
- averageValue /= float(KERNEL_WIDTH * KERNEL_WIDTH);
- out_FragColor = vec4(averageValue, 1.0);
+ uniform sampler2D colorTexture;
+ in vec2 v_textureCoordinates;
+ const int KERNEL_WIDTH = 16;
+ void main(void)
+ {
+ vec2 step = czm_pixelRatio / czm_viewport.zw;
+ vec2 integralPos = v_textureCoordinates - mod(v_textureCoordinates, 8.0 * step);
+ vec3 averageValue = vec3(0.0);
+ for (int i = 0; i < KERNEL_WIDTH; i++)
+ {
+ for (int j = 0; j < KERNEL_WIDTH; j++)
+ {
+ averageValue += texture(colorTexture, integralPos + step * vec2(i, j)).rgb;
+ }
+ }
+ averageValue /= float(KERNEL_WIDTH * KERNEL_WIDTH);
+ out_FragColor = vec4(averageValue, 1.0);
}
`;
viewer.scene.postProcessStages.add(
diff --git a/Apps/Sandcastle/gallery/Fog Post Process.html b/Apps/Sandcastle/gallery/Fog Post Process.html
index d3936751c118..8896ca04c059 100644
--- a/Apps/Sandcastle/gallery/Fog Post Process.html
+++ b/Apps/Sandcastle/gallery/Fog Post Process.html
@@ -48,40 +48,40 @@
}
const fragmentShaderSource = `
- float getDistance(sampler2D depthTexture, vec2 texCoords)
- {
- float depth = czm_unpackDepth(texture(depthTexture, texCoords));
- if (depth == 0.0) {
- return czm_infinity;
- }
- vec4 eyeCoordinate = czm_windowToEyeCoordinates(gl_FragCoord.xy, depth);
- return -eyeCoordinate.z / eyeCoordinate.w;
- }
- float interpolateByDistance(vec4 nearFarScalar, float distance)
- {
- float startDistance = nearFarScalar.x;
- float startValue = nearFarScalar.y;
- float endDistance = nearFarScalar.z;
- float endValue = nearFarScalar.w;
- float t = clamp((distance - startDistance) / (endDistance - startDistance), 0.0, 1.0);
- return mix(startValue, endValue, t);
- }
- vec4 alphaBlend(vec4 sourceColor, vec4 destinationColor)
- {
- return sourceColor * vec4(sourceColor.aaa, 1.0) + destinationColor * (1.0 - sourceColor.a);
- }
- uniform sampler2D colorTexture;
- uniform sampler2D depthTexture;
- uniform vec4 fogByDistance;
- uniform vec4 fogColor;
- in vec2 v_textureCoordinates;
- void main(void)
- {
- float distance = getDistance(depthTexture, v_textureCoordinates);
- vec4 sceneColor = texture(colorTexture, v_textureCoordinates);
- float blendAmount = interpolateByDistance(fogByDistance, distance);
- vec4 finalFogColor = vec4(fogColor.rgb, fogColor.a * blendAmount);
- out_FragColor = alphaBlend(finalFogColor, sceneColor);
+ float getDistance(sampler2D depthTexture, vec2 texCoords)
+ {
+ float depth = czm_unpackDepth(texture(depthTexture, texCoords));
+ if (depth == 0.0) {
+ return czm_infinity;
+ }
+ vec4 eyeCoordinate = czm_windowToEyeCoordinates(gl_FragCoord.xy, depth);
+ return -eyeCoordinate.z / eyeCoordinate.w;
+ }
+ float interpolateByDistance(vec4 nearFarScalar, float distance)
+ {
+ float startDistance = nearFarScalar.x;
+ float startValue = nearFarScalar.y;
+ float endDistance = nearFarScalar.z;
+ float endValue = nearFarScalar.w;
+ float t = clamp((distance - startDistance) / (endDistance - startDistance), 0.0, 1.0);
+ return mix(startValue, endValue, t);
+ }
+ vec4 alphaBlend(vec4 sourceColor, vec4 destinationColor)
+ {
+ return sourceColor * vec4(sourceColor.aaa, 1.0) + destinationColor * (1.0 - sourceColor.a);
+ }
+ uniform sampler2D colorTexture;
+ uniform sampler2D depthTexture;
+ uniform vec4 fogByDistance;
+ uniform vec4 fogColor;
+ in vec2 v_textureCoordinates;
+ void main(void)
+ {
+ float distance = getDistance(depthTexture, v_textureCoordinates);
+ vec4 sceneColor = texture(colorTexture, v_textureCoordinates);
+ float blendAmount = interpolateByDistance(fogByDistance, distance);
+ vec4 finalFogColor = vec4(fogColor.rgb, fogColor.a * blendAmount);
+ out_FragColor = alphaBlend(finalFogColor, sceneColor);
}
`;
diff --git a/Apps/Sandcastle/gallery/Google Earth Enterprise.html b/Apps/Sandcastle/gallery/Google Earth Enterprise.html
index 115773cdba69..651d2114543f 100644
--- a/Apps/Sandcastle/gallery/Google Earth Enterprise.html
+++ b/Apps/Sandcastle/gallery/Google Earth Enterprise.html
@@ -52,7 +52,7 @@
);
layers.add(blackMarble);
} catch (error) {
- console.log(`Failed to create Google Earth providers from metadata. Confirm GEE service is correctly configured.
+ console.log(`Failed to create Google Earth providers from metadata. Confirm GEE service is correctly configured.
${error}`);
}
diff --git a/Apps/Sandcastle/gallery/Materials.html b/Apps/Sandcastle/gallery/Materials.html
index 1640330d4f27..803d899b99a8 100644
--- a/Apps/Sandcastle/gallery/Materials.html
+++ b/Apps/Sandcastle/gallery/Materials.html
@@ -112,19 +112,19 @@
},
},
source: `
- czm_material czm_getMaterial(czm_materialInput materialInput) {
- czm_material material = czm_getDefaultMaterial(materialInput);
- vec4 color;
- float heightValue = texture(heightField, materialInput.st).r;
- color.rgb = mix(vec3(0.2, 0.6, 0.2), vec3(1.0, 0.5, 0.2), heightValue);
- color.a = (1.0 - texture(image, materialInput.st).r) * 0.7;
- color = czm_gammaCorrect(color);
- material.diffuse = color.rgb;
- material.alpha = color.a;
- material.normal = bumpMap.normal;
+ czm_material czm_getMaterial(czm_materialInput materialInput) {
+ czm_material material = czm_getDefaultMaterial(materialInput);
+ vec4 color;
+ float heightValue = texture(heightField, materialInput.st).r;
+ color.rgb = mix(vec3(0.2, 0.6, 0.2), vec3(1.0, 0.5, 0.2), heightValue);
+ color.a = (1.0 - texture(image, materialInput.st).r) * 0.7;
+ color = czm_gammaCorrect(color);
+ material.diffuse = color.rgb;
+ material.alpha = color.a;
+ material.normal = bumpMap.normal;
material.specular = step(0.1, heightValue); // Specular mountain tops
material.shininess = 8.0; // Sharpen highlight
- return material;
+ return material;
}
`,
},
diff --git a/packages/engine/Source/Scene/ArcGisMapServerImageryProvider.js b/packages/engine/Source/Scene/ArcGisMapServerImageryProvider.js
index f2768fbc57f6..d1b97d8f6365 100644
--- a/packages/engine/Source/Scene/ArcGisMapServerImageryProvider.js
+++ b/packages/engine/Source/Scene/ArcGisMapServerImageryProvider.js
@@ -260,9 +260,9 @@ async function requestMetadata(resource, imageryProviderBuilder) {
*
* Provides tiled imagery hosted by an ArcGIS MapServer. By default, the server's pre-cached tiles are
* used, if available.
- *
+ *
*
- *
+ *
* An {@link https://developers.arcgis.com/documentation/mapping-apis-and-services/security| ArcGIS Access Token } is required to authenticate requests to an ArcGIS Image Tile service.
* To access secure ArcGIS resources, it's required to create an ArcGIS developer
* account or an ArcGIS online account, then implement an authentication method to obtain an access token.
@@ -278,7 +278,7 @@ async function requestMetadata(resource, imageryProviderBuilder) {
* @example
* // Set the default access token for accessing ArcGIS Image Tile service
* Cesium.ArcGisMapService.defaultAccessToken = "";
- *
+ *
* // Add a base layer from a default ArcGIS basemap
* const viewer = new Cesium.Viewer("cesiumContainer", {
* baseLayer: Cesium.ImageryLayer.fromProviderAsync(
diff --git a/packages/engine/Specs/Scene/Model/PrimitiveOutlineGeneratorSpec.js b/packages/engine/Specs/Scene/Model/PrimitiveOutlineGeneratorSpec.js
index eb73de212900..1e3a0ace79e9 100644
--- a/packages/engine/Specs/Scene/Model/PrimitiveOutlineGeneratorSpec.js
+++ b/packages/engine/Specs/Scene/Model/PrimitiveOutlineGeneratorSpec.js
@@ -263,7 +263,7 @@ describe(
4, 8, 11
]);
// prettier-ignore
- let expectedOutlineCoordinates = new Float32Array([
+ let expectedOutlineCoordinates = new Float32Array([
0, 1, 0,
0, 1, 0,
0, 1, 0,
diff --git a/packages/engine/Specs/Scene/Vector3DTilePointsSpec.js b/packages/engine/Specs/Scene/Vector3DTilePointsSpec.js
index ee9cf1d6d196..b171cc95684b 100644
--- a/packages/engine/Specs/Scene/Vector3DTilePointsSpec.js
+++ b/packages/engine/Specs/Scene/Vector3DTilePointsSpec.js
@@ -431,7 +431,7 @@ describe(
/*[
Cesium3DTileStyle option,
Cesium3DTileStyle default value,
- Cesium3DTileFeature property,
+ Cesium3DTileFeature property,
expected Cesium3DTileFeature value,
expected undefined Cesium3DTileFeature value
]*/