From 44d5484ffbe6c4b2bd21975b9249a85b88b4fb52 Mon Sep 17 00:00:00 2001 From: mspivak-actionengine Date: Thu, 21 Sep 2023 16:53:39 +0300 Subject: [PATCH 1/3] fix(gltf, converter): make ext-mesh-features independent from ext-structural-metadata. Fix comments on prev pr --- modules/3d-tiles/src/types.ts | 8 +- modules/gltf/src/index.ts | 13 +- modules/gltf/src/lib/api/gltf-extensions.ts | 2 +- .../src/lib/extensions/EXT_mesh_features.ts | 60 +-- .../lib/extensions/EXT_structural_metadata.ts | 259 ++++++---- .../deprecated/EXT_feature_metadata.ts | 77 ++- .../lib/extensions/utils/3d-tiles-utils.ts | 80 +-- modules/gltf/src/lib/gltf-utils/gltf-utils.ts | 35 ++ .../types/gltf-ext-feature-metadata-schema.ts | 470 ++++++++++++++++++ .../types/gltf-ext-mesh-features-schema.ts | 10 +- .../gltf-ext-structural-metadata-schema.ts | 71 ++- .../gltf/src/lib/types/gltf-json-schema.ts | 469 +---------------- modules/gltf/src/lib/types/gltf-types.ts | 4 + modules/gltf/test/index.js | 1 + .../lib/extensions/EXT_mesh_features.spec.ts | 196 ++++++++ .../EXT_structural_metadata.spec.ts | 3 +- .../helpers/batch-ids-extensions.ts | 15 +- .../helpers/geometry-converter.ts | 139 +----- .../src/i3s-converter/i3s-converter.ts | 2 - 19 files changed, 1087 insertions(+), 827 deletions(-) create mode 100644 modules/gltf/src/lib/types/gltf-ext-feature-metadata-schema.ts create mode 100644 modules/gltf/test/lib/extensions/EXT_mesh_features.spec.ts diff --git a/modules/3d-tiles/src/types.ts b/modules/3d-tiles/src/types.ts index 8ff63d391e..daa13970bd 100644 --- a/modules/3d-tiles/src/types.ts +++ b/modules/3d-tiles/src/types.ts @@ -1,12 +1,10 @@ -import type {GLTFPostprocessed} from '@loaders.gl/gltf'; +import type {GLTFPostprocessed, FeatureTableJson} from '@loaders.gl/gltf'; +export type {FeatureTableJson}; + import {LoaderWithParser} from '@loaders.gl/loader-utils'; import {Matrix4, Vector3} from '@math.gl/core'; import {TILESET_TYPE, LOD_METRIC_TYPE, TILE_TYPE, TILE_REFINEMENT} from '@loaders.gl/tiles'; -export type FeatureTableJson = { - [key: string]: any[]; -}; - export type B3DMContent = { batchTableJson?: FeatureTableJson; byteLength: number; diff --git a/modules/gltf/src/index.ts b/modules/gltf/src/index.ts index b1b0a9ebf2..3203b6722c 100644 --- a/modules/gltf/src/index.ts +++ b/modules/gltf/src/index.ts @@ -22,8 +22,11 @@ export type { GLTF_KHR_draco_mesh_compression, GLTF_KHR_texture_basisu, GLTF_EXT_meshopt_compression, - GLTF_EXT_texture_webp, - // 3DTiles extensions + GLTF_EXT_texture_webp +} from './lib/types/gltf-json-schema'; + +// 3DTiles extensions +export type { GLTF_EXT_feature_metadata_GLTF, GLTF_EXT_feature_metadata_Schema, GLTF_EXT_feature_metadata_Class, @@ -42,7 +45,7 @@ export type { GLTF_EXT_feature_metadata_FeatureIdAttributeFeatureIds, GLTF_EXT_feature_metadata_FeatureIdTexture, GLTF_EXT_feature_metadata_FeatureIdTextureAccessor -} from './lib/types/gltf-json-schema'; +} from './lib/types/gltf-ext-feature-metadata-schema'; export type {GLTF_EXT_structural_metadata_GLTF} from './lib/types/gltf-ext-structural-metadata-schema'; @@ -54,6 +57,8 @@ export type { export {name as EXT_MESH_FEATURES} from './lib/extensions/EXT_mesh_features'; export {name as EXT_STRUCTURAL_METADATA} from './lib/extensions/EXT_structural_metadata'; export {name as EXT_FEATURE_METADATA} from './lib/extensions/deprecated/EXT_feature_metadata'; +export {getPropertyTableFromExtFeatureMetadata} from './lib/extensions/deprecated/EXT_feature_metadata'; +export {getPropertyTableFromExtStructuralMetadata} from './lib/extensions/EXT_structural_metadata'; // Postprocessed types (modified GLTF types) export type { @@ -67,7 +72,7 @@ export type { GLTFTexturePostprocessed } from './lib/types/gltf-postprocessed-schema'; -export type {GLTFWithBuffers} from './lib/types/gltf-types'; +export type {GLTFWithBuffers, FeatureTableJson} from './lib/types/gltf-types'; // glTF loader/writer definition objects export {GLTFLoader} from './gltf-loader'; diff --git a/modules/gltf/src/lib/api/gltf-extensions.ts b/modules/gltf/src/lib/api/gltf-extensions.ts index 452a1737b9..28174e9f26 100644 --- a/modules/gltf/src/lib/api/gltf-extensions.ts +++ b/modules/gltf/src/lib/api/gltf-extensions.ts @@ -47,8 +47,8 @@ export const EXTENSIONS: GLTFExtensionPlugin[] = [ // KHR_binary_gltf, // 2.0 - EXT_mesh_features, EXT_structural_metadata, + EXT_mesh_features, EXT_meshopt_compression, EXT_texture_webp, // Basisu should come after webp, we want basisu to be preferred if both are provided diff --git a/modules/gltf/src/lib/extensions/EXT_mesh_features.ts b/modules/gltf/src/lib/extensions/EXT_mesh_features.ts index 39af8f9fa7..38452d007c 100644 --- a/modules/gltf/src/lib/extensions/EXT_mesh_features.ts +++ b/modules/gltf/src/lib/extensions/EXT_mesh_features.ts @@ -7,11 +7,9 @@ import type { GLTF_EXT_mesh_features, GLTF_EXT_mesh_features_featureId } from '../types/gltf-ext-mesh-features-schema'; -import type {GLTF_EXT_structural_metadata_PropertyTable} from '../types/gltf-ext-structural-metadata-schema'; import {GLTFScenegraph} from '../api/gltf-scenegraph'; -import {getPrimitiveTextureData, primitivePropertyDataToAttributes} from './utils/3d-tiles-utils'; -import {getPropertyTablePopulated} from './EXT_structural_metadata'; +import {getPrimitiveTextureData} from './utils/3d-tiles-utils'; const EXT_MESH_FEATURES_NAME = 'EXT_mesh_features'; export const name = EXT_MESH_FEATURES_NAME; @@ -22,9 +20,9 @@ export async function decode(gltfData: {json: GLTF}, options: GLTFLoaderOptions) } /** - * Decodes feature metadata from extension + * Decodes feature metadata from extension. * @param {GLTFScenegraph} scenegraph - Instance of the class for structured access to GLTF data. - * @param {GLTFLoaderOptions} options - loader options. + * @param {GLTFLoaderOptions} options - GLTFLoader options. */ function decodeExtMeshFeatures(scenegraph: GLTFScenegraph, options: GLTFLoaderOptions): void { const json = scenegraph.gltf.json; @@ -44,47 +42,38 @@ function decodeExtMeshFeatures(scenegraph: GLTFScenegraph, options: GLTFLoaderOp * Takes data from EXT_mesh_features and store it in 'data' property of featureIds. * If combined with EXT_structural_metadata, corresponding data are taken from the property tables of that extension. * @param {GLTFScenegraph} scenegraph - Instance of the class for structured access to GLTF data. - * @param {GLTFMeshPrimitive} primitive - primitive that contains extensions. - * @param {GLTFLoaderOptions} options - loader options. + * @param {GLTFMeshPrimitive} primitive - Primitive that contains extensions. + * @param {GLTFLoaderOptions} options - GLTFLoader options. */ function processMeshPrimitiveFeatures( scenegraph: GLTFScenegraph, primitive: GLTFMeshPrimitive, options: GLTFLoaderOptions ): void { + // Processing of mesh primitive features requires buffers to be loaded. + if (!options?.gltf?.loadBuffers) { + return; + } + const extension = primitive.extensions?.[EXT_MESH_FEATURES_NAME] as GLTF_EXT_mesh_features; const featureIds: GLTF_EXT_mesh_features_featureId[] = extension?.featureIds; - if (!featureIds) return; - if (!extension.dataAttributeNames) { - extension.dataAttributeNames = []; + if (!featureIds) { + return; } - let featureIdCount = 0; // It can be used to name the feature if neither label nor property table name is provided. for (const featureId of featureIds) { - /* - When combined with the EXT_structural_metadata extension, feature ID sets can be associated with property tables. - A property table maps each feature ID to a set of values that are associated with the respective feature. - The feature ID in this case serves as an index for the row of the table. - The index of the property table that a certain set of feature IDs is associated with is stored in the propertyTable of the feature ID set definition. - */ - let propertyTable: GLTF_EXT_structural_metadata_PropertyTable | null = null; - if (typeof featureId.propertyTable === 'number') { - propertyTable = getPropertyTablePopulated(scenegraph, featureId.propertyTable); - } - - let propertyData: number[] | null = null; + let featureIdData: number[] | null = null; // Process "Feature ID by Vertex" if (typeof featureId.attribute !== 'undefined') { const accessorKey = `_FEATURE_ID_${featureId.attribute}`; const accessorIndex = primitive.attributes[accessorKey]; - const propertyDataTypedArray = scenegraph.getTypedArrayForAccessor(accessorIndex); - propertyData = Array.prototype.slice.call(propertyDataTypedArray); + featureIdData = scenegraph.getTypedArrayForAccessor(accessorIndex) as number[]; } // Process "Feature ID by Texture Coordinates" else if (typeof featureId.texture !== 'undefined' && options?.gltf?.loadImages) { - propertyData = getPrimitiveTextureData(scenegraph, featureId.texture, primitive); + featureIdData = getPrimitiveTextureData(scenegraph, featureId.texture, primitive); } // Process "Feature ID by Index" @@ -97,23 +86,6 @@ function processMeshPrimitiveFeatures( // TODO: At the moment of writing we don't have a tileset with the data of that kind. Implement it later. } - const attributeName = - featureId.label || propertyTable?.name || `featureAttribute${featureIdCount}`; - - // featureTable - an array where unique data from the property data are being stored - const featureTable: number[] = []; - if (propertyData) { - primitivePropertyDataToAttributes( - scenegraph, - attributeName, - propertyData, - featureTable, - primitive - ); - } - extension.dataAttributeNames.push(attributeName); - featureId.data = featureTable; - - featureIdCount++; + featureId.data = featureIdData; } } diff --git a/modules/gltf/src/lib/extensions/EXT_structural_metadata.ts b/modules/gltf/src/lib/extensions/EXT_structural_metadata.ts index fa307bf96a..11a126bcfe 100644 --- a/modules/gltf/src/lib/extensions/EXT_structural_metadata.ts +++ b/modules/gltf/src/lib/extensions/EXT_structural_metadata.ts @@ -15,6 +15,7 @@ import type { GLTF_EXT_structural_metadata_Primitive } from '../types/gltf-ext-structural-metadata-schema'; import type {GLTFLoaderOptions} from '../../gltf-loader'; +import type {FeatureTableJson} from '../types/gltf-types'; import {GLTFScenegraph} from '../api/gltf-scenegraph'; import { @@ -34,6 +35,51 @@ export async function decode(gltfData: {json: GLTF}, options: GLTFLoaderOptions) decodeExtStructuralMetadata(scenegraph, options); } +/** + * Handles EXT_structural_metadata to get property table. + * @param extension - Global level of EXT_STRUCTURAL_METADATA extension. + * @param metadataClass - User selected feature metadata class name. + * @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly. + */ +export function getPropertyTableFromExtStructuralMetadata( + extension: GLTF_EXT_structural_metadata_GLTF, + metadataClass?: string +): FeatureTableJson | null { + if (extension.propertyTables) { + /** + * Take only first feature table to generate attributes storage info object. + * TODO: Think about getting data from all feature tables? + * It can be tricky just because 3dTiles is able to have multiple featureId attributes and multiple feature tables. + * In I3S we should decide which featureIds attribute will be passed to geometry data. + */ + const firstPropertyTable = extension?.propertyTables[0]; + const propertyTableWithData = {}; + + for (const propertyName in firstPropertyTable.properties) { + propertyTableWithData[propertyName] = firstPropertyTable.properties[propertyName].data; + } + + return propertyTableWithData; + } + + if (extension.propertyTextures) { + // TODO: Think about getting data from all property textures. + const firstPropertyTexture = extension?.propertyTextures[0]; + const propertyTableWithData = {}; + + for (const propertyName in firstPropertyTexture.properties) { + propertyTableWithData[propertyName] = firstPropertyTexture.properties[propertyName].data; + } + + return propertyTableWithData; + } + + console.warn( + "Can't get property table from EXT_structural_metadata extension. There is neither propertyTables, nor propertyTextures in the extension." + ); + return null; +} + /* // Example of the extension. // See more info at https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_structural_metadata @@ -116,21 +162,42 @@ export function getPropertyTablePopulated( } /** - * Decodes feature metadata from extension + * Decodes feature metadata from extension. * @param scenegraph - Instance of the class for structured access to GLTF data. - * @param options - loader options. + * @param options - GLTFLoader options. */ function decodeExtStructuralMetadata(scenegraph: GLTFScenegraph, options: GLTFLoaderOptions): void { + // Decoding metadata involves buffers processing. + // So, if buffers have not been loaded, there is no reason to process metadata. + if (!options.gltf?.loadBuffers) { + return; + } const extension: GLTF_EXT_structural_metadata_GLTF | null = scenegraph.getExtension( EXT_STRUCTURAL_METADATA_NAME ); - if (!extension?.schema) { + if (!extension) { return; } + if (options.gltf?.loadImages) { + decodePropertyTextures(scenegraph, extension); + } + + decodePropertyTables(scenegraph, extension); +} + +/** + * Processes the data stored in the textures + * @param scenegraph - Instance of the class for structured access to GLTF data. + * @param extension - Top-level extension. + */ +function decodePropertyTextures( + scenegraph: GLTFScenegraph, + extension: GLTF_EXT_structural_metadata_GLTF +): void { const propertyTextures = extension.propertyTextures; const json = scenegraph.gltf.json; - if (propertyTextures && json.meshes && options?.gltf?.loadImages) { + if (propertyTextures && json.meshes) { // Iterate through all meshes/primitives. for (const mesh of json.meshes) { for (const primitive of mesh.primitives) { @@ -138,31 +205,43 @@ function decodeExtStructuralMetadata(scenegraph: GLTFScenegraph, options: GLTFLo } } } +} - const schemaClasses = extension.schema.classes; +/** + * Processes the data stored in the property tables. + * @param scenegraph - Instance of the class for structured access to GLTF data. + * @param extension - Top-level extension. + */ +function decodePropertyTables( + scenegraph: GLTFScenegraph, + extension: GLTF_EXT_structural_metadata_GLTF +): void { + const schema = extension.schema; + if (!schema) { + return; + } + const schemaClasses = schema.classes; const propertyTables = extension.propertyTables; if (schemaClasses && propertyTables) { for (const schemaName in schemaClasses) { const propertyTable = findPropertyTableByClass(propertyTables, schemaName); if (propertyTable) { - processPropertyTable(scenegraph, extension.schema, propertyTable); + processPropertyTable(scenegraph, schema, propertyTable); } } } } /** - * Find the property table by class name. - * @param propertyTables - propertyTable definition taken from the top-level extension - * @param schemaClassName - class name in the extension schema + * Finds the property table by class name. + * @param propertyTables - propertyTable definition taken from the top-level extension. + * @param schemaClassName - class name in the extension schema. */ function findPropertyTableByClass( propertyTables: GLTF_EXT_structural_metadata_PropertyTable[], schemaClassName: string ): GLTF_EXT_structural_metadata_PropertyTable | null { - for (let i = 0, len = propertyTables.length; i < len; i++) { - const propertyTable = propertyTables[i]; - + for (const propertyTable of propertyTables) { if (propertyTable.class === schemaClassName) { return propertyTable; } @@ -172,11 +251,11 @@ function findPropertyTableByClass( } /** - * Takes data from property textures reffered by the primitive + * Takes data from property textures reffered by the primitive. * @param scenegraph - Instance of the class for structured access to GLTF data. - * @param propertyTextures - propertyTexture definition taken from the top-level extention - * @param primitive - Primitive object - * @param extension - top-level extension + * @param propertyTextures - propertyTexture definition taken from the top-level extention. + * @param primitive - Primitive object. + * @param extension - Top-level extension. */ function processPrimitivePropertyTextures( scenegraph: GLTFScenegraph, @@ -202,11 +281,11 @@ function processPrimitivePropertyTextures( } /** - * Takes property data from the texture pointed by the primitive and appends them to `exension.data` + * Takes property data from the texture pointed by the primitive and appends them to `exension.data`. * @param scenegraph - Instance of the class for structured access to GLTF data. * @param propertyTexture - propertyTexture definition taken from the top-level extension. - * @param primitive - Primitive object - * @param extension - top-level extension + * @param primitive - Primitive object. + * @param extension - Top-level extension. */ function processPrimitivePropertyTexture( scenegraph: GLTFScenegraph, @@ -240,12 +319,12 @@ function processPrimitivePropertyTexture( } */ const className = propertyTexture.class; - for (const propName in propertyTexture.properties) { - // propName has values like "speed", "direction" + for (const propertyName in propertyTexture.properties) { + // propertyName has values like "speed", "direction" // Make attributeName as a combination of the class name and the propertyName like "wind_speed" or "wind_direction" - const attributeName = `${className}_${propName}`; + const attributeName = `${className}_${propertyName}`; const textureInfoTopLevel: GLTFTextureInfoMetadata | undefined = - propertyTexture.properties?.[propName]; + propertyTexture.properties?.[propertyName]; if (!textureInfoTopLevel) { // eslint-disable-next-line no-continue continue; @@ -283,8 +362,8 @@ function processPrimitivePropertyTexture( * Navigates through all properies in the property table, gets properties data, * and put the data to `propertyTable.data` as an array. * @param scenegraph - Instance of the class for structured access to GLTF data. - * @param schema - schema object - * @param propertyTable - propertyTable definition taken from the top-level extension + * @param schema - schema object. + * @param propertyTable - propertyTable definition taken from the top-level extension. */ function processPropertyTable( scenegraph: GLTFScenegraph, @@ -320,12 +399,12 @@ function processPropertyTable( } /** - * Decodes a propertyTable column from binary source based on property type + * Decodes a propertyTable column from binary source based on property type. * @param scenegraph - Instance of the class for structured access to GLTF data. - * @param schema - Schema object - * @param classProperty - class property object + * @param schema - Schema object. + * @param classProperty - class property object. * @param numberOfElements - The number of elements in each property array that propertyTableProperty contains. It's a number of rows in the table. - * @param propertyTableProperty - propertyTable's property metadata + * @param propertyTableProperty - propertyTable's property metadata. * @returns {string[] | number[] | string[][] | number[][]} */ function getPropertyDataFromBinarySource( @@ -394,12 +473,12 @@ function getPropertyDataFromBinarySource( } /** - * Parse propertyTable.property.arrayOffsets that are offsets of sub-arrays in a flatten array of values + * Parses propertyTable.property.arrayOffsets that are offsets of sub-arrays in a flatten array of values. * @param scenegraph - Instance of the class for structured access to GLTF data. - * @param classProperty - class property object - * @param propertyTableProperty - propertyTable's property metadata + * @param classProperty - class property object. + * @param propertyTableProperty - propertyTable's property metadata. * @param numberOfElements - The number of elements in each property array that propertyTableProperty contains. It's a number of rows in the table. - * @returns typed array with offset values + * @returns Typed array with offset values. * @see https://github.com/CesiumGS/glTF/blob/2976f1183343a47a29e4059a70961371cd2fcee8/extensions/2.0/Vendor/EXT_structural_metadata/schema/propertyTable.property.schema.json#L21 */ function getArrayOffsetsForProperty( @@ -414,14 +493,13 @@ function getArrayOffsetsForProperty( // If `count` is NOT defined, it's a VARIABLE-length array typeof classProperty.count === 'undefined' && // `arrayOffsets` is an index of the buffer view containing offsets for variable-length arrays. - typeof propertyTableProperty.arrayOffsets !== 'undefined' && - typeof propertyTableProperty.arrayOffsetType !== 'undefined' + typeof propertyTableProperty.arrayOffsets !== 'undefined' ) { // Data are in a VARIABLE-length array return getOffsetsForProperty( scenegraph, propertyTableProperty.arrayOffsets, - propertyTableProperty.arrayOffsetType, + propertyTableProperty.arrayOffsetType || 'UINT32', numberOfElements ); } @@ -429,11 +507,11 @@ function getArrayOffsetsForProperty( } /** - * Parse propertyTable.property.stringOffsets - * @param scenegraph - Instance of the class for structured access to GLTF data - * @param propertyTableProperty - propertyTable's property metadata - * @param numberOfElements - The number of elements in each property array that propertyTableProperty contains. It's a number of rows in the table - * @returns typed array with offset values + * Parses propertyTable.property.stringOffsets. + * @param scenegraph - Instance of the class for structured access to GLTF data. + * @param propertyTableProperty - propertyTable's property metadata. + * @param numberOfElements - The number of elements in each property array that propertyTableProperty contains. It's a number of rows in the table. + * @returns Typed array with offset values. * @see https://github.com/CesiumGS/glTF/blob/2976f1183343a47a29e4059a70961371cd2fcee8/extensions/2.0/Vendor/EXT_structural_metadata/schema/propertyTable.property.schema.json#L29C10-L29C23 */ function getStringOffsetsForProperty( @@ -442,14 +520,13 @@ function getStringOffsetsForProperty( numberOfElements: number ): TypedArray | null { if ( - typeof propertyTableProperty.stringOffsets !== 'undefined' && // `stringOffsets` is an index of the buffer view containing offsets for strings. - typeof propertyTableProperty.stringOffsetType !== 'undefined' + typeof propertyTableProperty.stringOffsets !== 'undefined' // `stringOffsets` is an index of the buffer view containing offsets for strings. ) { // Data are in a FIXED-length array return getOffsetsForProperty( scenegraph, propertyTableProperty.stringOffsets, - propertyTableProperty.stringOffsetType, + propertyTableProperty.stringOffsetType || 'UINT32', numberOfElements ); } @@ -458,11 +535,11 @@ function getStringOffsetsForProperty( /** * Decodes properties of SCALAR, VEC-N, MAT-N types from binary sourse. - * @param classProperty - class property object + * @param classProperty - class property object. * @param numberOfElements - The number of elements in each property array that propertyTableProperty contains. It's a number of rows in the table. - * @param valuesDataBytes - data taken from values property of the property table property. - * @param arrayOffsets - offsets for variable-length arrays. It's null for fixed-length arrays or scalar types. - * @returns property values in a typed array or in an array of typed arrays + * @param valuesDataBytes - Data taken from values property of the property table property. + * @param arrayOffsets - Offsets for variable-length arrays. It's null for fixed-length arrays or scalar types. + * @returns Property values in a typed array or in an array of typed arrays. */ function getPropertyDataNumeric( classProperty: GLTF_EXT_structural_metadata_ClassProperty, @@ -515,15 +592,15 @@ function getPropertyDataNumeric( } /** - * Parse variable-length array data. + * Parses variable-length array data. * In this case every value of the property in the table will be an array - * of arbitrary length - * @param valuesData - values in a flat typed array - * @param numberOfElements - number of rows in the property table - * @param arrayOffsets - offsets of nested arrays in the flat values array - * @param valuesDataBytesLength - data byte length - * @param valueSize - value size in bytes - * @returns array of typed arrays + * of arbitrary length. + * @param valuesData - Values in a flat typed array. + * @param numberOfElements - Number of rows in the property table. + * @param arrayOffsets - Offsets of nested arrays in the flat values array. + * @param valuesDataBytesLength - Data byte length. + * @param valueSize - Value size in bytes. + * @returns Array of typed arrays. */ function parseVariableLengthArrayNumeric( valuesData: BigTypedArray, @@ -547,13 +624,13 @@ function parseVariableLengthArrayNumeric( } /** - * Parse fixed-length array data + * Parses fixed-length array data. * In this case every value of the property in the table will be an array - * of constant length equal to `arrayCount` - * @param valuesData - values in a flat typed array - * @param numberOfElements - number of rows in the property table - * @param arrayCount - nested arrays length - * @returns array of typed arrays + * of constant length equal to `arrayCount`. + * @param valuesData - Values in a flat typed array. + * @param numberOfElements - Number of rows in the property table. + * @param arrayCount - Nested arrays length. + * @returns Array of typed arrays. */ function parseFixedLengthArrayNumeric( valuesData: BigTypedArray, @@ -570,12 +647,12 @@ function parseFixedLengthArrayNumeric( /** * Decodes properties of string type from binary source. - * @param classProperty - class property object + * @param classProperty - Class property object. * @param numberOfElements - The number of elements in each property array that propertyTableProperty contains. It's a number of rows in the table. - * @param valuesDataBytes - data taken from values property of the property table property. - * @param arrayOffsets - offsets for variable-length arrays. It's null for fixed-length arrays or scalar types. - * @param stringOffsets - index of the buffer view containing offsets for strings. It should be available for string type. - * @returns string property values + * @param valuesDataBytes - Data taken from values property of the property table property. + * @param arrayOffsets - Offsets for variable-length arrays. It's null for fixed-length arrays or scalar types. + * @param stringOffsets - Index of the buffer view containing offsets for strings. It should be available for string type. + * @returns String property values */ function getPropertyDataString( classProperty: GLTF_EXT_structural_metadata_ClassProperty, @@ -613,12 +690,12 @@ function getPropertyDataString( /** * Decodes properties of enum type from binary source. - * @param schema - schema object - * @param classProperty - class property object + * @param schema - Schema object. + * @param classProperty - Class property object. * @param numberOfElements - The number of elements in each property array that propertyTableProperty contains. It's a number of rows in the table. - * @param valuesDataBytes - data taken from values property of the property table property. - * @param arrayOffsets - offsets for variable-length arrays. It's null for fixed-length arrays or scalar types. - * @returns strings array of nested strings array + * @param valuesDataBytes - Data taken from values property of the property table property. + * @param arrayOffsets - Offsets for variable-length arrays. It's null for fixed-length arrays or scalar types. + * @returns Strings array of nested strings array. */ function getPropertyDataENUM( schema: GLTF_EXT_structural_metadata_Schema, @@ -681,14 +758,14 @@ function getPropertyDataENUM( } /** - * Parse variable length nested ENUM arrays - * @param params.valuesData - values in a flat typed array + * Parses variable length nested ENUM arrays. + * @param params.valuesData - Values in a flat typed array. * @param params.numberOfElements - The number of elements in each property array that propertyTableProperty contains. It's a number of rows in the table. - * @param params.arrayOffsets - offsets for variable-length arrays. It's null for fixed-length arrays or scalar types. - * @param params.valuesDataBytesLength - byte length of values array - * @param params.elementSize - single element byte size - * @param params.enumEntry - enums dictionary - * @returns nested strings array + * @param params.arrayOffsets - Offsets for variable-length arrays. It's null for fixed-length arrays or scalar types. + * @param params.valuesDataBytesLength - Byte length of values array. + * @param params.elementSize - Single element byte size. + * @param params.enumEntry - Enums dictionary. + * @returns Nested strings array. */ function parseVariableLengthArrayENUM(params: { valuesData: BigTypedArray; @@ -723,12 +800,12 @@ function parseVariableLengthArrayENUM(params: { } /** - * Parse fixed length ENUM arrays - * @param valuesData - values in a flat typed array + * Parses fixed length ENUM arrays. + * @param valuesData - Values in a flat typed array. * @param numberOfElements - The number of elements in each property array that propertyTableProperty contains. It's a number of rows in the table. - * @param arrayCount - nested arrays length - * @param enumEntry - enums dictionary - * @returns nested strings array + * @param arrayCount - Nested arrays length. + * @param enumEntry - Enums dictionary. + * @returns Nested strings array. */ function parseFixedLengthArrayENUM( valuesData: BigTypedArray, @@ -746,12 +823,12 @@ function parseFixedLengthArrayENUM( } /** - * Parse ENUM values into a string array - * @param valuesData - values in a flat typed array - * @param offset - offset to start parse from - * @param count - values length to parse - * @param enumEntry - enums dictionary - * @returns array of string with parsed ENUM names + * Parses ENUM values into a string array. + * @param valuesData - Values in a flat typed array. + * @param offset - Offset to start parse from. + * @param count - Values length to parse. + * @param enumEntry - Enums dictionary. + * @returns Array of strings with parsed ENUM names. */ function getEnumsArray( valuesData: BigTypedArray, @@ -782,7 +859,7 @@ function getEnumsArray( /** * Looks up ENUM whose `value` property matches the specified number in the parameter `value`. * @param {GLTF_EXT_structural_metadata_Enum} enumEntry - ENUM entry containing the array of possible enums. - * @param {number} value - the value of the ENUM to locate. + * @param {number} value - The value of the ENUM to locate. * @returns {GLTF_EXT_structural_metadata_EnumValue | null} ENUM matcihng the specified value or null of no ENUM object was found. */ function getEnumByValue( diff --git a/modules/gltf/src/lib/extensions/deprecated/EXT_feature_metadata.ts b/modules/gltf/src/lib/extensions/deprecated/EXT_feature_metadata.ts index c23134ffa8..e1f96d71b0 100644 --- a/modules/gltf/src/lib/extensions/deprecated/EXT_feature_metadata.ts +++ b/modules/gltf/src/lib/extensions/deprecated/EXT_feature_metadata.ts @@ -1,6 +1,6 @@ /* eslint-disable camelcase */ +import type {GLTF} from '../../types/gltf-json-schema'; import type { - GLTF, GLTF_EXT_feature_metadata_Class, GLTF_EXT_feature_metadata_ClassProperty, GLTF_EXT_feature_metadata_FeatureTable, @@ -8,12 +8,13 @@ import type { GLTF_EXT_feature_metadata_FeatureTexture, GLTF_EXT_feature_metadata_GLTF, GLTF_EXT_feature_metadata_TextureAccessor -} from '../../types/gltf-json-schema'; +} from '../../types/gltf-ext-feature-metadata-schema'; import type {BigTypedArray, TypedArray} from '@loaders.gl/schema'; +import type {FeatureTableJson} from '../../types/gltf-types'; import {GLTFScenegraph} from '../../api/gltf-scenegraph'; import {getImageData} from '@loaders.gl/images'; import {GLTFMeshPrimitive} from '../../types/gltf-json-schema'; -import {getComponentTypeFromArray} from '../../gltf-utils/gltf-utils'; +import {getComponentTypeFromArray, getFloat32ArrayForAccessor} from '../../gltf-utils/gltf-utils'; import {GLTFLoaderOptions} from '../../../gltf-loader'; import {emod} from '@loaders.gl/math'; import {convertRawBufferToMetadataArray, getOffsetsForProperty} from '../utils/3d-tiles-utils'; @@ -27,6 +28,64 @@ export async function decode(gltfData: {json: GLTF}, options: GLTFLoaderOptions) decodeExtFeatureMetadata(scenegraph, options); } +/** + * Handles EXT_feature_metadata to get property table. + * @param extension - Global level of EXT_FEATURE_METADATA extension. + * @param metadataClass - User selected feature metadata class name. + * @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly. + */ +export function getPropertyTableFromExtFeatureMetadata( + extension: GLTF_EXT_feature_metadata_GLTF, + metadataClass?: string +): FeatureTableJson | null { + if (extension.featureTables) { + /** + * Take only first feature table to generate attributes storage info object. + * TODO: Think about getting data from all feature tables? + * It can be tricky just because 3dTiles is able to have multiple featureId attributes and multiple feature tables. + * In I3S we should decide which featureIds attribute will be passed to geometry data. + */ + const firstFeatureTableName = Object.keys(extension.featureTables)?.[0]; + + if (firstFeatureTableName) { + const featureTable = extension.featureTables[firstFeatureTableName]; + const propertyTable = {}; + + for (const propertyName in featureTable.properties) { + propertyTable[propertyName] = featureTable.properties[propertyName].data; + } + + return propertyTable; + } + } + + if (extension.featureTextures) { + let featureTexture: string | undefined; + for (const textureKey in extension.featureTextures) { + const texture = extension.featureTextures[textureKey]; + if (texture.class === metadataClass) { + featureTexture = textureKey; + } + } + + if (typeof featureTexture === 'string') { + const featureTable = extension.featureTextures[featureTexture]; + const propertyTable = {}; + + for (const propertyName in featureTable.properties) { + propertyTable[propertyName] = featureTable.properties[propertyName].data; + } + + return propertyTable; + } + } + + console.warn( + "Can't get property table from EXT_feature_metadata extension. There is neither featureTables, nor featureTextures in the extension." + ); + return null; +} + /** * Decodes feature metadata from extension * @param scenegraph @@ -320,16 +379,12 @@ function processPrimitiveTextures( const textureData: number[] = []; const texCoordAccessorKey = `TEXCOORD_${featureTextureProperty.texture.texCoord}`; const texCoordAccessorIndex = primitive.attributes[texCoordAccessorKey]; - const texCoordBufferView = scenegraph.getBufferView(texCoordAccessorIndex); - const texCoordArray: Uint8Array = scenegraph.getTypedArrayForBufferView(texCoordBufferView); - - const textureCoordinates: Float32Array = new Float32Array( - texCoordArray.buffer, - texCoordArray.byteOffset, - texCoordArray.length / 4 - ); // textureCoordinates contains UV coordinates of the actual data stored in the texture // accessor.count is a number of UV pairs (they are stored as VEC2) + const textureCoordinates: Float32Array | null = getFloat32ArrayForAccessor(scenegraph.gltf, texCoordAccessorIndex); + if (!textureCoordinates) { + return; + } const textureIndex = featureTextureProperty.texture.index; const texture = json.textures?.[textureIndex]; diff --git a/modules/gltf/src/lib/extensions/utils/3d-tiles-utils.ts b/modules/gltf/src/lib/extensions/utils/3d-tiles-utils.ts index ca566ac025..74d14d8e1e 100644 --- a/modules/gltf/src/lib/extensions/utils/3d-tiles-utils.ts +++ b/modules/gltf/src/lib/extensions/utils/3d-tiles-utils.ts @@ -12,7 +12,7 @@ import type {BigTypedArray, TypedArray} from '@loaders.gl/schema'; import type {ImageType} from '@loaders.gl/images'; import {GLTFScenegraph} from '../../api/gltf-scenegraph'; -import {getComponentTypeFromArray} from '../../gltf-utils/gltf-utils'; +import {getComponentTypeFromArray, getFloat32ArrayForAccessor} from '../../gltf-utils/gltf-utils'; import {getImageData} from '@loaders.gl/images'; import {emod} from '@loaders.gl/math'; @@ -80,7 +80,7 @@ export function getArrayElementByteSize(attributeType, componentType): number { * @param bufferViewIndex - Buffer view index * @param offsetType - The type of values in `arrayOffsets` or `stringOffsets`. * @param numberOfElements - The number of elements in each property array. - * @returns array with values offsets + * @returns Array of values offsets. The number of offsets in the array is equal to `numberOfElements` plus one. */ export function getOffsetsForProperty( scenegraph: GLTFScenegraph, @@ -113,10 +113,10 @@ export function getOffsetsForProperty( /** * Converts raw bytes that are in the buffer to an array of the type defined by the schema. - * @param data - raw bytes in the buffer - * @param attributeType - SCALAR, VECN, MATN - * @param componentType - type of the component in elements, e.g. 'UINT8' or 'FLOAT32' - * @param elementCount - number of elements in the array. Default value is 1. + * @param data - Raw bytes in the buffer. + * @param attributeType - SCALAR, VECN, MATN. + * @param componentType - Type of the component in elements, e.g. 'UINT8' or 'FLOAT32'. + * @param elementCount - Number of elements in the array. Default value is 1. * @returns Data array */ export function convertRawBufferToMetadataArray( @@ -144,8 +144,8 @@ export function convertRawBufferToMetadataArray( * Processes data encoded in the texture associated with the primitive. * If Ext_mesh_featues is combined with the Ext_structural_metadata, propertyTable will also be processed. * @param scenegraph - Instance of the class for structured access to GLTF data. - * @param textureInfo - reference to the texture where extension data are stored. - * @param primitive - primitive object in the mesh + * @param textureInfo - Reference to the texture where extension data are stored. + * @param primitive - Primitive object in the mesh. * @returns Array of data taken. Null if data can't be taken from the texture. */ export function getPrimitiveTextureData( @@ -170,15 +170,11 @@ export function getPrimitiveTextureData( const texCoordAccessorKey = `TEXCOORD_${textureInfo.texCoord || 0}`; const texCoordAccessorIndex = primitive.attributes[texCoordAccessorKey]; - const texCoordBufferView = scenegraph.getBufferView(texCoordAccessorIndex); - const texCoordArray: Uint8Array = scenegraph.getTypedArrayForBufferView(texCoordBufferView); - // textureCoordinates array contains UV coordinates of the actual data stored in the texture - const textureCoordinates: Float32Array = new Float32Array( - texCoordArray.buffer, - texCoordArray.byteOffset, - texCoordArray.length / 4 - ); + const textureCoordinates: Float32Array | null = getFloat32ArrayForAccessor(scenegraph.gltf, texCoordAccessorIndex); + if (!textureCoordinates) { + return null; + } const textureIndex: number = textureInfo.index; const imageIndex = json.textures?.[textureIndex]?.source; @@ -208,11 +204,11 @@ export function getPrimitiveTextureData( * Puts property data to attributes. * It creates corresponding buffer, bufferView and accessor * so the data can be accessed like regular data stored in buffers. - * @param scenegraph - scenegraph object - * @param attributeName - name of the attribute - * @param propertyData - property data to store - * @param featureTable - an array where unique data from the property data are being stored - * @param primitive - primitive object + * @param scenegraph - Scenegraph object. + * @param attributeName - Name of the attribute. + * @param propertyData - Property data to store. + * @param featureTable - Array where unique data from the property data are being stored. + * @param primitive - Primitive object. */ export function primitivePropertyDataToAttributes( scenegraph: GLTFScenegraph, @@ -221,7 +217,10 @@ export function primitivePropertyDataToAttributes( featureTable: number[], primitive: GLTFMeshPrimitive ): void { - if (propertyData === null) return; + // No reason to create an empty buffer if there is no property data to store. + if (!propertyData?.length) { + return; + } /* featureTable will contain unique values, e.g. propertyData = [24, 35, 28, 24] @@ -255,11 +254,11 @@ export function primitivePropertyDataToAttributes( /** * Gets the value from the texture by coordinates provided. - * @param parsedImage - image where the data are stored. - * @param mimeType - MIME type + * @param parsedImage - Image where the data are stored. + * @param mimeType - MIME type. * @param textureCoordinates - uv coordinates to access data in the image. - * @param index - index of uv coordinates in the array textureCoordinates - * @param channels - image channels where data are stored. Channels of an RGBA texture are numbered 0..3 respectively. + * @param index - Index of uv coordinates in the array textureCoordinates. + * @param channels - Image channels where data are stored. Channels of an RGBA texture are numbered 0..3 respectively. * @returns Value taken from the image. */ function getImageValueByCoordinates( @@ -267,14 +266,14 @@ function getImageValueByCoordinates( mimeType: string | undefined, textureCoordinates: Float32Array, index: number, - channels: number[] = [0] + channels: number[] | string = [0] ) { - const CHANNELS_MAP = [ - {offset: 0, shift: 0}, - {offset: 1, shift: 8}, - {offset: 2, shift: 16}, - {offset: 3, shift: 24} - ]; + const CHANNELS_MAP = { + r: {offset: 0, shift: 0}, + g: {offset: 1, shift: 8}, + b: {offset: 2, shift: 16}, + a: {offset: 3, shift: 24} + }; const u = textureCoordinates[index]; const v = textureCoordinates[index + 1]; @@ -285,7 +284,8 @@ function getImageValueByCoordinates( const offset = coordinatesToOffset(u, v, parsedImage, components); let value: number = 0; for (const c of channels) { - const map = CHANNELS_MAP[c]; + // We can get the element of CHANNELS_MAP by either index (0, 1, 2, 3) or key (r, g, b, a) + const map = typeof c === "number" ? Object.values(CHANNELS_MAP)[c] : CHANNELS_MAP[c]; const imageOffset = offset + map.offset; const imageData = getImageData(parsedImage); if (imageData.data.length <= imageOffset) { @@ -298,12 +298,12 @@ function getImageValueByCoordinates( } /** - * Retrieves the offset in the image where the data are stored - * @param u - u-coordinate - * @param v - v-coordinate - * @param parsedImage - image where the data are stored - * @param componentsCount - number of components the data consists of. - * @returns offset in the image where the data are stored + * Retrieves the offset in the image where the data are stored. + * @param u - u-coordinate. + * @param v - v-coordinate. + * @param parsedImage - Image where the data are stored. + * @param componentsCount - Number of components the data consists of. + * @returns Offset in the image where the data are stored. */ function coordinatesToOffset( u: number, diff --git a/modules/gltf/src/lib/gltf-utils/gltf-utils.ts b/modules/gltf/src/lib/gltf-utils/gltf-utils.ts index e05bae3eb4..4e9874ca69 100644 --- a/modules/gltf/src/lib/gltf-utils/gltf-utils.ts +++ b/modules/gltf/src/lib/gltf-utils/gltf-utils.ts @@ -1,5 +1,8 @@ import {assert} from '../utils/assert'; + +import type {GLTFWithBuffers} from '../types/gltf-types'; import type {GLTFPostprocessed} from '../types/gltf-postprocessed-schema'; +import {BYTES, COMPONENTS} from '../gltf-utils/gltf-constants'; /** * Memory needed to store texture and all mipmap levels 1 + 1/4 + 1/16 + 1/64 + ... @@ -85,6 +88,38 @@ export function getAccessorArrayTypeAndLength(accessor, bufferView) { return {ArrayType, length, byteLength}; } +export function getFloat32ArrayForAccessor(gltfData: GLTFWithBuffers, texCoordAccessor: number): Float32Array | null { + const accessor = gltfData.json.accessors?.[texCoordAccessor]; + if (accessor && accessor.bufferView) { + // Get `bufferView` of the `accessor` + const bufferView = gltfData.json.bufferViews?.[accessor.bufferView]; + if (bufferView) { + // Get `arrayBuffer` the `bufferView` look at + const {arrayBuffer, byteOffset: bufferByteOffset} = gltfData.buffers[bufferView.buffer]; + // Resulting byteOffset is sum of the buffer, accessor and bufferView byte offsets + const byteOffset = + (bufferByteOffset || 0) + (accessor.byteOffset || 0) + (bufferView.byteOffset || 0); + // Deduce TypedArray type and its length from `accessor` and `bufferView` data + const {ArrayType, length} = getAccessorArrayTypeAndLength(accessor, bufferView); + // Number of bytes each component occupies + const bytes = BYTES[accessor.componentType]; + // Number of components. For the `TEXCOORD_0` with `VEC2` type, it must return 2 + const components = COMPONENTS[accessor.type]; + // Multiplier to calculate the address of the `TEXCOORD_0` element in the arrayBuffer + const elementAddressScale = bufferView.byteStride || bytes * components; + // Data transform to Float32Array + const result = new Float32Array(length); + for (let i = 0; i < accessor.count; i++) { + // Take [u, v] couple from the arrayBuffer + const uv = new ArrayType(arrayBuffer, byteOffset + i * elementAddressScale, 2); + result.set(uv, i * components); + } + return result; + } + } + return null; +} + /** * Calculate the GPU memory used by a GLTF tile, for both buffer and texture memory * @param gltf - the gltf content of a GLTF tile diff --git a/modules/gltf/src/lib/types/gltf-ext-feature-metadata-schema.ts b/modules/gltf/src/lib/types/gltf-ext-feature-metadata-schema.ts new file mode 100644 index 0000000000..ef075034e2 --- /dev/null +++ b/modules/gltf/src/lib/types/gltf-ext-feature-metadata-schema.ts @@ -0,0 +1,470 @@ +import {GLTFTextureInfo} from './gltf-json-schema'; + +/* eslint-disable camelcase */ + +/** + * EXT_feature_metadata extension types + * This extension has glTF-level metadata and primitive-level feature indexing and segmentation metadata + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata + * + * glTF-level metadata + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#gltf-extension-1 + * JSON Schema - https://github.com/CesiumGS/glTF/blob/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata/schema/glTF.EXT_feature_metadata.schema.json + */ +export type GLTF_EXT_feature_metadata_GLTF = { + /** An object defining classes and enums. */ + schema?: GLTF_EXT_feature_metadata_Schema; + /** A uri to an external schema file. */ + schemaUri?: string; + /** An object containing statistics about features. */ + statistics?: GLTF_EXT_feature_metadata_Statistics; + /** A dictionary, where each key is a feature table ID and each value is an object defining the feature table. */ + featureTables?: { + [key: string]: GLTF_EXT_feature_metadata_FeatureTable; + }; + /** A dictionary, where each key is a feature texture ID and each value is an object defining the feature texture. */ + featureTextures?: { + [key: string]: GLTF_EXT_feature_metadata_FeatureTexture; + }; + extensions?: Record; + extras?: unknown; +}; + +/** + * An object defining classes and enums. + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#schema + * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/schema.schema.json + */ +export type GLTF_EXT_feature_metadata_Schema = { + /** The name of the schema. */ + name?: string; + /** The description of the schema. */ + description?: string; + /** Application-specific version of the schema. */ + version?: string; + /** A dictionary, where each key is a class ID and each value is an object defining the class. */ + classes?: { + [key: string]: GLTF_EXT_feature_metadata_Class; + }; + /** A dictionary, where each key is an enum ID and each value is an object defining the values for the enum. */ + enums?: { + [key: string]: GLTF_EXT_feature_metadata_Enum; + }; + extensions?: Record; + extras?: unknown; +}; + +/** + * A class containing a set of properties. + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#class + * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/class.schema.json + */ +export type GLTF_EXT_feature_metadata_Class = { + /** The name of the class, e.g. for display purposes. */ + name?: string; + /** The description of the class. */ + description?: string; + /** A dictionary, where each key is a property ID and each value is an object defining the property. */ + properties: { + [key: string]: GLTF_EXT_feature_metadata_ClassProperty; + }; + extensions?: Record; + extras?: unknown; +}; + +/** + * A class property. + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#class-property + * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/class.property.schema.json + */ +export type GLTF_EXT_feature_metadata_ClassProperty = { + /** The name of the property, e.g. for display purposes. */ + name?: string; + /** The description of the property. */ + description?: string; + /** + * The property type. If ENUM is used, then enumType must also be specified. + * If ARRAY is used, then componentType must also be specified. + * ARRAY is a fixed-length array when componentCount is defined, and variable-length otherwise. + */ + type: + | 'INT8' + | 'UINT8' + | 'INT16' + | 'UINT16' + | 'INT32' + | 'UINT32' + | 'INT64' + | 'UINT64' + | 'FLOAT32' + | 'FLOAT64' + | 'BOOLEAN' + | 'STRING' + | 'ENUM' + | 'ARRAY' + | string; + /** + * An enum ID as declared in the enums dictionary. + * This value must be specified when type or componentType is ENUM. + */ + enumType?: string; + /** + * When type is ARRAY this indicates the type of each component of the array. + * If ENUM is used, then enumType must also be specified. + */ + componentType?: + | 'INT8' + | 'UINT8' + | 'INT16' + | 'UINT16' + | 'INT32' + | 'UINT32' + | 'INT64' + | 'UINT64' + | 'FLOAT32' + | 'FLOAT64' + | 'BOOLEAN' + | 'STRING' + | 'ENUM' + | string; + /** The number of components per element for ARRAY elements. */ + componentCount?: number; + /** + * Specifies whether integer values are normalized. + * This applies both when type is an integer type, or when type is ARRAY with a componentType that is an integer type. + * For unsigned integer types, values are normalized between [0.0, 1.0]. + * For signed integer types, values are normalized between [-1.0, 1.0]. + * For all other types, this property is ignored. + */ + normalized: boolean; + /** + * Maximum allowed values for property values. + * Only applicable for numeric types and fixed-length arrays of numeric types. + * For numeric types this is a single number. + * For fixed-length arrays this is an array with componentCount number of elements. + * The normalized property has no effect on these values: they always correspond to the integer values. + */ + max?: number | number[]; + /** + * Minimum allowed values for property values. + * Only applicable for numeric types and fixed-length arrays of numeric types. + * For numeric types this is a single number. + * For fixed-length arrays this is an array with componentCount number of elements. + * The normalized property has no effect on these values: they always correspond to the integer values. + */ + min?: number | number[]; + /** + * A default value to use when the property value is not defined. + * If used, optional must be set to true. + * The type of the default value must match the property definition: For BOOLEAN use true or false. + * For STRING use a JSON string. For a numeric type use a JSON number. + * For ENUM use the enum name, not the integer value. + * For ARRAY use a JSON array containing values matching the componentType. + */ + default?: boolean | number | string | number[]; + /** If true, this property is optional. */ + optional?: boolean; // default false; + /** + * An identifier that describes how this property should be interpreted. + * The semantic cannot be used by other properties in the class. + */ + semantic?: string; + extensions?: Record; + extras?: unknown; +}; + +/** + * An object defining the values of an enum. + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#enum + * JSON Schema - https://github.com/CesiumGS/glTF/blob/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata/schema/enum.schema.json + */ +export type GLTF_EXT_feature_metadata_Enum = { + /** The name of the enum, e.g. for display purposes. */ + name?: string; + /** The description of the enum. */ + description?: string; + /** The type of the integer enum value. */ + valueType?: 'INT8' | 'UINT8' | 'INT16' | 'UINT16' | 'INT32' | 'UINT32' | 'INT64' | 'UINT64'; // default: "UINT16" + /** An array of enum values. Duplicate names or duplicate integer values are not allowed. */ + values: GLTF_EXT_feature_metadata_EnumValue[]; + extensions?: Record; + extras?: unknown; + [key: string]: unknown; +}; + +/** + * An enum value. + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#enum-value + * JSON Schema - https://github.com/CesiumGS/glTF/blob/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata/schema/enum.value.schema.json + */ +export type GLTF_EXT_feature_metadata_EnumValue = { + /** The name of the enum value. */ + name: string; + /** The description of the enum value. */ + description?: string; + /** The integer enum value. */ + value: number; // default: "UINT16" + extensions?: Record; + extras?: unknown; + [key: string]: unknown; +}; + +/** + * A feature table defined by a class and property values stored in arrays. + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#feature-table + * JSON Schenma - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/featureTable.schema.json + */ +export type GLTF_EXT_feature_metadata_FeatureTable = { + /** The class that property values conform to. The value must be a class ID declared in the classes dictionary. */ + class?: string; + /** The number of features, as well as the number of elements in each property array. */ + count: number; + /** + * A dictionary, where each key corresponds to a property ID in the class properties dictionary + * and each value is an object describing where property values are stored. + * Optional properties may be excluded from this dictionary. + */ + properties?: { + [key: string]: GLTF_EXT_feature_metadata_FeatureTableProperty; + }; + extensions?: Record; + extras?: unknown; +}; + +/** + * An array of binary property values. + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#feature-table-property + * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/featureTable.property.schema.json + */ +export type GLTF_EXT_feature_metadata_FeatureTableProperty = { + /** + * The index of the buffer view containing property values. + * The data type of property values is determined by the property definition: + * When type is BOOLEAN values are packed into a bitfield. + * When type is STRING values are stored as byte sequences and decoded as UTF-8 strings. + * When type is a numeric type values are stored as the provided type. + * When type is ENUM values are stored as the enum's valueType. + * Each enum value in the buffer must match one of the allowed values in the enum definition. + * When type is ARRAY elements are packed tightly together and the data type is based on the componentType following the same rules as above. + * arrayOffsetBufferView is required for variable-size arrays + * and stringOffsetBufferView is required for strings (for variable-length arrays of strings, both are required) + * The buffer view byteOffset must be aligned to a multiple of 8 bytes. + * If the buffer view's buffer is the GLB-stored BIN chunk the byte offset is measured relative to the beginning of the GLB. + * Otherwise it is measured relative to the beginning of the buffer. + */ + bufferView: number; + + /** The type of values in arrayOffsetBufferView and stringOffsetBufferView. */ + offsetType?: 'UINT8' | 'UINT16' | 'UINT32' | 'UINT64' | string; // default: "UINT32" + /** + * The index of the buffer view containing offsets for variable-length arrays. + * The number of offsets is equal to the feature table count plus one. + * The offsets represent the start positions of each array, with the last offset representing the position after the last array. + * The array length is computed using the difference between the current offset and the subsequent offset. + * If componentType is STRING the offsets index into the string offsets array (stored in stringOffsetBufferView), + * otherwise they index into the property array (stored in bufferView). + * The data type of these offsets is determined by offsetType. + * The buffer view byteOffset must be aligned to a multiple of 8 bytes in the same manner as the main bufferView + */ + arrayOffsetBufferView?: number; + /** + * The index of the buffer view containing offsets for strings. + * The number of offsets is equal to the number of string components plus one. + * The offsets represent the byte offsets of each string in the main bufferView, + * with the last offset representing the byte offset after the last string. + * The string byte length is computed using the difference between the current offset and the subsequent offset. + * The data type of these offsets is determined by offsetType. + * The buffer view byteOffset must be aligned to a multiple of 8 bytes in the same manner as the main bufferView. + */ + stringOffsetBufferView?: number; + extensions?: Record; + extras?: unknown; + /** This is not part of the spec. GLTFLoader loads feature tables data into this property */ + data: unknown; +}; + +/** + * Features whose property values are stored directly in texture channels. This is not to be confused with feature ID textures which store feature IDs for use with a feature table. + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#feature-texture + * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/featureTexture.schema.json + */ +export type GLTF_EXT_feature_metadata_FeatureTexture = { + /** The class this feature texture conforms to. The value must be a class ID declared in the classes dictionary. */ + class: string; + /** + * A dictionary, where each key corresponds to a property ID in the class properties dictionary + * and each value describes the texture channels containing property values. + */ + properties: { + [key: string]: GLTF_EXT_feature_metadata_TextureAccessor; + }; + extensions?: Record; + extras?: unknown; +}; + +/** + * A description of how to access property values from the color channels of a texture. + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#texture-accessor + * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/textureAccessor.schema.json + */ +export type GLTF_EXT_feature_metadata_TextureAccessor = { + /** Texture channels containing property values. Channels are labeled by rgba and are swizzled with a string of 1-4 characters. */ + channels: string; + /** The glTF texture and texture coordinates to use. */ + texture: GLTFTextureInfo; + extensions?: Record; + extras?: unknown; + /** This is not part of the spec. GLTFLoader loads feature tables data into this property */ + data: unknown; +}; + +/** + * Statistics about features. + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#statistics-1 + * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/statistics.schema.json + */ +export type GLTF_EXT_feature_metadata_Statistics = { + /** + * A dictionary, where each key is a class ID declared in the classes dictionary + * and each value is an object containing statistics about features that conform to the class. + */ + classes?: { + [key: string]: GLTF_EXT_feature_metadata_StatisticsClass; + }; + extensions?: Record; + extras?: unknown; +}; + +/** + * Statistics about features that conform to the class. + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#class-statistics + * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/statistics.class.property.schema.json + */ +export type GLTF_EXT_feature_metadata_StatisticsClass = { + /** The number of features that conform to the class. */ + count?: number; + /** + * A dictionary, where each key is a class ID declared in the classes dictionary + * and each value is an object containing statistics about property values. + */ + properties?: { + [key: string]: GLTF_EXT_feature_metadata_StatisticsClassProperty; + }; + extensions?: Record; + extras?: unknown; +}; + +/** + * min, max, mean, median, standardDeviation, variance, sum are + * only applicable for numeric types and fixed-length arrays of numeric types. + * For numeric types this is a single number. + * For fixed-length arrays this is an array with componentCount number of elements. + * The normalized property has no effect on these values. + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#property-statistics + * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/statistics.class.property.schema.json + */ +export type GLTF_EXT_feature_metadata_StatisticsClassProperty = { + /** The minimum property value. */ + min?: number | number[]; + /** The maximum property value. */ + max?: number | number[]; + /** The arithmetic mean of the property values. */ + mean?: number | number[]; + /** The median of the property values. */ + median?: number | number[]; + /** The standard deviation of the property values. */ + standardDeviation?: number | number[]; + /** The variance of the property values. */ + variance?: number | number[]; + /** The sum of the property values. */ + sum?: number | number[]; + /** + * A dictionary, where each key corresponds to an enum name and each value is the number of occurrences of that enum. + * Only applicable when type or componentType is ENUM. + * For fixed-length arrays, this is an array with componentCount number of elements. + */ + occurrences: { + [key: string]: number | number[]; + }; + extensions?: Record; + extras?: unknown; +}; + +/** + * EXT_feature_metadata extension types + * This extension has glTF-level metadata and primitive-level (feature indexing and segmentation) metadata + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata + * + * primitive-level metadata + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#primitive-extension + * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/mesh.primitive.EXT_feature_metadata.schema.json + */ +export type GLTF_EXT_feature_metadata_Primitive = { + /** Feature ids definition in attributes */ + featureIdAttributes?: GLTF_EXT_feature_metadata_FeatureIdAttribute[]; + /** Feature ids definition in textures */ + featureIdTextures?: GLTF_EXT_feature_metadata_FeatureIdTexture[]; + /** An array of IDs of feature textures from the root EXT_feature_metadata object. */ + featureTextures?: string[]; + extensions?: Record; + extras?: unknown; +}; + +/** + * Attribute which described featureIds definition. + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#feature-id-attribute + * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/featureIdAttribute.schema.json + */ +export type GLTF_EXT_feature_metadata_FeatureIdAttribute = { + /** Name of feature table */ + featureTable: string; + /** Described how feature ids are defined */ + featureIds: GLTF_EXT_feature_metadata_FeatureIdAttributeFeatureIds; + extensions?: Record; + extras?: unknown; +}; + +/** + * Defining featureIds by attributes or implicitly. + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#primitive-extensionfeatureidattributes + * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/featureIdAttribute.featureIds.schema.json + */ +export type GLTF_EXT_feature_metadata_FeatureIdAttributeFeatureIds = { + /** Name of attribute where featureIds are defined */ + attribute?: string; + /** Sets a constant feature ID for each vertex. The default is 0. */ + constant?: number; + /** Sets the rate at which feature IDs increment. + * If divisor is zero then constant is used. + * If divisor is greater than zero the feature ID increments once per divisor sets of vertices, starting at constant. + * The default is 0 + */ + divisor?: number; +}; + +/** + * An object describing a texture used for storing per-texel feature IDs. + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#feature-id-texture + * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/featureIdTexture.schema.json + */ +export type GLTF_EXT_feature_metadata_FeatureIdTexture = { + /** The ID of the feature table in the model's root `EXT_feature_metadata.featureTables` dictionary. */ + featureTable: string; + /** A description of the texture and channel to use for feature IDs. The `channels` property must have a single channel. Furthermore, + * feature IDs must be whole numbers in the range `[0, count - 1]` (inclusive), where `count` is the total number of features + * in the feature table. Texel values must be read as integers. Texture filtering should be disabled when fetching feature IDs. + */ + featureIds: GLTF_EXT_feature_metadata_FeatureIdTextureAccessor; +}; + +/** + * A description of how to access property values from the color channels of a texture. + * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#featureidtexturefeatureids + * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/textureAccessor.schema.json + */ +export type GLTF_EXT_feature_metadata_FeatureIdTextureAccessor = { + /** gLTF textureInfo object - https://github.com/CesiumGS/glTF/blob/3d-tiles-next/specification/2.0/schema/textureInfo.schema.json */ + texture: GLTFTextureInfo; + /** Must be a single channel ("r", "g", "b", or "a") */ + channels: 'r' | 'g' | 'b' | 'a'; +}; diff --git a/modules/gltf/src/lib/types/gltf-ext-mesh-features-schema.ts b/modules/gltf/src/lib/types/gltf-ext-mesh-features-schema.ts index d395020cef..5fa662c4a1 100644 --- a/modules/gltf/src/lib/types/gltf-ext-mesh-features-schema.ts +++ b/modules/gltf/src/lib/types/gltf-ext-mesh-features-schema.ts @@ -3,23 +3,21 @@ import {GLTFTextureInfoMetadata} from './gltf-json-schema'; /** * EXT_mesh_features extension types - * This is a primitive-level extension + * This is a primitive-level extension. + * An object describing feature IDs for a mesh primitive. * @see https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_mesh_features * or https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_mesh_features/schema/mesh.primitive.EXT_mesh_features.schema.json - * An object describing feature IDs for a mesh primitive. */ export type GLTF_EXT_mesh_features = { /** An array of feature ID sets. */ featureIds: GLTF_EXT_mesh_features_featureId[]; extensions?: Record; extras?: unknown; - /** For internal usage */ - dataAttributeNames?: string[]; }; /** - * @see https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_mesh_features/schema/featureId.schema.json * Feature IDs stored in an attribute or texture. + * @see https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_mesh_features/schema/featureId.schema.json */ export type GLTF_EXT_mesh_features_featureId = { /** The number of unique features in the attribute or texture. */ @@ -43,6 +41,6 @@ export type GLTF_EXT_mesh_features_featureId = { extensions?: Record; extras?: unknown; - /** For internal usage */ + /** This is not part of the spec. GLTFLoader loads feature tables data into this property */ data?: unknown; }; diff --git a/modules/gltf/src/lib/types/gltf-ext-structural-metadata-schema.ts b/modules/gltf/src/lib/types/gltf-ext-structural-metadata-schema.ts index f6f373841b..1bca88e338 100644 --- a/modules/gltf/src/lib/types/gltf-ext-structural-metadata-schema.ts +++ b/modules/gltf/src/lib/types/gltf-ext-structural-metadata-schema.ts @@ -3,6 +3,7 @@ import {GLTFTextureInfoMetadata} from './gltf-json-schema'; /* eslint-disable camelcase */ /** + * glTF extension that provides structural metadata about vertices, texels, and features in a glTF asset. * @see https://github.com/CesiumGS/glTF/blob/3d-tiles-next/extensions/2.0/Vendor/EXT_structural_metadata/schema/glTF.EXT_structural_metadata.schema.json */ export type GLTF_EXT_structural_metadata_GLTF = { @@ -16,11 +17,12 @@ export type GLTF_EXT_structural_metadata_GLTF = { propertyTextures?: GLTF_EXT_structural_metadata_PropertyTexture[]; /** "An array of property attribute definitions, which may be referenced by index. */ propertyAttributes?: GLTF_EXT_structural_metadata_PropertyAttribute[]; - /** For internal usage */ + /** This is not part of the spec. GLTFLoader loads names of attributes crated into this property */ dataAttributeNames?: string[]; }; /** + * An object defining classes and enums. * @see https://github.com/CesiumGS/glTF/blob/3d-tiles-next/extensions/2.0/Vendor/EXT_structural_metadata/schema/schema.schema.json */ export type GLTF_EXT_structural_metadata_Schema = { @@ -40,8 +42,8 @@ export type GLTF_EXT_structural_metadata_Schema = { enums?: { [key: string]: GLTF_EXT_structural_metadata_Enum; }; - extensions?: Record; - extras?: any; + extensions?: Record; + extras?: unknown; }; /** @@ -53,15 +55,19 @@ export type GLTF_EXT_structural_metadata_Enum = { name?: string; /** The description of the enum. */ description?: string; - /** The type of the integer enum value. */ - valueType?: 'INT8' | 'UINT8' | 'INT16' | 'UINT16' | 'INT32' | 'UINT32' | 'INT64' | 'UINT64'; // default: "UINT16" + /** + * The type of the integer enum value. + * Default value is 'UINT16' + */ + valueType?: 'INT8' | 'UINT8' | 'INT16' | 'UINT16' | 'INT32' | 'UINT32' | 'INT64' | 'UINT64'; /** An array of enum values. Duplicate names or duplicate integer values are not allowed. */ values: GLTF_EXT_structural_metadata_EnumValue[]; - extensions?: Record; - extras?: any; + extensions?: Record; + extras?: unknown; }; /** + * An enum value. * @see https://github.com/CesiumGS/glTF/blob/3d-tiles-next/extensions/2.0/Vendor/EXT_structural_metadata/schema/enum.value.schema.json */ export type GLTF_EXT_structural_metadata_EnumValue = { @@ -71,11 +77,12 @@ export type GLTF_EXT_structural_metadata_EnumValue = { description?: string; /** The integer enum value. */ value: number; - extensions?: Record; - extras?: any; + extensions?: Record; + extras?: unknown; }; /** + * A class containing a set of properties. * @see https://github.com/CesiumGS/glTF/blob/3d-tiles-next/extensions/2.0/Vendor/EXT_structural_metadata/schema/class.schema.json */ export type GLTF_EXT_structural_metadata_Class = { @@ -90,11 +97,12 @@ export type GLTF_EXT_structural_metadata_Class = { properties: { [key: string]: GLTF_EXT_structural_metadata_ClassProperty; }; - extensions?: Record; - extras?: any; + extensions?: Record; + extras?: unknown; }; /** + * A class property. * @see https://github.com/CesiumGS/glTF/blob/3d-tiles-next/extensions/2.0/Vendor/EXT_structural_metadata/schema/class.property.schema.json */ export type GLTF_EXT_structural_metadata_ClassProperty = { @@ -185,8 +193,9 @@ export type GLTF_EXT_structural_metadata_ClassProperty = { * If not required, individual entities may include `noData` values, or the entire property may be omitted. * As a result, `noData` has no effect on a required property. * Client implementations may use required properties to make performance optimizations. + * Default value is false. */ - required?: boolean; // default false; + required?: boolean; /** * A `noData` value represents missing data — also known as a sentinel value — wherever it appears. @@ -201,10 +210,14 @@ export type GLTF_EXT_structural_metadata_ClassProperty = { * The semantic cannot be used by other properties in the class. */ semantic?: string; - extensions?: Record; - extras?: any; + extensions?: Record; + extras?: unknown; }; +/** + * Properties conforming to a class, organized as property values stored in binary columnar arrays. + * @see https://github.com/CesiumGS/glTF/blob/3d-tiles-next/extensions/2.0/Vendor/EXT_structural_metadata/schema/propertyTable.schema.json + */ export type GLTF_EXT_structural_metadata_PropertyTable = { /** The name of the property table, e.g. for display purposes. */ name?: string; @@ -220,11 +233,12 @@ export type GLTF_EXT_structural_metadata_PropertyTable = { properties?: { [key: string]: GLTF_EXT_structural_metadata_PropertyTable_Property; }; - extensions?: Record; - extras?: any; + extensions?: Record; + extras?: unknown; }; /** + * An array of binary property values. * @see https://github.com/CesiumGS/glTF/blob/3d-tiles-next/extensions/2.0/Vendor/EXT_structural_metadata/schema/propertyTable.property.schema.json */ export type GLTF_EXT_structural_metadata_PropertyTable_Property = { @@ -262,11 +276,13 @@ export type GLTF_EXT_structural_metadata_PropertyTable_Property = { stringOffsets?: number; /** * The type of values in `arrayOffsets`. + * Default value is 'UINT32' */ arrayOffsetType?: 'UINT8' | 'UINT16' | 'UINT32' | 'UINT64' | string; /** * The type of values in `stringOffsets`. + * Default value is 'UINT32' */ stringOffsetType?: 'UINT8' | 'UINT16' | 'UINT32' | 'UINT64' | string; /** @@ -293,13 +309,14 @@ export type GLTF_EXT_structural_metadata_PropertyTable_Property = { * This is the minimum of all property values, after the transforms based on the `normalized`, `offset`, and `scale` properties have been applied. */ min?: number | number[]; - extensions?: Record; - extras?: any; - /** For internal usage */ + extensions?: Record; + extras?: unknown; + /** This is not part of the spec. GLTFLoader loads feature tables data into this property */ data?: unknown; }; /** + * Properties conforming to a class, organized as property values stored in textures. * @see https://github.com/CesiumGS/glTF/blob/3d-tiles-next/extensions/2.0/Vendor/EXT_structural_metadata/schema/propertyTexture.schema.json */ export type GLTF_EXT_structural_metadata_PropertyTexture = { @@ -322,11 +339,12 @@ export type GLTF_EXT_structural_metadata_PropertyTexture = { properties?: { [key: string]: GLTFTextureInfoMetadata; }; - extensions?: Record; - extras?: any; + extensions?: Record; + extras?: unknown; }; /** + * Properties conforming to a class, organized as property values stored in attributes. * @see https://github.com/CesiumGS/glTF/blob/3d-tiles-next/extensions/2.0/Vendor/EXT_structural_metadata/schema/propertyAttribute.schema.json */ export type GLTF_EXT_structural_metadata_PropertyAttribute = { @@ -340,13 +358,14 @@ export type GLTF_EXT_structural_metadata_PropertyAttribute = { * Required properties must be included in this dictionary. */ properties?: { - [key: string]: any; + [key: string]: unknown; }; - extensions?: Record; - extras?: any; + extensions?: Record; + extras?: unknown; }; /** + * Structural metadata about a glTF primitive. * @see https://github.com/CesiumGS/glTF/blob/3d-tiles-next/extensions/2.0/Vendor/EXT_structural_metadata/schema/mesh.primitive.EXT_structural_metadata.schema.json */ export type GLTF_EXT_structural_metadata_Primitive = { @@ -354,6 +373,6 @@ export type GLTF_EXT_structural_metadata_Primitive = { propertyTextures?: number[]; /** An array of indexes of property attributes in the root `EXT_structural_metadata` object. */ propertyAttributes?: number[]; - extensions?: Record; - extras?: any; + extensions?: Record; + extras?: unknown; }; diff --git a/modules/gltf/src/lib/types/gltf-json-schema.ts b/modules/gltf/src/lib/types/gltf-json-schema.ts index e36b362223..0bd5b0974e 100644 --- a/modules/gltf/src/lib/types/gltf-json-schema.ts +++ b/modules/gltf/src/lib/types/gltf-json-schema.ts @@ -371,7 +371,7 @@ export type GLTFTextureInfo = { * https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_mesh_features */ export type GLTFTextureInfoMetadata = GLTFTextureInfo & { - channels: number[]; + channels: number[] | string; /** For internal usage */ data?: unknown; }; @@ -803,470 +803,3 @@ export type GLTF_MSFT_texture_dds = { source: GLTFId; extras?: any; }; - -/** - * EXT_feature_metadata extension types - * This extension has glTF-level metadata and primitive-level feature indexing and segmentation metadata - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata - * - * glTF-level metadata - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#gltf-extension-1 - * JSON Schema - https://github.com/CesiumGS/glTF/blob/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata/schema/glTF.EXT_feature_metadata.schema.json - */ -export type GLTF_EXT_feature_metadata_GLTF = { - /** An object defining classes and enums. */ - schema?: GLTF_EXT_feature_metadata_Schema; - /** A uri to an external schema file. */ - schemaUri?: string; - /** An object containing statistics about features. */ - statistics?: GLTF_EXT_feature_metadata_Statistics; - /** A dictionary, where each key is a feature table ID and each value is an object defining the feature table. */ - featureTables?: { - [key: string]: GLTF_EXT_feature_metadata_FeatureTable; - }; - /** A dictionary, where each key is a feature texture ID and each value is an object defining the feature texture. */ - featureTextures?: { - [key: string]: GLTF_EXT_feature_metadata_FeatureTexture; - }; - extensions?: Record; - extras?: any; -}; - -/** - * An object defining classes and enums. - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#schema - * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/schema.schema.json - */ -export type GLTF_EXT_feature_metadata_Schema = { - /** The name of the schema. */ - name?: string; - /** The description of the schema. */ - description?: string; - /** Application-specific version of the schema. */ - version?: string; - /** A dictionary, where each key is a class ID and each value is an object defining the class. */ - classes?: { - [key: string]: GLTF_EXT_feature_metadata_Class; - }; - /** A dictionary, where each key is an enum ID and each value is an object defining the values for the enum. */ - enums?: { - [key: string]: GLTF_EXT_feature_metadata_Enum; - }; - extensions?: Record; - extras?: any; -}; - -/** - * A class containing a set of properties. - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#class - * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/class.schema.json - */ -export type GLTF_EXT_feature_metadata_Class = { - /** The name of the class, e.g. for display purposes. */ - name?: string; - /** The description of the class. */ - description?: string; - /** A dictionary, where each key is a property ID and each value is an object defining the property. */ - properties: { - [key: string]: GLTF_EXT_feature_metadata_ClassProperty; - }; - extensions?: Record; - extras?: any; -}; - -/** - * A class property. - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#class-property - * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/class.property.schema.json - */ -export type GLTF_EXT_feature_metadata_ClassProperty = { - /** The name of the property, e.g. for display purposes. */ - name?: string; - /** The description of the property. */ - description?: string; - /** - * The property type. If ENUM is used, then enumType must also be specified. - * If ARRAY is used, then componentType must also be specified. - * ARRAY is a fixed-length array when componentCount is defined, and variable-length otherwise. - */ - type: - | 'INT8' - | 'UINT8' - | 'INT16' - | 'UINT16' - | 'INT32' - | 'UINT32' - | 'INT64' - | 'UINT64' - | 'FLOAT32' - | 'FLOAT64' - | 'BOOLEAN' - | 'STRING' - | 'ENUM' - | 'ARRAY' - | string; - /** - * An enum ID as declared in the enums dictionary. - * This value must be specified when type or componentType is ENUM. - */ - enumType?: string; - /** - * When type is ARRAY this indicates the type of each component of the array. - * If ENUM is used, then enumType must also be specified. - */ - componentType?: - | 'INT8' - | 'UINT8' - | 'INT16' - | 'UINT16' - | 'INT32' - | 'UINT32' - | 'INT64' - | 'UINT64' - | 'FLOAT32' - | 'FLOAT64' - | 'BOOLEAN' - | 'STRING' - | 'ENUM' - | string; - /** The number of components per element for ARRAY elements. */ - componentCount?: number; - /** - * Specifies whether integer values are normalized. - * This applies both when type is an integer type, or when type is ARRAY with a componentType that is an integer type. - * For unsigned integer types, values are normalized between [0.0, 1.0]. - * For signed integer types, values are normalized between [-1.0, 1.0]. - * For all other types, this property is ignored. - */ - normalized: boolean; - /** - * Maximum allowed values for property values. - * Only applicable for numeric types and fixed-length arrays of numeric types. - * For numeric types this is a single number. - * For fixed-length arrays this is an array with componentCount number of elements. - * The normalized property has no effect on these values: they always correspond to the integer values. - */ - max?: number | number[]; - /** - * Minimum allowed values for property values. - * Only applicable for numeric types and fixed-length arrays of numeric types. - * For numeric types this is a single number. - * For fixed-length arrays this is an array with componentCount number of elements. - * The normalized property has no effect on these values: they always correspond to the integer values. - */ - min?: number | number[]; - /** - * A default value to use when the property value is not defined. - * If used, optional must be set to true. - * The type of the default value must match the property definition: For BOOLEAN use true or false. - * For STRING use a JSON string. For a numeric type use a JSON number. - * For ENUM use the enum name, not the integer value. - * For ARRAY use a JSON array containing values matching the componentType. - */ - default?: boolean | number | string | number[]; - /** If true, this property is optional. */ - optional?: boolean; // default false; - /** - * An identifier that describes how this property should be interpreted. - * The semantic cannot be used by other properties in the class. - */ - semantic?: string; - extensions?: Record; - extras?: any; -}; - -/** - * An object defining the values of an enum. - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#enum - * JSON Schema - https://github.com/CesiumGS/glTF/blob/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata/schema/enum.schema.json - */ -export type GLTF_EXT_feature_metadata_Enum = { - /** The name of the enum, e.g. for display purposes. */ - name?: string; - /** The description of the enum. */ - description?: string; - /** The type of the integer enum value. */ - valueType?: 'INT8' | 'UINT8' | 'INT16' | 'UINT16' | 'INT32' | 'UINT32' | 'INT64' | 'UINT64'; // default: "UINT16" - /** An array of enum values. Duplicate names or duplicate integer values are not allowed. */ - values: GLTF_EXT_feature_metadata_EnumValue[]; - extensions?: Record; - extras?: any; - [key: string]: any; -}; - -/** - * An enum value. - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#enum-value - * JSON Schema - https://github.com/CesiumGS/glTF/blob/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata/schema/enum.value.schema.json - */ -export type GLTF_EXT_feature_metadata_EnumValue = { - /** The name of the enum value. */ - name: string; - /** The description of the enum value. */ - description?: string; - /** The integer enum value. */ - value: number; // default: "UINT16" - extensions?: Record; - extras?: any; - [key: string]: any; -}; - -/** - * A feature table defined by a class and property values stored in arrays. - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#feature-table - * JSON Schenma - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/featureTable.schema.json - */ -export type GLTF_EXT_feature_metadata_FeatureTable = { - /** The class that property values conform to. The value must be a class ID declared in the classes dictionary. */ - class?: string; - /** The number of features, as well as the number of elements in each property array. */ - count: number; - /** - * A dictionary, where each key corresponds to a property ID in the class properties dictionary - * and each value is an object describing where property values are stored. - * Optional properties may be excluded from this dictionary. - */ - properties?: { - [key: string]: GLTF_EXT_feature_metadata_FeatureTableProperty; - }; - extensions?: Record; - extras?: any; -}; - -/** - * An array of binary property values. - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#feature-table-property - * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/featureTable.property.schema.json - */ -export type GLTF_EXT_feature_metadata_FeatureTableProperty = { - /** - * The index of the buffer view containing property values. - * The data type of property values is determined by the property definition: - * When type is BOOLEAN values are packed into a bitfield. - * When type is STRING values are stored as byte sequences and decoded as UTF-8 strings. - * When type is a numeric type values are stored as the provided type. - * When type is ENUM values are stored as the enum's valueType. - * Each enum value in the buffer must match one of the allowed values in the enum definition. - * When type is ARRAY elements are packed tightly together and the data type is based on the componentType following the same rules as above. - * arrayOffsetBufferView is required for variable-size arrays - * and stringOffsetBufferView is required for strings (for variable-length arrays of strings, both are required) - * The buffer view byteOffset must be aligned to a multiple of 8 bytes. - * If the buffer view's buffer is the GLB-stored BIN chunk the byte offset is measured relative to the beginning of the GLB. - * Otherwise it is measured relative to the beginning of the buffer. - */ - bufferView: number; - - /** The type of values in arrayOffsetBufferView and stringOffsetBufferView. */ - offsetType?: 'UINT8' | 'UINT16' | 'UINT32' | 'UINT64' | string; // default: "UINT32" - /** - * The index of the buffer view containing offsets for variable-length arrays. - * The number of offsets is equal to the feature table count plus one. - * The offsets represent the start positions of each array, with the last offset representing the position after the last array. - * The array length is computed using the difference between the current offset and the subsequent offset. - * If componentType is STRING the offsets index into the string offsets array (stored in stringOffsetBufferView), - * otherwise they index into the property array (stored in bufferView). - * The data type of these offsets is determined by offsetType. - * The buffer view byteOffset must be aligned to a multiple of 8 bytes in the same manner as the main bufferView - */ - arrayOffsetBufferView?: number; - /** - * The index of the buffer view containing offsets for strings. - * The number of offsets is equal to the number of string components plus one. - * The offsets represent the byte offsets of each string in the main bufferView, - * with the last offset representing the byte offset after the last string. - * The string byte length is computed using the difference between the current offset and the subsequent offset. - * The data type of these offsets is determined by offsetType. - * The buffer view byteOffset must be aligned to a multiple of 8 bytes in the same manner as the main bufferView. - */ - stringOffsetBufferView?: number; - /** This is not part of the spec. GLTFLoader loads feature tables data into this property */ - data: any; - extensions?: Record; - extras?: any; -}; - -/** - * Features whose property values are stored directly in texture channels. This is not to be confused with feature ID textures which store feature IDs for use with a feature table. - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#feature-texture - * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/featureTexture.schema.json - */ -export type GLTF_EXT_feature_metadata_FeatureTexture = { - /** The class this feature texture conforms to. The value must be a class ID declared in the classes dictionary. */ - class: string; - /** - * A dictionary, where each key corresponds to a property ID in the class properties dictionary - * and each value describes the texture channels containing property values. - */ - properties: { - [key: string]: GLTF_EXT_feature_metadata_TextureAccessor; - }; - extensions?: Record; - extras?: any; -}; - -/** - * A description of how to access property values from the color channels of a texture. - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#texture-accessor - * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/textureAccessor.schema.json - */ -export type GLTF_EXT_feature_metadata_TextureAccessor = { - /** Texture channels containing property values. Channels are labeled by rgba and are swizzled with a string of 1-4 characters. */ - channels: string; - /** The glTF texture and texture coordinates to use. */ - texture: GLTFTextureInfo; - /** This is not part of the spec. GLTFLoader loads feature tables data into this property */ - data: any; - extensions?: Record; - extras?: any; -}; - -/** - * Statistics about features. - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#statistics-1 - * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/statistics.schema.json - */ -export type GLTF_EXT_feature_metadata_Statistics = { - /** - * A dictionary, where each key is a class ID declared in the classes dictionary - * and each value is an object containing statistics about features that conform to the class. - */ - classes?: { - [key: string]: GLTF_EXT_feature_metadata_StatisticsClass; - }; - extensions?: Record; - extras?: any; -}; - -/** - * Statistics about features that conform to the class. - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#class-statistics - * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/statistics.class.property.schema.json - */ -export type GLTF_EXT_feature_metadata_StatisticsClass = { - /** The number of features that conform to the class. */ - count?: number; - /** - * A dictionary, where each key is a class ID declared in the classes dictionary - * and each value is an object containing statistics about property values. - */ - properties?: { - [key: string]: GLTF_EXT_feature_metadata_StatisticsClassProperty; - }; - extensions?: Record; - extras?: any; -}; - -/** - * min, max, mean, median, standardDeviation, variance, sum are - * only applicable for numeric types and fixed-length arrays of numeric types. - * For numeric types this is a single number. - * For fixed-length arrays this is an array with componentCount number of elements. - * The normalized property has no effect on these values. - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#property-statistics - * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/statistics.class.property.schema.json - */ -export type GLTF_EXT_feature_metadata_StatisticsClassProperty = { - /** The minimum property value. */ - min?: number | number[]; - /** The maximum property value. */ - max?: number | number[]; - /** The arithmetic mean of the property values. */ - mean?: number | number[]; - /** The median of the property values. */ - median?: number | number[]; - /** The standard deviation of the property values. */ - standardDeviation?: number | number[]; - /** The variance of the property values. */ - variance?: number | number[]; - /** The sum of the property values. */ - sum?: number | number[]; - /** - * A dictionary, where each key corresponds to an enum name and each value is the number of occurrences of that enum. - * Only applicable when type or componentType is ENUM. - * For fixed-length arrays, this is an array with componentCount number of elements. - */ - occurrences: { - [key: string]: number | number[]; - }; - extensions?: Record; - extras?: any; -}; - -/** - * EXT_feature_metadata extension types - * This extension has glTF-level metadata and primitive-level (feature indexing and segmentation) metadata - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata - * - * primitive-level metadata - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#primitive-extension - * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/mesh.primitive.EXT_feature_metadata.schema.json - */ -export type GLTF_EXT_feature_metadata_Primitive = { - /** Feature ids definition in attributes */ - featureIdAttributes?: GLTF_EXT_feature_metadata_FeatureIdAttribute[]; - /** Feature ids definition in textures */ - featureIdTextures?: GLTF_EXT_feature_metadata_FeatureIdTexture[]; - /** An array of IDs of feature textures from the root EXT_feature_metadata object. */ - featureTextures?: string[]; - extensions?: Record; - extras?: any; -}; - -/** - * Attribute which described featureIds definition. - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#feature-id-attribute - * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/featureIdAttribute.schema.json - */ -export type GLTF_EXT_feature_metadata_FeatureIdAttribute = { - /** Name of feature table */ - featureTable: string; - /** Described how feature ids are defined */ - featureIds: GLTF_EXT_feature_metadata_FeatureIdAttributeFeatureIds; - extensions?: Record; - extras?: any; -}; - -/** - * Defining featureIds by attributes or implicitly. - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#primitive-extensionfeatureidattributes - * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/featureIdAttribute.featureIds.schema.json - */ -export type GLTF_EXT_feature_metadata_FeatureIdAttributeFeatureIds = { - /** Name of attribute where featureIds are defined */ - attribute?: string; - /** Sets a constant feature ID for each vertex. The default is 0. */ - constant?: number; - /** Sets the rate at which feature IDs increment. - * If divisor is zero then constant is used. - * If divisor is greater than zero the feature ID increments once per divisor sets of vertices, starting at constant. - * The default is 0 - */ - divisor?: number; -}; - -/** - * An object describing a texture used for storing per-texel feature IDs. - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#feature-id-texture - * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/featureIdTexture.schema.json - */ -export type GLTF_EXT_feature_metadata_FeatureIdTexture = { - /** The ID of the feature table in the model's root `EXT_feature_metadata.featureTables` dictionary. */ - featureTable: string; - /** A description of the texture and channel to use for feature IDs. The `channels` property must have a single channel. Furthermore, - * feature IDs must be whole numbers in the range `[0, count - 1]` (inclusive), where `count` is the total number of features - * in the feature table. Texel values must be read as integers. Texture filtering should be disabled when fetching feature IDs. - */ - featureIds: GLTF_EXT_feature_metadata_FeatureIdTextureAccessor; -}; - -/** - * A description of how to access property values from the color channels of a texture. - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#featureidtexturefeatureids - * JSON Schema - https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/textureAccessor.schema.json - */ -export type GLTF_EXT_feature_metadata_FeatureIdTextureAccessor = { - /** gLTF textureInfo object - https://github.com/CesiumGS/glTF/blob/3d-tiles-next/specification/2.0/schema/textureInfo.schema.json */ - texture: GLTFTextureInfo; - /** Must be a single channel ("r", "g", "b", or "a") */ - channels: 'r' | 'g' | 'b' | 'a'; -}; diff --git a/modules/gltf/src/lib/types/gltf-types.ts b/modules/gltf/src/lib/types/gltf-types.ts index f3267e02f1..480b744d91 100644 --- a/modules/gltf/src/lib/types/gltf-types.ts +++ b/modules/gltf/src/lib/types/gltf-types.ts @@ -29,6 +29,10 @@ type GLTFExternalImage = data: Uint8Array; }; +export type FeatureTableJson = { + [key: string]: any[]; +}; + export type { GLTF, GLTFAccessor, diff --git a/modules/gltf/test/index.js b/modules/gltf/test/index.js index 2057d4baa6..db0c9787e8 100644 --- a/modules/gltf/test/index.js +++ b/modules/gltf/test/index.js @@ -17,6 +17,7 @@ import './lib/extensions/KHR_materials_unlit.spec'; import './lib/extensions/KHR_texture_transform.spec'; import './lib/extensions/EXT_feature_metadata.spec'; import './lib/extensions/EXT_structural_metadata.spec'; +import './lib/extensions/EXT_mesh_features.spec'; import './glb-loader.spec'; import './glb-writer.spec'; diff --git a/modules/gltf/test/lib/extensions/EXT_mesh_features.spec.ts b/modules/gltf/test/lib/extensions/EXT_mesh_features.spec.ts new file mode 100644 index 0000000000..b7c80d619d --- /dev/null +++ b/modules/gltf/test/lib/extensions/EXT_mesh_features.spec.ts @@ -0,0 +1,196 @@ +/* eslint-disable camelcase */ +import test from 'tape-promise/tape'; + +import { decodeExtensions } from '../../../src/lib/api/gltf-extensions'; + +test('gltf#EXT_mesh_features - Should decode', async (t) => { + const binaryBufferData = [ + 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 33, 223, 70, 43, 39, 58, 199, 113, 55, 81, 71, 94, 21, 60, 71, 154, 68, 219, 198, 113, 55, 81, 199, 183, 210, 225, 198, 43, 39, 58, 71, 113, 55, 81, 199, 94, 21, 60, 199, 211, 158, 216, 70, 113, 55, 81, 71, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 1, 10, 0, 68, 82, 89, 71, 82, 79, 85, 78, 68, 0, 108, 60, 0, 95, 5, 0, 1, 3, 0, 0, + // the following is to allign the buffer: + 0, 0 + ]; + + const GLTF_WITH_EXTENSION = { + buffers: [ + { + arrayBuffer: new Uint8Array(binaryBufferData).buffer, + byteOffset: 0, + byteLength: 128 + } + ], + images: [ + { + "shape": [ + 1, + 1, + 4 + ], + "data": { + "0": 111, + "1": 103, + "2": 88, + "3": 255 + }, + "width": 1, + "height": 1, + "components": 4, + "layers": [ + 1 + ] + }, + { + "shape": [ + 1, + 1, + 4 + ], + "data": { + "0": 1, + "1": 1, + "2": 1, + "3": 255 + }, + "width": 1, + "height": 1, + "components": 4, + "layers": [ + 1 + ] + } + ], + json: { + "buffers": [ + { + "byteLength": 126 + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 24, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 24, + "byteLength": 48, + "target": 34962 + }, + { + "buffer": 0, + "byteOffset": 72, + "byteLength": 32, + "target": 34962 + }, + { + "buffer": 0, + "byteOffset": 104, + "byteLength": 3 + }, + { + "buffer": 0, + "byteOffset": 107, + "byteLength": 10 + }, + { + "buffer": 0, + "byteOffset": 117, + "byteLength": 3 + }, + { + "buffer": 0, + "byteOffset": 120, + "byteLength": 3 + }, + { + "buffer": 0, + "byteOffset": 123, + "byteLength": 3 + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5125, + "count": 6, + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 4, + "type": "VEC3", + "max": [ + 48149.36831235699, + 47655.16766258143, + 53559.4425966118 + ], + "min": [ + -48149.36831235606, + -47655.16766258143, + -53559.4425966118 + ] + }, + { + "bufferView": 2, + "byteOffset": 0, + "componentType": 5126, + "count": 4, + "type": "VEC2" + } + ], + "extensions": { + }, + "extensionsUsed": [ + "EXT_mesh_features" + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "TEXCOORD_0": 2, + "POSITION": 1 + }, + "indices": 0, + "material": 0, + "extensions": { + "EXT_mesh_features": { + "featureIds": [ + { + "featureCount": 1, + "texture": { + "index": 1 + }, + "propertyTable": 0, + "data": undefined + } + ] + } + } + } + ] + } + ], + "textures": [ + { + "sampler": 0, + "source": 0 + }, + { + "sampler": 1, + "source": 1 + } + ] + } + }; + const options = { gltf: { loadImages: true, loadBuffers: true } }; + await decodeExtensions(GLTF_WITH_EXTENSION, options); + // GLTF_WITH_EXTENSION has been modified + + t.deepEqual(GLTF_WITH_EXTENSION.json.meshes[0].primitives[0].extensions.EXT_mesh_features.featureIds[0].data, [1, 1, 1, 1]); + t.end(); +}); diff --git a/modules/gltf/test/lib/extensions/EXT_structural_metadata.spec.ts b/modules/gltf/test/lib/extensions/EXT_structural_metadata.spec.ts index d785e32956..762bdf6bd2 100644 --- a/modules/gltf/test/lib/extensions/EXT_structural_metadata.spec.ts +++ b/modules/gltf/test/lib/extensions/EXT_structural_metadata.spec.ts @@ -98,7 +98,8 @@ test('gltf#EXT_structural_metadata - Should decode', async (t) => { } }; - await decodeExtensions(GLTF_WITH_EXTENSION); + const options = { gltf: { loadImages: true, loadBuffers: true } }; + await decodeExtensions(GLTF_WITH_EXTENSION, options); const expectedJson = { extensionsUsed: ['EXT_structural_metadata', 'EXT_mesh_features'], diff --git a/modules/tile-converter/src/i3s-converter/helpers/batch-ids-extensions.ts b/modules/tile-converter/src/i3s-converter/helpers/batch-ids-extensions.ts index 2199b105fe..c1a8fbfe13 100644 --- a/modules/tile-converter/src/i3s-converter/helpers/batch-ids-extensions.ts +++ b/modules/tile-converter/src/i3s-converter/helpers/batch-ids-extensions.ts @@ -94,19 +94,18 @@ function handleExtMeshFeaturesExtension( }, extMeshFeatures: GLTF_EXT_mesh_features ): NumericArray { - const dataAttributeNames = extMeshFeatures?.dataAttributeNames; - if (dataAttributeNames?.length) { - // Let's use the first element of the array - // TODO: What to do with others if any? - const batchIdsAttribute = attributes[dataAttributeNames[0]]; - return batchIdsAttribute.value; + for (let ids of extMeshFeatures.featureIds) { + if (typeof ids.propertyTable !== "undefined") { // propertyTable is an index that can be 0 + // return the first featureID set that corresponts to property table. + return ids.data as NumericArray; + } } return []; } /** * Get batchIds from EXT_feature_metadata extension. - * Docs - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata + * @see - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata * @param attributes - glTF attributes * @param extFeatureMetadata - primitive-level EXT_FEATURE_METADATA extension data * @param textures - texture images @@ -161,7 +160,7 @@ function handleExtFeatureMetadataExtension( /** * Generates implicit feature ids - * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#implicit-feature-ids + * @see - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#implicit-feature-ids * @param featuresCount * @param constant * @param devisor diff --git a/modules/tile-converter/src/i3s-converter/helpers/geometry-converter.ts b/modules/tile-converter/src/i3s-converter/helpers/geometry-converter.ts index 42f49e6722..8b72683891 100644 --- a/modules/tile-converter/src/i3s-converter/helpers/geometry-converter.ts +++ b/modules/tile-converter/src/i3s-converter/helpers/geometry-converter.ts @@ -1,14 +1,13 @@ import type {FeatureTableJson, Tiles3DTileContent} from '@loaders.gl/3d-tiles'; import type { - GLTF_EXT_mesh_features, - GLTF_EXT_structural_metadata_GLTF, GLTFAccessorPostprocessed, GLTFMaterialPostprocessed, GLTFNodePostprocessed, GLTFMeshPrimitivePostprocessed, GLTFMeshPostprocessed, GLTFTexturePostprocessed, - GLTF_EXT_feature_metadata_GLTF + GLTF_EXT_feature_metadata_GLTF, + GLTF_EXT_structural_metadata_GLTF } from '@loaders.gl/gltf'; import {Vector3, Matrix4, Vector4} from '@math.gl/core'; @@ -50,7 +49,12 @@ import type {GLTFAttributesData, TextureImageProperties, TypedArrayConstructor} import {generateSyntheticIndices} from '../../lib/utils/geometry-utils'; import {BoundingSphere, OrientedBoundingBox} from '@math.gl/culling'; -import {EXT_MESH_FEATURES, EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA} from '@loaders.gl/gltf'; +import { + EXT_FEATURE_METADATA, + EXT_STRUCTURAL_METADATA, + getPropertyTableFromExtFeatureMetadata, + getPropertyTableFromExtStructuralMetadata +} from '@loaders.gl/gltf'; // Spec - https://github.com/Esri/i3s-spec/blob/master/docs/1.7/pbrMetallicRoughness.cmn.md const DEFAULT_ROUGHNESS_FACTOR = 1; @@ -1606,7 +1610,7 @@ function generateFeatureIndexAttribute( * For example it can be batchTable for b3dm files or property table in gLTF extension. * @param tileContent - 3DTiles tile content * @param metadataClass - user selected feature metadata class name - * @return batch table from b3dm / feature properties from EXT_FEATURE_METADATA, EXT_MESH_FEATURES or EXT_STRUCTURAL_METADATA + * @return batch table from b3dm / feature properties from EXT_FEATURE_METADATA or EXT_STRUCTURAL_METADATA. */ export function getPropertyTable( tileContent: Tiles3DTileContent | null, @@ -1616,7 +1620,7 @@ export function getPropertyTable( return null; } let propertyTable: FeatureTableJson | null; - const batchTableJson = tileContent?.batchTableJson; + const batchTableJson = tileContent.batchTableJson; if (batchTableJson) { return batchTableJson; @@ -1654,13 +1658,11 @@ function getPropertyTableExtension(tileContent: Tiles3DTileContent): { | string | GLTF_EXT_feature_metadata_GLTF | GLTF_EXT_structural_metadata_GLTF - | GLTF_EXT_mesh_features | null; } { const extensionsWithPropertyTables = [ EXT_FEATURE_METADATA, - EXT_STRUCTURAL_METADATA, - EXT_MESH_FEATURES + EXT_STRUCTURAL_METADATA ]; const extensionsUsed = tileContent?.gltf?.extensionsUsed; @@ -1672,6 +1674,12 @@ function getPropertyTableExtension(tileContent: Tiles3DTileContent): { for (const extensionItem of tileContent?.gltf?.extensionsUsed || []) { if (extensionsWithPropertyTables.includes(extensionItem)) { extensionName = extensionItem; + /* + It returns the first extension containing the property table. + We assume that there can be only one extension containing the property table: + either EXT_FEATURE_METADATA, which is a depricated extension, + or EXT_STRUCTURAL_METADATA. + */ break; } } @@ -1682,117 +1690,8 @@ function getPropertyTableExtension(tileContent: Tiles3DTileContent): { const extension = tileContent?.gltf?.extensions?.[extensionName] as | string // EXT_mesh_features doesn't have global metadata - | GLTF_EXT_feature_metadata_GLTF; + | GLTF_EXT_feature_metadata_GLTF + | GLTF_EXT_structural_metadata_GLTF; return {extensionName, extension}; } - -/** - * Handle EXT_feature_metadata to get property table - * @param extension - global level of EXT_FEATURE_METADATA extension - * @param metadataClass - user selected feature metadata class name - * @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly. - */ -function getPropertyTableFromExtFeatureMetadata( - extension: GLTF_EXT_feature_metadata_GLTF, - metadataClass?: string -): FeatureTableJson | null { - if (extension?.featureTables) { - /** - * Take only first feature table to generate attributes storage info object. - * TODO: Think about getting data from all feature tables? - * It can be tricky just because 3dTiles is able to have multiple featureId attributes and multiple feature tables. - * In I3S we should decide which featureIds attribute will be passed to geometry data. - */ - const firstFeatureTableName = Object.keys(extension.featureTables)?.[0]; - - if (firstFeatureTableName) { - const featureTable = extension?.featureTables[firstFeatureTableName]; - const propertyTable = {}; - - for (const propertyName in featureTable.properties) { - propertyTable[propertyName] = featureTable.properties[propertyName].data; - } - - return propertyTable; - } - } - - if (extension?.featureTextures) { - let featureTexture: string | undefined; - for (const textureKey in extension.featureTextures) { - const texture = extension.featureTextures[textureKey]; - if (texture.class === metadataClass) { - featureTexture = textureKey; - } - } - - if (typeof featureTexture === 'string') { - const featureTable = extension?.featureTextures[featureTexture]; - const propertyTable = {}; - - for (const propertyName in featureTable.properties) { - propertyTable[propertyName] = featureTable.properties[propertyName].data; - } - - return propertyTable; - } - } - - console.warn( - "The I3S converter couldn't handle EXT_feature_metadata extension: There is neither featureTables, no featureTextures in the extension." - ); - return null; -} - -/** - * Handle EXT_structural_metadata to get property table - * @param extension - global level of EXT_STRUCTURAL_METADATA extension - * @param metadataClass - user selected feature metadata class name - * @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly. - */ -function getPropertyTableFromExtStructuralMetadata( - extension: GLTF_EXT_structural_metadata_GLTF, - metadataClass?: string -): FeatureTableJson | null { - if (extension?.propertyTables) { - /** - * Take only first feature table to generate attributes storage info object. - * TODO: Think about getting data from all feature tables? - * It can be tricky just because 3dTiles is able to have multiple featureId attributes and multiple feature tables. - * In I3S we should decide which featureIds attribute will be passed to geometry data. - */ - const firstPropertyTable = extension?.propertyTables[0]; - const propertyTableWithData = {}; - - for (const propertyName in firstPropertyTable.properties) { - propertyTableWithData[propertyName] = firstPropertyTable.properties[propertyName].data; - } - - return propertyTableWithData; - } - - if (extension?.propertyTextures) { - /** - * Take only first feature table to generate attributes storage info object. - * TODO: Think about getting data from all feature tables? - * It can be tricky just because 3dTiles is able to have multiple featureId attributes and multiple feature tables. - * In I3S we should decide which featureIds attribute will be passed to geometry data. - */ - if (extension?.propertyTextures) { - const firstPropertyTexture = extension?.propertyTextures[0]; - const propertyTableWithData = {}; - - for (const propertyName in firstPropertyTexture.properties) { - propertyTableWithData[propertyName] = firstPropertyTexture.properties[propertyName].data; - } - - return propertyTableWithData; - } - } - - console.warn( - "The I3S converter couldn't handle EXT_structural_metadata extension: There is neither propertyTables, no propertyTextures in the extension." - ); - return null; -} diff --git a/modules/tile-converter/src/i3s-converter/i3s-converter.ts b/modules/tile-converter/src/i3s-converter/i3s-converter.ts index eb65bd965e..4a2093912b 100644 --- a/modules/tile-converter/src/i3s-converter/i3s-converter.ts +++ b/modules/tile-converter/src/i3s-converter/i3s-converter.ts @@ -656,7 +656,6 @@ export default class I3SConverter { We will append new attributes only in case the property table is updated. According to ver 1.9 (see https://github.com/Esri/i3s-spec/blob/master/docs/1.9/attributeStorageInfo.cmn.md): "The attributeStorageInfo object describes the structure of the binary attribute data resource of a layer, which is the same for every node in the layer." - But the specification of ver 2.1 doesn't have such a requirement ("...the same for every node...") */ this._convertPropertyTableToNodeAttributes(propertyTable); } @@ -1167,7 +1166,6 @@ export default class I3SConverter { We will append new attributes only in case the property table is updated. According to ver 1.9 (see https://github.com/Esri/i3s-spec/blob/master/docs/1.9/attributeStorageInfo.cmn.md): "The attributeStorageInfo object describes the structure of the binary attribute data resource of a layer, which is the same for every node in the layer." - But the specification of ver 2.1 doesn't have such a requirement ("...the same for every node...") */ const found = this.layers0!.attributeStorageInfo!.find((element) => element.name === key); if (!found) { From e32caa310c95671c9af0008d8a5b927a795bfdfe Mon Sep 17 00:00:00 2001 From: mspivak-actionengine Date: Thu, 21 Sep 2023 18:11:13 +0300 Subject: [PATCH 2/3] prettier run --- .../lib/extensions/EXT_structural_metadata.ts | 7 +- .../deprecated/EXT_feature_metadata.ts | 14 +- .../lib/extensions/utils/3d-tiles-utils.ts | 13 +- modules/gltf/src/lib/gltf-utils/gltf-utils.ts | 5 +- .../gltf-ext-structural-metadata-schema.ts | 2 +- .../lib/extensions/EXT_mesh_features.spec.ts | 219 ++++++++---------- .../EXT_structural_metadata.spec.ts | 2 +- .../helpers/batch-ids-extensions.ts | 3 +- .../helpers/geometry-converter.ts | 11 +- 9 files changed, 133 insertions(+), 143 deletions(-) diff --git a/modules/gltf/src/lib/extensions/EXT_structural_metadata.ts b/modules/gltf/src/lib/extensions/EXT_structural_metadata.ts index 11a126bcfe..166123020f 100644 --- a/modules/gltf/src/lib/extensions/EXT_structural_metadata.ts +++ b/modules/gltf/src/lib/extensions/EXT_structural_metadata.ts @@ -74,8 +74,9 @@ export function getPropertyTableFromExtStructuralMetadata( return propertyTableWithData; } + // eslint-disable-next-line no-console console.warn( - "Can't get property table from EXT_structural_metadata extension. There is neither propertyTables, nor propertyTextures in the extension." + 'Cannot get property table from EXT_structural_metadata extension. There is neither propertyTables, nor propertyTextures in the extension.' ); return null; } @@ -189,7 +190,7 @@ function decodeExtStructuralMetadata(scenegraph: GLTFScenegraph, options: GLTFLo /** * Processes the data stored in the textures * @param scenegraph - Instance of the class for structured access to GLTF data. - * @param extension - Top-level extension. + * @param extension - Top-level extension. */ function decodePropertyTextures( scenegraph: GLTFScenegraph, @@ -210,7 +211,7 @@ function decodePropertyTextures( /** * Processes the data stored in the property tables. * @param scenegraph - Instance of the class for structured access to GLTF data. - * @param extension - Top-level extension. + * @param extension - Top-level extension. */ function decodePropertyTables( scenegraph: GLTFScenegraph, diff --git a/modules/gltf/src/lib/extensions/deprecated/EXT_feature_metadata.ts b/modules/gltf/src/lib/extensions/deprecated/EXT_feature_metadata.ts index e1f96d71b0..9bca0de0df 100644 --- a/modules/gltf/src/lib/extensions/deprecated/EXT_feature_metadata.ts +++ b/modules/gltf/src/lib/extensions/deprecated/EXT_feature_metadata.ts @@ -80,8 +80,9 @@ export function getPropertyTableFromExtFeatureMetadata( } } + // eslint-disable-next-line no-console console.warn( - "Can't get property table from EXT_feature_metadata extension. There is neither featureTables, nor featureTextures in the extension." + 'Cannot get property table from EXT_feature_metadata extension. There is neither featureTables, nor featureTextures in the extension.' ); return null; } @@ -381,10 +382,13 @@ function processPrimitiveTextures( const texCoordAccessorIndex = primitive.attributes[texCoordAccessorKey]; // textureCoordinates contains UV coordinates of the actual data stored in the texture // accessor.count is a number of UV pairs (they are stored as VEC2) - const textureCoordinates: Float32Array | null = getFloat32ArrayForAccessor(scenegraph.gltf, texCoordAccessorIndex); - if (!textureCoordinates) { - return; - } + const textureCoordinates: Float32Array | null = getFloat32ArrayForAccessor( + scenegraph.gltf, + texCoordAccessorIndex + ); + if (!textureCoordinates) { + return; + } const textureIndex = featureTextureProperty.texture.index; const texture = json.textures?.[textureIndex]; diff --git a/modules/gltf/src/lib/extensions/utils/3d-tiles-utils.ts b/modules/gltf/src/lib/extensions/utils/3d-tiles-utils.ts index 74d14d8e1e..a69d680e32 100644 --- a/modules/gltf/src/lib/extensions/utils/3d-tiles-utils.ts +++ b/modules/gltf/src/lib/extensions/utils/3d-tiles-utils.ts @@ -171,10 +171,13 @@ export function getPrimitiveTextureData( const texCoordAccessorKey = `TEXCOORD_${textureInfo.texCoord || 0}`; const texCoordAccessorIndex = primitive.attributes[texCoordAccessorKey]; - const textureCoordinates: Float32Array | null = getFloat32ArrayForAccessor(scenegraph.gltf, texCoordAccessorIndex); - if (!textureCoordinates) { - return null; - } + const textureCoordinates: Float32Array | null = getFloat32ArrayForAccessor( + scenegraph.gltf, + texCoordAccessorIndex + ); + if (!textureCoordinates) { + return null; + } const textureIndex: number = textureInfo.index; const imageIndex = json.textures?.[textureIndex]?.source; @@ -285,7 +288,7 @@ function getImageValueByCoordinates( let value: number = 0; for (const c of channels) { // We can get the element of CHANNELS_MAP by either index (0, 1, 2, 3) or key (r, g, b, a) - const map = typeof c === "number" ? Object.values(CHANNELS_MAP)[c] : CHANNELS_MAP[c]; + const map = typeof c === 'number' ? Object.values(CHANNELS_MAP)[c] : CHANNELS_MAP[c]; const imageOffset = offset + map.offset; const imageData = getImageData(parsedImage); if (imageData.data.length <= imageOffset) { diff --git a/modules/gltf/src/lib/gltf-utils/gltf-utils.ts b/modules/gltf/src/lib/gltf-utils/gltf-utils.ts index 4e9874ca69..0c5a031724 100644 --- a/modules/gltf/src/lib/gltf-utils/gltf-utils.ts +++ b/modules/gltf/src/lib/gltf-utils/gltf-utils.ts @@ -88,7 +88,10 @@ export function getAccessorArrayTypeAndLength(accessor, bufferView) { return {ArrayType, length, byteLength}; } -export function getFloat32ArrayForAccessor(gltfData: GLTFWithBuffers, texCoordAccessor: number): Float32Array | null { +export function getFloat32ArrayForAccessor( + gltfData: GLTFWithBuffers, + texCoordAccessor: number +): Float32Array | null { const accessor = gltfData.json.accessors?.[texCoordAccessor]; if (accessor && accessor.bufferView) { // Get `bufferView` of the `accessor` diff --git a/modules/gltf/src/lib/types/gltf-ext-structural-metadata-schema.ts b/modules/gltf/src/lib/types/gltf-ext-structural-metadata-schema.ts index 1bca88e338..cb59fdeae6 100644 --- a/modules/gltf/src/lib/types/gltf-ext-structural-metadata-schema.ts +++ b/modules/gltf/src/lib/types/gltf-ext-structural-metadata-schema.ts @@ -58,7 +58,7 @@ export type GLTF_EXT_structural_metadata_Enum = { /** * The type of the integer enum value. * Default value is 'UINT16' - */ + */ valueType?: 'INT8' | 'UINT8' | 'INT16' | 'UINT16' | 'INT32' | 'UINT32' | 'INT64' | 'UINT64'; /** An array of enum values. Duplicate names or duplicate integer values are not allowed. */ values: GLTF_EXT_structural_metadata_EnumValue[]; diff --git a/modules/gltf/test/lib/extensions/EXT_mesh_features.spec.ts b/modules/gltf/test/lib/extensions/EXT_mesh_features.spec.ts index b7c80d619d..aec8b68e62 100644 --- a/modules/gltf/test/lib/extensions/EXT_mesh_features.spec.ts +++ b/modules/gltf/test/lib/extensions/EXT_mesh_features.spec.ts @@ -1,11 +1,15 @@ /* eslint-disable camelcase */ import test from 'tape-promise/tape'; -import { decodeExtensions } from '../../../src/lib/api/gltf-extensions'; +import {decodeExtensions} from '../../../src/lib/api/gltf-extensions'; test('gltf#EXT_mesh_features - Should decode', async (t) => { const binaryBufferData = [ - 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 33, 223, 70, 43, 39, 58, 199, 113, 55, 81, 71, 94, 21, 60, 71, 154, 68, 219, 198, 113, 55, 81, 199, 183, 210, 225, 198, 43, 39, 58, 71, 113, 55, 81, 199, 94, 21, 60, 199, 211, 158, 216, 70, 113, 55, 81, 71, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 1, 10, 0, 68, 82, 89, 71, 82, 79, 85, 78, 68, 0, 108, 60, 0, 95, 5, 0, 1, 3, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 33, 223, 70, 43, 39, + 58, 199, 113, 55, 81, 71, 94, 21, 60, 71, 154, 68, 219, 198, 113, 55, 81, 199, 183, 210, 225, + 198, 43, 39, 58, 71, 113, 55, 81, 199, 94, 21, 60, 199, 211, 158, 216, 70, 113, 55, 81, 71, 0, + 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, + 0, 1, 10, 0, 68, 82, 89, 71, 82, 79, 85, 78, 68, 0, 108, 60, 0, 95, 5, 0, 1, 3, 0, 0, // the following is to allign the buffer: 0, 0 ]; @@ -20,153 +24,130 @@ test('gltf#EXT_mesh_features - Should decode', async (t) => { ], images: [ { - "shape": [ - 1, - 1, - 4 - ], - "data": { - "0": 111, - "1": 103, - "2": 88, - "3": 255 + shape: [1, 1, 4], + data: { + '0': 111, + '1': 103, + '2': 88, + '3': 255 }, - "width": 1, - "height": 1, - "components": 4, - "layers": [ - 1 - ] + width: 1, + height: 1, + components: 4, + layers: [1] }, { - "shape": [ - 1, - 1, - 4 - ], - "data": { - "0": 1, - "1": 1, - "2": 1, - "3": 255 + shape: [1, 1, 4], + data: { + '0': 1, + '1': 1, + '2': 1, + '3': 255 }, - "width": 1, - "height": 1, - "components": 4, - "layers": [ - 1 - ] + width: 1, + height: 1, + components: 4, + layers: [1] } ], json: { - "buffers": [ + buffers: [ { - "byteLength": 126 + byteLength: 126 } ], - "bufferViews": [ + bufferViews: [ { - "buffer": 0, - "byteOffset": 0, - "byteLength": 24, - "target": 34963 + buffer: 0, + byteOffset: 0, + byteLength: 24, + target: 34963 }, { - "buffer": 0, - "byteOffset": 24, - "byteLength": 48, - "target": 34962 + buffer: 0, + byteOffset: 24, + byteLength: 48, + target: 34962 }, { - "buffer": 0, - "byteOffset": 72, - "byteLength": 32, - "target": 34962 + buffer: 0, + byteOffset: 72, + byteLength: 32, + target: 34962 }, { - "buffer": 0, - "byteOffset": 104, - "byteLength": 3 + buffer: 0, + byteOffset: 104, + byteLength: 3 }, { - "buffer": 0, - "byteOffset": 107, - "byteLength": 10 + buffer: 0, + byteOffset: 107, + byteLength: 10 }, { - "buffer": 0, - "byteOffset": 117, - "byteLength": 3 + buffer: 0, + byteOffset: 117, + byteLength: 3 }, { - "buffer": 0, - "byteOffset": 120, - "byteLength": 3 + buffer: 0, + byteOffset: 120, + byteLength: 3 }, { - "buffer": 0, - "byteOffset": 123, - "byteLength": 3 + buffer: 0, + byteOffset: 123, + byteLength: 3 } ], - "accessors": [ + accessors: [ { - "bufferView": 0, - "byteOffset": 0, - "componentType": 5125, - "count": 6, - "type": "SCALAR" + bufferView: 0, + byteOffset: 0, + componentType: 5125, + count: 6, + type: 'SCALAR' }, { - "bufferView": 1, - "byteOffset": 0, - "componentType": 5126, - "count": 4, - "type": "VEC3", - "max": [ - 48149.36831235699, - 47655.16766258143, - 53559.4425966118 - ], - "min": [ - -48149.36831235606, - -47655.16766258143, - -53559.4425966118 - ] + bufferView: 1, + byteOffset: 0, + componentType: 5126, + count: 4, + type: 'VEC3', + max: [48149.36831235699, 47655.16766258143, 53559.4425966118], + min: [-48149.36831235606, -47655.16766258143, -53559.4425966118] }, { - "bufferView": 2, - "byteOffset": 0, - "componentType": 5126, - "count": 4, - "type": "VEC2" + bufferView: 2, + byteOffset: 0, + componentType: 5126, + count: 4, + type: 'VEC2' } ], - "extensions": { - }, - "extensionsUsed": [ - "EXT_mesh_features" - ], - "meshes": [ + extensions: {}, + extensionsUsed: ['EXT_mesh_features'], + meshes: [ { - "primitives": [ + primitives: [ { - "attributes": { - "TEXCOORD_0": 2, - "POSITION": 1 + attributes: { + TEXCOORD_0: 2, + POSITION: 1 }, - "indices": 0, - "material": 0, - "extensions": { - "EXT_mesh_features": { - "featureIds": [ + indices: 0, + material: 0, + extensions: { + EXT_mesh_features: { + featureIds: [ { - "featureCount": 1, - "texture": { - "index": 1 + featureCount: 1, + texture: { + index: 1 }, - "propertyTable": 0, - "data": undefined + propertyTable: 0, + data: undefined } ] } @@ -175,22 +156,26 @@ test('gltf#EXT_mesh_features - Should decode', async (t) => { ] } ], - "textures": [ + textures: [ { - "sampler": 0, - "source": 0 + sampler: 0, + source: 0 }, { - "sampler": 1, - "source": 1 + sampler: 1, + source: 1 } ] } }; - const options = { gltf: { loadImages: true, loadBuffers: true } }; + const options = {gltf: {loadImages: true, loadBuffers: true}}; await decodeExtensions(GLTF_WITH_EXTENSION, options); // GLTF_WITH_EXTENSION has been modified - t.deepEqual(GLTF_WITH_EXTENSION.json.meshes[0].primitives[0].extensions.EXT_mesh_features.featureIds[0].data, [1, 1, 1, 1]); + t.deepEqual( + GLTF_WITH_EXTENSION.json.meshes[0].primitives[0].extensions.EXT_mesh_features.featureIds[0] + .data, + [1, 1, 1, 1] + ); t.end(); }); diff --git a/modules/gltf/test/lib/extensions/EXT_structural_metadata.spec.ts b/modules/gltf/test/lib/extensions/EXT_structural_metadata.spec.ts index 762bdf6bd2..67ff0c986b 100644 --- a/modules/gltf/test/lib/extensions/EXT_structural_metadata.spec.ts +++ b/modules/gltf/test/lib/extensions/EXT_structural_metadata.spec.ts @@ -98,7 +98,7 @@ test('gltf#EXT_structural_metadata - Should decode', async (t) => { } }; - const options = { gltf: { loadImages: true, loadBuffers: true } }; + const options = {gltf: {loadImages: true, loadBuffers: true}}; await decodeExtensions(GLTF_WITH_EXTENSION, options); const expectedJson = { diff --git a/modules/tile-converter/src/i3s-converter/helpers/batch-ids-extensions.ts b/modules/tile-converter/src/i3s-converter/helpers/batch-ids-extensions.ts index c1a8fbfe13..6a6e19c3a2 100644 --- a/modules/tile-converter/src/i3s-converter/helpers/batch-ids-extensions.ts +++ b/modules/tile-converter/src/i3s-converter/helpers/batch-ids-extensions.ts @@ -95,7 +95,8 @@ function handleExtMeshFeaturesExtension( extMeshFeatures: GLTF_EXT_mesh_features ): NumericArray { for (let ids of extMeshFeatures.featureIds) { - if (typeof ids.propertyTable !== "undefined") { // propertyTable is an index that can be 0 + if (typeof ids.propertyTable !== 'undefined') { + // propertyTable is an index that can be 0 // return the first featureID set that corresponts to property table. return ids.data as NumericArray; } diff --git a/modules/tile-converter/src/i3s-converter/helpers/geometry-converter.ts b/modules/tile-converter/src/i3s-converter/helpers/geometry-converter.ts index 8b72683891..4df0050f7e 100644 --- a/modules/tile-converter/src/i3s-converter/helpers/geometry-converter.ts +++ b/modules/tile-converter/src/i3s-converter/helpers/geometry-converter.ts @@ -1654,16 +1654,9 @@ export function getPropertyTable( */ function getPropertyTableExtension(tileContent: Tiles3DTileContent): { extensionName: null | string; - extension: - | string - | GLTF_EXT_feature_metadata_GLTF - | GLTF_EXT_structural_metadata_GLTF - | null; + extension: string | GLTF_EXT_feature_metadata_GLTF | GLTF_EXT_structural_metadata_GLTF | null; } { - const extensionsWithPropertyTables = [ - EXT_FEATURE_METADATA, - EXT_STRUCTURAL_METADATA - ]; + const extensionsWithPropertyTables = [EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA]; const extensionsUsed = tileContent?.gltf?.extensionsUsed; if (!extensionsUsed) { From 0132425dca82d0486bda9145b9cf259d3fb15384 Mon Sep 17 00:00:00 2001 From: mspivak-actionengine Date: Thu, 21 Sep 2023 21:58:22 +0300 Subject: [PATCH 3/3] comment added --- .../gltf/src/lib/extensions/utils/3d-tiles-utils.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/modules/gltf/src/lib/extensions/utils/3d-tiles-utils.ts b/modules/gltf/src/lib/extensions/utils/3d-tiles-utils.ts index a69d680e32..91bcbb0d0a 100644 --- a/modules/gltf/src/lib/extensions/utils/3d-tiles-utils.ts +++ b/modules/gltf/src/lib/extensions/utils/3d-tiles-utils.ts @@ -287,7 +287,15 @@ function getImageValueByCoordinates( const offset = coordinatesToOffset(u, v, parsedImage, components); let value: number = 0; for (const c of channels) { - // We can get the element of CHANNELS_MAP by either index (0, 1, 2, 3) or key (r, g, b, a) + /* + According to the EXT_feature_metadata extension specification: + Channels are labeled by rgba and are swizzled with a string of 1-4 characters. + According to the EXT_mesh_features extension specification: + The channels array contains non-negative integer values corresponding to channels of the source texture that the feature ID consists of. + Channels of an RGBA texture are numbered 0–3 respectively. + Function getImageValueByCoordinates is used to process both extensions. + So, there should be possible to get the element of CHANNELS_MAP by either index (0, 1, 2, 3) or key (r, g, b, a). + */ const map = typeof c === 'number' ? Object.values(CHANNELS_MAP)[c] : CHANNELS_MAP[c]; const imageOffset = offset + map.offset; const imageData = getImageData(parsedImage);