GltfLoader.js 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836
  1. import arrayFill from "../Core/arrayFill.js";
  2. import Cartesian3 from "../Core/Cartesian3.js";
  3. import Cartesian4 from "../Core/Cartesian4.js";
  4. import Check from "../Core/Check.js";
  5. import ComponentDatatype from "../Core/ComponentDatatype.js";
  6. import Credit from "../Core/Credit.js";
  7. import defaultValue from "../Core/defaultValue.js";
  8. import defer from "../Core/defer.js";
  9. import defined from "../Core/defined.js";
  10. import InterpolationType from "../Core/InterpolationType.js";
  11. import FeatureDetection from "../Core/FeatureDetection.js";
  12. import Matrix4 from "../Core/Matrix4.js";
  13. import Quaternion from "../Core/Quaternion.js";
  14. import Sampler from "../Renderer/Sampler.js";
  15. import getAccessorByteStride from "./GltfPipeline/getAccessorByteStride.js";
  16. import getComponentReader from "./GltfPipeline/getComponentReader.js";
  17. import numberOfComponentsForType from "./GltfPipeline/numberOfComponentsForType.js";
  18. import AttributeType from "./AttributeType.js";
  19. import Axis from "./Axis.js";
  20. import GltfStructuralMetadataLoader from "./GltfStructuralMetadataLoader.js";
  21. import GltfLoaderUtil from "./GltfLoaderUtil.js";
  22. import InstanceAttributeSemantic from "./InstanceAttributeSemantic.js";
  23. import ModelComponents from "./ModelComponents.js";
  24. import ResourceCache from "./ResourceCache.js";
  25. import ResourceLoader from "./ResourceLoader.js";
  26. import SupportedImageFormats from "./SupportedImageFormats.js";
  27. import VertexAttributeSemantic from "./VertexAttributeSemantic.js";
  28. const Attribute = ModelComponents.Attribute;
  29. const Indices = ModelComponents.Indices;
  30. const FeatureIdAttribute = ModelComponents.FeatureIdAttribute;
  31. const FeatureIdTexture = ModelComponents.FeatureIdTexture;
  32. const FeatureIdImplicitRange = ModelComponents.FeatureIdImplicitRange;
  33. const MorphTarget = ModelComponents.MorphTarget;
  34. const Primitive = ModelComponents.Primitive;
  35. const Instances = ModelComponents.Instances;
  36. const Skin = ModelComponents.Skin;
  37. const Node = ModelComponents.Node;
  38. const AnimatedPropertyType = ModelComponents.AnimatedPropertyType;
  39. const AnimationSampler = ModelComponents.AnimationSampler;
  40. const AnimationTarget = ModelComponents.AnimationTarget;
  41. const AnimationChannel = ModelComponents.AnimationChannel;
  42. const Animation = ModelComponents.Animation;
  43. const Asset = ModelComponents.Asset;
  44. const Scene = ModelComponents.Scene;
  45. const Components = ModelComponents.Components;
  46. const MetallicRoughness = ModelComponents.MetallicRoughness;
  47. const SpecularGlossiness = ModelComponents.SpecularGlossiness;
  48. const Material = ModelComponents.Material;
  49. const GltfLoaderState = {
  50. UNLOADED: 0,
  51. LOADING: 1,
  52. LOADED: 2,
  53. PROCESSING: 3,
  54. PROCESSED: 4,
  55. READY: 4,
  56. FAILED: 5,
  57. };
  58. /**
  59. * Loads a glTF model.
  60. * <p>
  61. * Implements the {@link ResourceLoader} interface.
  62. * </p>
  63. *
  64. * @alias GltfLoader
  65. * @constructor
  66. * @augments ResourceLoader
  67. *
  68. * @param {Object} options Object with the following properties:
  69. * @param {Resource} options.gltfResource The {@link Resource} containing the glTF. This is often the path of the .gltf or .glb file, but may also be the path of the .b3dm, .i3dm, or .cmpt file containing the embedded glb. .cmpt resources should have a URI fragment indicating the index of the inner content to which the glb belongs in order to individually identify the glb in the cache, e.g. http://example.com/tile.cmpt#index=2.
  70. * @param {Resource} [options.baseResource] The {@link Resource} that paths in the glTF JSON are relative to.
  71. * @param {Uint8Array} [options.typedArray] The typed array containing the glTF contents, e.g. from a .b3dm, .i3dm, or .cmpt file.
  72. * @param {Object} [options.gltfJson] A parsed glTF JSON file instead of passing it in as a typed array.
  73. * @param {Boolean} [options.releaseGltfJson=false] When true, the glTF JSON is released once the glTF is loaded. This is is especially useful for cases like 3D Tiles, where each .gltf model is unique and caching the glTF JSON is not effective.
  74. * @param {Boolean} [options.asynchronous=true] Determines if WebGL resource creation will be spread out over several frames or block until all WebGL resources are created.
  75. * @param {Boolean} [options.incrementallyLoadTextures=true] Determine if textures may continue to stream in after the glTF is loaded.
  76. * @param {Axis} [options.upAxis=Axis.Y] The up-axis of the glTF model.
  77. * @param {Axis} [options.forwardAxis=Axis.Z] The forward-axis of the glTF model.
  78. * @param {Boolean} [options.loadAsTypedArray=false] Load all attributes and indices as typed arrays instead of GPU buffers.
  79. * @param {Boolean} [options.renameBatchIdSemantic=false] If true, rename _BATCHID or BATCHID to _FEATURE_ID_0. This is used for .b3dm models
  80. *
  81. * @private
  82. */
  83. export default function GltfLoader(options) {
  84. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  85. const gltfResource = options.gltfResource;
  86. let baseResource = options.baseResource;
  87. const typedArray = options.typedArray;
  88. const releaseGltfJson = defaultValue(options.releaseGltfJson, false);
  89. const asynchronous = defaultValue(options.asynchronous, true);
  90. const incrementallyLoadTextures = defaultValue(
  91. options.incrementallyLoadTextures,
  92. true
  93. );
  94. const upAxis = defaultValue(options.upAxis, Axis.Y);
  95. const forwardAxis = defaultValue(options.forwardAxis, Axis.Z);
  96. const loadAsTypedArray = defaultValue(options.loadAsTypedArray, false);
  97. const renameBatchIdSemantic = defaultValue(
  98. options.renameBatchIdSemantic,
  99. false
  100. );
  101. //>>includeStart('debug', pragmas.debug);
  102. Check.typeOf.object("options.gltfResource", gltfResource);
  103. //>>includeEnd('debug');
  104. baseResource = defined(baseResource) ? baseResource : gltfResource.clone();
  105. this._gltfJson = options.gltfJson;
  106. this._gltfResource = gltfResource;
  107. this._baseResource = baseResource;
  108. this._typedArray = typedArray;
  109. this._releaseGltfJson = releaseGltfJson;
  110. this._asynchronous = asynchronous;
  111. this._incrementallyLoadTextures = incrementallyLoadTextures;
  112. this._upAxis = upAxis;
  113. this._forwardAxis = forwardAxis;
  114. this._loadAsTypedArray = loadAsTypedArray;
  115. this._renameBatchIdSemantic = renameBatchIdSemantic;
  116. // When loading EXT_feature_metadata, the feature tables and textures
  117. // are now stored as arrays like the newer EXT_structural_metadata extension.
  118. // This requires sorting the dictionary keys for a consistent ordering.
  119. this._sortedPropertyTableIds = undefined;
  120. this._sortedFeatureTextureIds = undefined;
  121. this._gltfJsonLoader = undefined;
  122. this._state = GltfLoaderState.UNLOADED;
  123. this._textureState = GltfLoaderState.UNLOADED;
  124. this._promise = defer();
  125. this._texturesLoadedPromise = defer();
  126. // Loaders that need to be processed before the glTF becomes ready
  127. this._textureLoaders = [];
  128. this._bufferViewLoaders = [];
  129. this._geometryLoaders = [];
  130. this._structuralMetadataLoader = undefined;
  131. // Loaded results
  132. this._components = undefined;
  133. }
  134. if (defined(Object.create)) {
  135. GltfLoader.prototype = Object.create(ResourceLoader.prototype);
  136. GltfLoader.prototype.constructor = GltfLoader;
  137. }
  138. Object.defineProperties(GltfLoader.prototype, {
  139. /**
  140. * A promise that resolves to the resource when the resource is ready.
  141. *
  142. * @memberof GltfLoader.prototype
  143. *
  144. * @type {Promise.<GltfLoader>}
  145. * @readonly
  146. * @private
  147. */
  148. promise: {
  149. get: function () {
  150. return this._promise.promise;
  151. },
  152. },
  153. /**
  154. * The cache key of the resource.
  155. *
  156. * @memberof GltfLoader.prototype
  157. *
  158. * @type {String}
  159. * @readonly
  160. * @private
  161. */
  162. cacheKey: {
  163. get: function () {
  164. return undefined;
  165. },
  166. },
  167. /**
  168. * The loaded components.
  169. *
  170. * @memberof GltfLoader.prototype
  171. *
  172. * @type {ModelComponents.Components}
  173. * @readonly
  174. * @private
  175. */
  176. components: {
  177. get: function () {
  178. return this._components;
  179. },
  180. },
  181. /**
  182. * A promise that resolves when all textures are loaded.
  183. * When <code>incrementallyLoadTextures</code> is true this may resolve after
  184. * <code>promise</code> resolves.
  185. *
  186. * @memberof GltfLoader.prototype
  187. *
  188. * @type {Promise<void>}
  189. * @readonly
  190. * @private
  191. */
  192. texturesLoadedPromise: {
  193. get: function () {
  194. return this._texturesLoadedPromise.promise;
  195. },
  196. },
  197. });
  198. /**
  199. * Loads the resource.
  200. * @private
  201. */
  202. GltfLoader.prototype.load = function () {
  203. const gltfJsonLoader = ResourceCache.loadGltfJson({
  204. gltfResource: this._gltfResource,
  205. baseResource: this._baseResource,
  206. typedArray: this._typedArray,
  207. gltfJson: this._gltfJson,
  208. });
  209. this._gltfJsonLoader = gltfJsonLoader;
  210. this._state = GltfLoaderState.LOADING;
  211. this._textureState = GltfLoaderState.LOADING;
  212. const that = this;
  213. gltfJsonLoader.promise
  214. .then(function () {
  215. if (that.isDestroyed()) {
  216. return;
  217. }
  218. that._state = GltfLoaderState.LOADED;
  219. that._textureState = GltfLoaderState.LOADED;
  220. })
  221. .catch(function (error) {
  222. if (that.isDestroyed()) {
  223. return;
  224. }
  225. handleError(that, error);
  226. });
  227. };
  228. function handleError(gltfLoader, error) {
  229. gltfLoader.unload();
  230. gltfLoader._state = GltfLoaderState.FAILED;
  231. gltfLoader._textureState = GltfLoaderState.FAILED;
  232. const errorMessage = "Failed to load glTF";
  233. error = gltfLoader.getError(errorMessage, error);
  234. gltfLoader._promise.reject(error);
  235. gltfLoader._texturesLoadedPromise.reject(error);
  236. }
  237. function process(loader, frameState) {
  238. let i;
  239. const textureLoaders = loader._textureLoaders;
  240. const textureLoadersLength = textureLoaders.length;
  241. for (i = 0; i < textureLoadersLength; ++i) {
  242. textureLoaders[i].process(frameState);
  243. }
  244. const bufferViewLoaders = loader._bufferViewLoaders;
  245. const bufferViewLoadersLength = bufferViewLoaders.length;
  246. for (i = 0; i < bufferViewLoadersLength; ++i) {
  247. bufferViewLoaders[i].process(frameState);
  248. }
  249. const geometryLoaders = loader._geometryLoaders;
  250. const geometryLoadersLength = geometryLoaders.length;
  251. for (i = 0; i < geometryLoadersLength; ++i) {
  252. geometryLoaders[i].process(frameState);
  253. }
  254. if (defined(loader._structuralMetadataLoader)) {
  255. loader._structuralMetadataLoader.process(frameState);
  256. }
  257. }
  258. /**
  259. * Processes the resource until it becomes ready.
  260. *
  261. * @param {FrameState} frameState The frame state.
  262. * @private
  263. */
  264. GltfLoader.prototype.process = function (frameState) {
  265. //>>includeStart('debug', pragmas.debug);
  266. Check.typeOf.object("frameState", frameState);
  267. //>>includeEnd('debug');
  268. if (!FeatureDetection.supportsWebP.initialized) {
  269. FeatureDetection.supportsWebP.initialize();
  270. return;
  271. }
  272. if (this._state === GltfLoaderState.LOADED) {
  273. this._state = GltfLoaderState.PROCESSING;
  274. const supportedImageFormats = new SupportedImageFormats({
  275. webp: FeatureDetection.supportsWebP(),
  276. basis: frameState.context.supportsBasis,
  277. });
  278. let gltf;
  279. if (defined(this._gltfJsonLoader)) {
  280. gltf = this._gltfJsonLoader.gltf;
  281. } else {
  282. gltf = this._gltfJson;
  283. }
  284. // Parse the glTF which populates the loaders arrays. The ready promise
  285. // resolves once all the loaders are ready (i.e. all external resources
  286. // have been fetched and all GPU resources have been created). Loaders that
  287. // create GPU resources need to be processed every frame until they become
  288. // ready since the JobScheduler is not able to execute all jobs in a single
  289. // frame. Also note that it's fine to call process before a loader is ready
  290. // to process; nothing will happen.
  291. parse(this, gltf, supportedImageFormats, frameState);
  292. if (defined(this._gltfJsonLoader) && this._releaseGltfJson) {
  293. // Check that the glTF JSON loader is still defined before trying to unload it.
  294. // It may be undefined if the ready promise rejects immediately (which can happen in unit tests)
  295. ResourceCache.unload(this._gltfJsonLoader);
  296. this._gltfJsonLoader = undefined;
  297. }
  298. }
  299. if (this._textureState === GltfLoaderState.LOADED) {
  300. this._textureState = GltfLoaderState.PROCESSING;
  301. }
  302. if (
  303. this._state === GltfLoaderState.PROCESSING ||
  304. this._textureState === GltfLoaderState.PROCESSING
  305. ) {
  306. process(this, frameState);
  307. }
  308. if (this._state === GltfLoaderState.PROCESSED) {
  309. unloadBufferViews(this); // Buffer views can be unloaded after the data has been copied
  310. this._state = GltfLoaderState.READY;
  311. this._promise.resolve(this);
  312. }
  313. if (this._textureState === GltfLoaderState.PROCESSED) {
  314. this._textureState = GltfLoaderState.READY;
  315. this._texturesLoadedPromise.resolve(this);
  316. }
  317. };
  318. function loadVertexBuffer(
  319. loader,
  320. gltf,
  321. accessorId,
  322. semantic,
  323. draco,
  324. dequantize,
  325. loadAsTypedArray
  326. ) {
  327. const accessor = gltf.accessors[accessorId];
  328. const bufferViewId = accessor.bufferView;
  329. const vertexBufferLoader = ResourceCache.loadVertexBuffer({
  330. gltf: gltf,
  331. gltfResource: loader._gltfResource,
  332. baseResource: loader._baseResource,
  333. bufferViewId: bufferViewId,
  334. draco: draco,
  335. attributeSemantic: semantic,
  336. accessorId: accessorId,
  337. asynchronous: loader._asynchronous,
  338. dequantize: dequantize,
  339. loadAsTypedArray: loadAsTypedArray,
  340. });
  341. loader._geometryLoaders.push(vertexBufferLoader);
  342. return vertexBufferLoader;
  343. }
  344. function loadIndexBuffer(loader, gltf, accessorId, draco, loadAsTypedArray) {
  345. const indexBufferLoader = ResourceCache.loadIndexBuffer({
  346. gltf: gltf,
  347. accessorId: accessorId,
  348. gltfResource: loader._gltfResource,
  349. baseResource: loader._baseResource,
  350. draco: draco,
  351. asynchronous: loader._asynchronous,
  352. loadAsTypedArray: loadAsTypedArray,
  353. });
  354. loader._geometryLoaders.push(indexBufferLoader);
  355. return indexBufferLoader;
  356. }
  357. function loadBufferView(loader, gltf, bufferViewId) {
  358. const bufferViewLoader = ResourceCache.loadBufferView({
  359. gltf: gltf,
  360. bufferViewId: bufferViewId,
  361. gltfResource: loader._gltfResource,
  362. baseResource: loader._baseResource,
  363. });
  364. loader._bufferViewLoaders.push(bufferViewLoader);
  365. return bufferViewLoader;
  366. }
  367. function getPackedTypedArray(gltf, accessor, bufferViewTypedArray) {
  368. let byteOffset = accessor.byteOffset;
  369. const byteStride = getAccessorByteStride(gltf, accessor);
  370. const count = accessor.count;
  371. const componentCount = numberOfComponentsForType(accessor.type);
  372. const componentType = accessor.componentType;
  373. const componentByteLength = ComponentDatatype.getSizeInBytes(componentType);
  374. const defaultByteStride = componentByteLength * componentCount;
  375. const componentsLength = count * componentCount;
  376. if (byteStride === defaultByteStride) {
  377. // Copy the typed array and let the underlying ArrayBuffer be freed
  378. bufferViewTypedArray = new Uint8Array(bufferViewTypedArray);
  379. return ComponentDatatype.createArrayBufferView(
  380. componentType,
  381. bufferViewTypedArray.buffer,
  382. bufferViewTypedArray.byteOffset + byteOffset,
  383. componentsLength
  384. );
  385. }
  386. const accessorTypedArray = ComponentDatatype.createTypedArray(
  387. componentType,
  388. componentsLength
  389. );
  390. const dataView = new DataView(bufferViewTypedArray.buffer);
  391. const components = new Array(componentCount);
  392. const componentReader = getComponentReader(accessor.componentType);
  393. byteOffset = bufferViewTypedArray.byteOffset + byteOffset;
  394. for (let i = 0; i < count; ++i) {
  395. componentReader(
  396. dataView,
  397. byteOffset,
  398. componentCount,
  399. componentByteLength,
  400. components
  401. );
  402. for (let j = 0; j < componentCount; ++j) {
  403. accessorTypedArray[i * componentCount + j] = components[j];
  404. }
  405. byteOffset += byteStride;
  406. }
  407. return accessorTypedArray;
  408. }
  409. function loadDefaultAccessorValues(accessor, values) {
  410. const accessorType = accessor.type;
  411. if (accessorType === AttributeType.SCALAR) {
  412. return arrayFill(values, 0);
  413. }
  414. const MathType = AttributeType.getMathType(accessorType);
  415. return arrayFill(values, MathType.clone(MathType.ZERO));
  416. }
  417. function loadAccessorValues(accessor, packedTypedArray, values, useQuaternion) {
  418. const accessorType = accessor.type;
  419. const accessorCount = accessor.count;
  420. if (accessorType === AttributeType.SCALAR) {
  421. for (let i = 0; i < accessorCount; i++) {
  422. values[i] = packedTypedArray[i];
  423. }
  424. } else if (accessorType === AttributeType.VEC4 && useQuaternion) {
  425. for (let i = 0; i < accessorCount; i++) {
  426. values[i] = Quaternion.unpack(packedTypedArray, i * 4);
  427. }
  428. } else {
  429. const MathType = AttributeType.getMathType(accessorType);
  430. const numberOfComponents = AttributeType.getNumberOfComponents(
  431. accessorType
  432. );
  433. for (let i = 0; i < accessorCount; i++) {
  434. values[i] = MathType.unpack(packedTypedArray, i * numberOfComponents);
  435. }
  436. }
  437. return values;
  438. }
  439. function loadAccessor(loader, gltf, accessorId, useQuaternion) {
  440. const accessor = gltf.accessors[accessorId];
  441. const accessorCount = accessor.count;
  442. const values = new Array(accessorCount);
  443. const bufferViewId = accessor.bufferView;
  444. if (defined(bufferViewId)) {
  445. const bufferViewLoader = loadBufferView(loader, gltf, bufferViewId);
  446. bufferViewLoader.promise
  447. .then(function (bufferViewLoader) {
  448. if (loader.isDestroyed()) {
  449. return;
  450. }
  451. const bufferViewTypedArray = bufferViewLoader.typedArray;
  452. const packedTypedArray = getPackedTypedArray(
  453. gltf,
  454. accessor,
  455. bufferViewTypedArray
  456. );
  457. useQuaternion = defaultValue(useQuaternion, false);
  458. loadAccessorValues(accessor, packedTypedArray, values, useQuaternion);
  459. })
  460. .catch(function () {
  461. loadDefaultAccessorValues(accessor, values);
  462. });
  463. return values;
  464. }
  465. return loadDefaultAccessorValues(accessor, values);
  466. }
  467. function fromArray(MathType, values) {
  468. if (!defined(values)) {
  469. return undefined;
  470. }
  471. if (MathType === Number) {
  472. return values[0];
  473. }
  474. return MathType.unpack(values);
  475. }
  476. function getDefault(MathType) {
  477. if (MathType === Number) {
  478. return 0.0;
  479. }
  480. return new MathType(); // defaults to 0.0 for all types
  481. }
  482. function createAttribute(gltf, accessorId, name, semantic, setIndex) {
  483. const accessor = gltf.accessors[accessorId];
  484. const MathType = AttributeType.getMathType(accessor.type);
  485. const attribute = new Attribute();
  486. attribute.name = name;
  487. attribute.semantic = semantic;
  488. attribute.setIndex = setIndex;
  489. attribute.constant = getDefault(MathType);
  490. attribute.componentDatatype = accessor.componentType;
  491. attribute.normalized = defaultValue(accessor.normalized, false);
  492. attribute.count = accessor.count;
  493. attribute.type = accessor.type;
  494. attribute.min = fromArray(MathType, accessor.min);
  495. attribute.max = fromArray(MathType, accessor.max);
  496. attribute.byteOffset = accessor.byteOffset;
  497. attribute.byteStride = getAccessorByteStride(gltf, accessor);
  498. return attribute;
  499. }
  500. function getSetIndex(gltfSemantic) {
  501. const setIndexRegex = /^\w+_(\d+)$/;
  502. const setIndexMatch = setIndexRegex.exec(gltfSemantic);
  503. if (setIndexMatch !== null) {
  504. return parseInt(setIndexMatch[1]);
  505. }
  506. return undefined;
  507. }
  508. function loadAttribute(
  509. loader,
  510. gltf,
  511. accessorId,
  512. semanticType,
  513. gltfSemantic,
  514. draco,
  515. dequantize,
  516. loadAsTypedArray,
  517. loadAsTypedArrayPacked
  518. ) {
  519. const accessor = gltf.accessors[accessorId];
  520. const bufferViewId = accessor.bufferView;
  521. // For .b3dm, rename _BATCHID (or the legacy BATCHID) to _FEATURE_ID_0
  522. // in the generated model components for compatibility with EXT_mesh_features
  523. let renamedSemantic = gltfSemantic;
  524. if (
  525. loader._renameBatchIdSemantic &&
  526. (gltfSemantic === "_BATCHID" || gltfSemantic === "BATCHID")
  527. ) {
  528. renamedSemantic = "_FEATURE_ID_0";
  529. }
  530. const name = gltfSemantic;
  531. const modelSemantic = semanticType.fromGltfSemantic(renamedSemantic);
  532. const setIndex = defined(modelSemantic)
  533. ? getSetIndex(renamedSemantic)
  534. : undefined;
  535. const attribute = createAttribute(
  536. gltf,
  537. accessorId,
  538. name,
  539. modelSemantic,
  540. setIndex
  541. );
  542. if (!defined(draco) && !defined(bufferViewId)) {
  543. return attribute;
  544. }
  545. const vertexBufferLoader = loadVertexBuffer(
  546. loader,
  547. gltf,
  548. accessorId,
  549. gltfSemantic,
  550. draco,
  551. dequantize,
  552. loadAsTypedArray
  553. );
  554. vertexBufferLoader.promise.then(function (vertexBufferLoader) {
  555. if (loader.isDestroyed()) {
  556. return;
  557. }
  558. if (loadAsTypedArrayPacked) {
  559. // The accessor's byteOffset and byteStride should be ignored since values
  560. // are tightly packed in a typed array
  561. const bufferViewTypedArray = vertexBufferLoader.typedArray;
  562. attribute.packedTypedArray = getPackedTypedArray(
  563. gltf,
  564. accessor,
  565. bufferViewTypedArray
  566. );
  567. attribute.byteOffset = 0;
  568. attribute.byteStride = undefined;
  569. } else if (loadAsTypedArray) {
  570. attribute.typedArray = vertexBufferLoader.typedArray;
  571. } else {
  572. attribute.buffer = vertexBufferLoader.buffer;
  573. }
  574. attribute.count = accessor.count;
  575. if (
  576. defined(draco) &&
  577. defined(draco.attributes) &&
  578. defined(draco.attributes[gltfSemantic])
  579. ) {
  580. // The accessor's byteOffset and byteStride should be ignored for draco.
  581. // Each attribute is tightly packed in its own buffer after decode.
  582. attribute.byteOffset = 0;
  583. attribute.byteStride = undefined;
  584. attribute.quantization = vertexBufferLoader.quantization;
  585. }
  586. });
  587. return attribute;
  588. }
  589. function loadVertexAttribute(loader, gltf, accessorId, gltfSemantic, draco) {
  590. return loadAttribute(
  591. loader,
  592. gltf,
  593. accessorId,
  594. VertexAttributeSemantic,
  595. gltfSemantic,
  596. draco,
  597. false,
  598. loader._loadAsTypedArray,
  599. false
  600. );
  601. }
  602. function loadInstancedAttribute(
  603. loader,
  604. gltf,
  605. accessorId,
  606. gltfSemantic,
  607. loadAsTypedArrayPacked
  608. ) {
  609. // Don't pass in draco object since instanced attributes can't be draco compressed
  610. return loadAttribute(
  611. loader,
  612. gltf,
  613. accessorId,
  614. InstanceAttributeSemantic,
  615. gltfSemantic,
  616. undefined,
  617. true,
  618. loadAsTypedArrayPacked,
  619. loadAsTypedArrayPacked
  620. );
  621. }
  622. function loadIndices(loader, gltf, accessorId, draco) {
  623. const accessor = gltf.accessors[accessorId];
  624. const bufferViewId = accessor.bufferView;
  625. if (!defined(draco) && !defined(bufferViewId)) {
  626. return undefined;
  627. }
  628. const indices = new Indices();
  629. indices.count = accessor.count;
  630. const loadAsTypedArray = loader._loadAsTypedArray;
  631. const indexBufferLoader = loadIndexBuffer(
  632. loader,
  633. gltf,
  634. accessorId,
  635. draco,
  636. loadAsTypedArray
  637. );
  638. indexBufferLoader.promise.then(function (indexBufferLoader) {
  639. if (loader.isDestroyed()) {
  640. return;
  641. }
  642. indices.indexDatatype = indexBufferLoader.indexDatatype;
  643. if (defined(indexBufferLoader.buffer)) {
  644. indices.buffer = indexBufferLoader.buffer;
  645. } else {
  646. indices.typedArray = indexBufferLoader.typedArray;
  647. }
  648. });
  649. return indices;
  650. }
  651. function loadTexture(
  652. loader,
  653. gltf,
  654. textureInfo,
  655. supportedImageFormats,
  656. samplerOverride
  657. ) {
  658. const imageId = GltfLoaderUtil.getImageIdFromTexture({
  659. gltf: gltf,
  660. textureId: textureInfo.index,
  661. supportedImageFormats: supportedImageFormats,
  662. });
  663. if (!defined(imageId)) {
  664. return undefined;
  665. }
  666. const textureLoader = ResourceCache.loadTexture({
  667. gltf: gltf,
  668. textureInfo: textureInfo,
  669. gltfResource: loader._gltfResource,
  670. baseResource: loader._baseResource,
  671. supportedImageFormats: supportedImageFormats,
  672. asynchronous: loader._asynchronous,
  673. });
  674. loader._textureLoaders.push(textureLoader);
  675. const textureReader = GltfLoaderUtil.createModelTextureReader({
  676. textureInfo: textureInfo,
  677. });
  678. textureLoader.promise.then(function (textureLoader) {
  679. if (loader.isDestroyed()) {
  680. return;
  681. }
  682. textureReader.texture = textureLoader.texture;
  683. if (defined(samplerOverride)) {
  684. textureReader.texture.sampler = samplerOverride;
  685. }
  686. });
  687. return textureReader;
  688. }
  689. function loadMaterial(loader, gltf, gltfMaterial, supportedImageFormats) {
  690. const material = new Material();
  691. const extensions = defaultValue(
  692. gltfMaterial.extensions,
  693. defaultValue.EMPTY_OBJECT
  694. );
  695. const pbrSpecularGlossiness = extensions.KHR_materials_pbrSpecularGlossiness;
  696. const pbrMetallicRoughness = gltfMaterial.pbrMetallicRoughness;
  697. material.unlit = defined(extensions.KHR_materials_unlit);
  698. if (defined(pbrSpecularGlossiness)) {
  699. const specularGlossiness = new SpecularGlossiness();
  700. material.specularGlossiness = specularGlossiness;
  701. if (defined(pbrSpecularGlossiness.diffuseTexture)) {
  702. specularGlossiness.diffuseTexture = loadTexture(
  703. loader,
  704. gltf,
  705. pbrSpecularGlossiness.diffuseTexture,
  706. supportedImageFormats
  707. );
  708. }
  709. if (defined(pbrSpecularGlossiness.specularGlossinessTexture)) {
  710. if (defined(pbrSpecularGlossiness.specularGlossinessTexture)) {
  711. specularGlossiness.specularGlossinessTexture = loadTexture(
  712. loader,
  713. gltf,
  714. pbrSpecularGlossiness.specularGlossinessTexture,
  715. supportedImageFormats
  716. );
  717. }
  718. }
  719. specularGlossiness.diffuseFactor = fromArray(
  720. Cartesian4,
  721. pbrSpecularGlossiness.diffuseFactor
  722. );
  723. specularGlossiness.specularFactor = fromArray(
  724. Cartesian3,
  725. pbrSpecularGlossiness.specularFactor
  726. );
  727. specularGlossiness.glossinessFactor =
  728. pbrSpecularGlossiness.glossinessFactor;
  729. material.pbrSpecularGlossiness = pbrSpecularGlossiness;
  730. } else if (defined(pbrMetallicRoughness)) {
  731. const metallicRoughness = new MetallicRoughness();
  732. material.metallicRoughness = metallicRoughness;
  733. if (defined(pbrMetallicRoughness.baseColorTexture)) {
  734. metallicRoughness.baseColorTexture = loadTexture(
  735. loader,
  736. gltf,
  737. pbrMetallicRoughness.baseColorTexture,
  738. supportedImageFormats
  739. );
  740. }
  741. if (defined(pbrMetallicRoughness.metallicRoughnessTexture)) {
  742. metallicRoughness.metallicRoughnessTexture = loadTexture(
  743. loader,
  744. gltf,
  745. pbrMetallicRoughness.metallicRoughnessTexture,
  746. supportedImageFormats
  747. );
  748. }
  749. metallicRoughness.baseColorFactor = fromArray(
  750. Cartesian4,
  751. pbrMetallicRoughness.baseColorFactor
  752. );
  753. metallicRoughness.metallicFactor = pbrMetallicRoughness.metallicFactor;
  754. metallicRoughness.roughnessFactor = pbrMetallicRoughness.roughnessFactor;
  755. material.pbrMetallicRoughness = pbrMetallicRoughness;
  756. }
  757. // Top level textures
  758. if (defined(gltfMaterial.emissiveTexture)) {
  759. material.emissiveTexture = loadTexture(
  760. loader,
  761. gltf,
  762. gltfMaterial.emissiveTexture,
  763. supportedImageFormats
  764. );
  765. }
  766. if (defined(gltfMaterial.normalTexture)) {
  767. material.normalTexture = loadTexture(
  768. loader,
  769. gltf,
  770. gltfMaterial.normalTexture,
  771. supportedImageFormats
  772. );
  773. }
  774. if (defined(gltfMaterial.occlusionTexture)) {
  775. material.occlusionTexture = loadTexture(
  776. loader,
  777. gltf,
  778. gltfMaterial.occlusionTexture,
  779. supportedImageFormats
  780. );
  781. }
  782. material.emissiveFactor = fromArray(Cartesian3, gltfMaterial.emissiveFactor);
  783. material.alphaMode = gltfMaterial.alphaMode;
  784. material.alphaCutoff = gltfMaterial.alphaCutoff;
  785. material.doubleSided = gltfMaterial.doubleSided;
  786. return material;
  787. }
  788. // for EXT_mesh_features
  789. function loadFeatureIdAttribute(featureIds, positionalLabel) {
  790. const featureIdAttribute = new FeatureIdAttribute();
  791. featureIdAttribute.featureCount = featureIds.featureCount;
  792. featureIdAttribute.nullFeatureId = featureIds.nullFeatureId;
  793. featureIdAttribute.propertyTableId = featureIds.propertyTable;
  794. featureIdAttribute.setIndex = featureIds.attribute;
  795. featureIdAttribute.label = featureIds.label;
  796. featureIdAttribute.positionalLabel = positionalLabel;
  797. return featureIdAttribute;
  798. }
  799. // for backwards compatibility with EXT_feature_metadata
  800. function loadFeatureIdAttributeLegacy(
  801. gltfFeatureIdAttribute,
  802. featureTableId,
  803. featureCount,
  804. positionalLabel
  805. ) {
  806. const featureIdAttribute = new FeatureIdAttribute();
  807. const featureIds = gltfFeatureIdAttribute.featureIds;
  808. featureIdAttribute.featureCount = featureCount;
  809. featureIdAttribute.propertyTableId = featureTableId;
  810. featureIdAttribute.setIndex = getSetIndex(featureIds.attribute);
  811. featureIdAttribute.positionalLabel = positionalLabel;
  812. return featureIdAttribute;
  813. }
  814. // implicit ranges do not exist in EXT_mesh_features and EXT_instance_features,
  815. // but both default to the vertex/instance ID which is like
  816. // an implicit range of {offset: 0, repeat: 1}
  817. function loadDefaultFeatureIds(featureIds, positionalLabel) {
  818. const featureIdRange = new FeatureIdImplicitRange();
  819. featureIdRange.propertyTableId = featureIds.propertyTable;
  820. featureIdRange.featureCount = featureIds.featureCount;
  821. featureIdRange.nullFeatureId = featureIds.nullFeatureId;
  822. featureIdRange.label = featureIds.label;
  823. featureIdRange.positionalLabel = positionalLabel;
  824. featureIdRange.offset = 0;
  825. featureIdRange.repeat = 1;
  826. return featureIdRange;
  827. }
  828. // for backwards compatibility with EXT_feature_metadata
  829. function loadFeatureIdImplicitRangeLegacy(
  830. gltfFeatureIdAttribute,
  831. featureTableId,
  832. featureCount,
  833. positionalLabel
  834. ) {
  835. const featureIdRange = new FeatureIdImplicitRange();
  836. const featureIds = gltfFeatureIdAttribute.featureIds;
  837. featureIdRange.propertyTableId = featureTableId;
  838. featureIdRange.featureCount = featureCount;
  839. // constant/divisor was renamed to offset/repeat
  840. featureIdRange.offset = defaultValue(featureIds.constant, 0);
  841. // The default is now undefined
  842. const divisor = defaultValue(featureIds.divisor, 0);
  843. featureIdRange.repeat = divisor === 0 ? undefined : divisor;
  844. featureIdRange.positionalLabel = positionalLabel;
  845. return featureIdRange;
  846. }
  847. // for EXT_mesh_features
  848. function loadFeatureIdTexture(
  849. loader,
  850. gltf,
  851. gltfFeatureIdTexture,
  852. supportedImageFormats,
  853. positionalLabel
  854. ) {
  855. const featureIdTexture = new FeatureIdTexture();
  856. featureIdTexture.featureCount = gltfFeatureIdTexture.featureCount;
  857. featureIdTexture.nullFeatureId = gltfFeatureIdTexture.nullFeatureId;
  858. featureIdTexture.propertyTableId = gltfFeatureIdTexture.propertyTable;
  859. featureIdTexture.label = gltfFeatureIdTexture.label;
  860. featureIdTexture.positionalLabel = positionalLabel;
  861. const textureInfo = gltfFeatureIdTexture.texture;
  862. featureIdTexture.textureReader = loadTexture(
  863. loader,
  864. gltf,
  865. textureInfo,
  866. supportedImageFormats,
  867. Sampler.NEAREST // Feature ID textures require nearest sampling
  868. );
  869. // Though the new channel index is more future-proof, this implementation
  870. // only supports RGBA textures. At least for now, the string representation
  871. // is more useful for generating shader code.
  872. const channelString = textureInfo.channels
  873. .map(function (channelIndex) {
  874. return "rgba".charAt(channelIndex);
  875. })
  876. .join("");
  877. featureIdTexture.textureReader.channels = channelString;
  878. return featureIdTexture;
  879. }
  880. // for backwards compatibility with EXT_feature_metadata
  881. function loadFeatureIdTextureLegacy(
  882. loader,
  883. gltf,
  884. gltfFeatureIdTexture,
  885. featureTableId,
  886. supportedImageFormats,
  887. featureCount,
  888. positionalLabel
  889. ) {
  890. const featureIdTexture = new FeatureIdTexture();
  891. const featureIds = gltfFeatureIdTexture.featureIds;
  892. const textureInfo = featureIds.texture;
  893. featureIdTexture.featureCount = featureCount;
  894. featureIdTexture.propertyTableId = featureTableId;
  895. featureIdTexture.textureReader = loadTexture(
  896. loader,
  897. gltf,
  898. textureInfo,
  899. supportedImageFormats,
  900. Sampler.NEAREST // Feature ID textures require nearest sampling
  901. );
  902. featureIdTexture.textureReader.channels = featureIds.channels;
  903. featureIdTexture.positionalLabel = positionalLabel;
  904. return featureIdTexture;
  905. }
  906. function loadMorphTarget(loader, gltf, target) {
  907. const morphTarget = new MorphTarget();
  908. for (const semantic in target) {
  909. if (target.hasOwnProperty(semantic)) {
  910. const accessorId = target[semantic];
  911. morphTarget.attributes.push(
  912. // Don't pass in draco object since morph targets can't be draco compressed
  913. loadVertexAttribute(loader, gltf, accessorId, semantic, undefined)
  914. );
  915. }
  916. }
  917. return morphTarget;
  918. }
  919. function loadPrimitive(loader, gltf, gltfPrimitive, supportedImageFormats) {
  920. const primitive = new Primitive();
  921. const materialId = gltfPrimitive.material;
  922. if (defined(materialId)) {
  923. primitive.material = loadMaterial(
  924. loader,
  925. gltf,
  926. gltf.materials[materialId],
  927. supportedImageFormats
  928. );
  929. }
  930. const extensions = defaultValue(
  931. gltfPrimitive.extensions,
  932. defaultValue.EMPTY_OBJECT
  933. );
  934. const draco = extensions.KHR_draco_mesh_compression;
  935. const attributes = gltfPrimitive.attributes;
  936. if (defined(attributes)) {
  937. for (const semantic in attributes) {
  938. if (attributes.hasOwnProperty(semantic)) {
  939. const accessorId = attributes[semantic];
  940. primitive.attributes.push(
  941. loadVertexAttribute(loader, gltf, accessorId, semantic, draco)
  942. );
  943. }
  944. }
  945. }
  946. const targets = gltfPrimitive.targets;
  947. if (defined(targets)) {
  948. const targetsLength = targets.length;
  949. for (let i = 0; i < targetsLength; ++i) {
  950. primitive.morphTargets.push(loadMorphTarget(loader, gltf, targets[i]));
  951. }
  952. }
  953. const indices = gltfPrimitive.indices;
  954. if (defined(indices)) {
  955. primitive.indices = loadIndices(loader, gltf, indices, draco);
  956. }
  957. // With the latest revision, feature IDs are defined in EXT_mesh_features
  958. // while EXT_structural_metadata is for defining property textures and
  959. // property mappings. In the legacy EXT_feature_metadata, these concepts
  960. // were all in one extension.
  961. const structuralMetadata = extensions.EXT_structural_metadata;
  962. const meshFeatures = extensions.EXT_mesh_features;
  963. const featureMetadataLegacy = extensions.EXT_feature_metadata;
  964. const hasFeatureMetadataLegacy = defined(featureMetadataLegacy);
  965. // Load feature Ids
  966. if (defined(meshFeatures)) {
  967. loadPrimitiveFeatures(
  968. loader,
  969. gltf,
  970. primitive,
  971. meshFeatures,
  972. supportedImageFormats
  973. );
  974. } else if (hasFeatureMetadataLegacy) {
  975. loadPrimitiveFeaturesLegacy(
  976. loader,
  977. gltf,
  978. primitive,
  979. featureMetadataLegacy,
  980. supportedImageFormats
  981. );
  982. }
  983. // Load structural metadata
  984. if (defined(structuralMetadata)) {
  985. loadPrimitiveMetadata(primitive, structuralMetadata);
  986. } else if (hasFeatureMetadataLegacy) {
  987. loadPrimitiveMetadataLegacy(loader, primitive, featureMetadataLegacy);
  988. }
  989. primitive.primitiveType = gltfPrimitive.mode;
  990. return primitive;
  991. }
  992. // For EXT_mesh_features
  993. function loadPrimitiveFeatures(
  994. loader,
  995. gltf,
  996. primitive,
  997. meshFeaturesExtension,
  998. supportedImageFormats
  999. ) {
  1000. let featureIdsArray;
  1001. if (
  1002. defined(meshFeaturesExtension) &&
  1003. defined(meshFeaturesExtension.featureIds)
  1004. ) {
  1005. featureIdsArray = meshFeaturesExtension.featureIds;
  1006. } else {
  1007. featureIdsArray = [];
  1008. }
  1009. for (let i = 0; i < featureIdsArray.length; i++) {
  1010. const featureIds = featureIdsArray[i];
  1011. const label = `featureId_${i}`;
  1012. let featureIdComponent;
  1013. if (defined(featureIds.texture)) {
  1014. featureIdComponent = loadFeatureIdTexture(
  1015. loader,
  1016. gltf,
  1017. featureIds,
  1018. supportedImageFormats,
  1019. label
  1020. );
  1021. } else if (defined(featureIds.attribute)) {
  1022. featureIdComponent = loadFeatureIdAttribute(featureIds, label);
  1023. } else {
  1024. // default to vertex ID, in other words an implicit range with
  1025. // offset: 0, repeat: 1
  1026. featureIdComponent = loadDefaultFeatureIds(featureIds, label);
  1027. }
  1028. primitive.featureIds.push(featureIdComponent);
  1029. }
  1030. }
  1031. // For EXT_feature_metadata
  1032. function loadPrimitiveFeaturesLegacy(
  1033. loader,
  1034. gltf,
  1035. primitive,
  1036. metadataExtension,
  1037. supportedImageFormats
  1038. ) {
  1039. // For looking up the featureCount for each set of feature IDs
  1040. const featureTables = gltf.extensions.EXT_feature_metadata.featureTables;
  1041. let nextFeatureIdIndex = 0;
  1042. // Feature ID Attributes
  1043. const featureIdAttributes = metadataExtension.featureIdAttributes;
  1044. if (defined(featureIdAttributes)) {
  1045. const featureIdAttributesLength = featureIdAttributes.length;
  1046. for (let i = 0; i < featureIdAttributesLength; ++i) {
  1047. const featureIdAttribute = featureIdAttributes[i];
  1048. const featureTableId = featureIdAttribute.featureTable;
  1049. const propertyTableId = loader._sortedPropertyTableIds.indexOf(
  1050. featureTableId
  1051. );
  1052. const featureCount = featureTables[featureTableId].count;
  1053. const label = `featureId_${nextFeatureIdIndex}`;
  1054. nextFeatureIdIndex++;
  1055. let featureIdComponent;
  1056. if (defined(featureIdAttribute.featureIds.attribute)) {
  1057. featureIdComponent = loadFeatureIdAttributeLegacy(
  1058. featureIdAttribute,
  1059. propertyTableId,
  1060. featureCount,
  1061. label
  1062. );
  1063. } else {
  1064. featureIdComponent = loadFeatureIdImplicitRangeLegacy(
  1065. featureIdAttribute,
  1066. propertyTableId,
  1067. featureCount,
  1068. label
  1069. );
  1070. }
  1071. primitive.featureIds.push(featureIdComponent);
  1072. }
  1073. }
  1074. // Feature ID Textures
  1075. const featureIdTextures = metadataExtension.featureIdTextures;
  1076. if (defined(featureIdTextures)) {
  1077. const featureIdTexturesLength = featureIdTextures.length;
  1078. for (let i = 0; i < featureIdTexturesLength; ++i) {
  1079. const featureIdTexture = featureIdTextures[i];
  1080. const featureTableId = featureIdTexture.featureTable;
  1081. const propertyTableId = loader._sortedPropertyTableIds.indexOf(
  1082. featureTableId
  1083. );
  1084. const featureCount = featureTables[featureTableId].count;
  1085. const featureIdLabel = `featureId_${nextFeatureIdIndex}`;
  1086. nextFeatureIdIndex++;
  1087. const featureIdComponent = loadFeatureIdTextureLegacy(
  1088. loader,
  1089. gltf,
  1090. featureIdTexture,
  1091. propertyTableId,
  1092. supportedImageFormats,
  1093. featureCount,
  1094. featureIdLabel
  1095. );
  1096. // Feature ID textures are added after feature ID attributes in the list
  1097. primitive.featureIds.push(featureIdComponent);
  1098. }
  1099. }
  1100. }
  1101. // For primitive-level EXT_structural_metadata
  1102. function loadPrimitiveMetadata(primitive, structuralMetadataExtension) {
  1103. if (!defined(structuralMetadataExtension)) {
  1104. return;
  1105. }
  1106. // Property Textures
  1107. if (defined(structuralMetadataExtension.propertyTextures)) {
  1108. primitive.propertyTextureIds = structuralMetadataExtension.propertyTextures;
  1109. }
  1110. // Property Attributes
  1111. if (defined(structuralMetadataExtension.propertyAttributes)) {
  1112. primitive.propertyAttributeIds =
  1113. structuralMetadataExtension.propertyAttributes;
  1114. }
  1115. }
  1116. // For EXT_feature_metadata
  1117. function loadPrimitiveMetadataLegacy(loader, primitive, metadataExtension) {
  1118. // Feature Textures
  1119. if (defined(metadataExtension.featureTextures)) {
  1120. // feature textures are now identified by an integer index. To convert the
  1121. // string IDs to integers, find their place in the sorted list of feature
  1122. // table names
  1123. primitive.propertyTextureIds = metadataExtension.featureTextures.map(
  1124. function (id) {
  1125. return loader._sortedFeatureTextureIds.indexOf(id);
  1126. }
  1127. );
  1128. }
  1129. }
  1130. function loadInstances(loader, gltf, nodeExtensions, frameState) {
  1131. const instancingExtension = nodeExtensions.EXT_mesh_gpu_instancing;
  1132. const instances = new Instances();
  1133. const attributes = instancingExtension.attributes;
  1134. if (defined(attributes)) {
  1135. const hasRotation = defined(attributes.ROTATION);
  1136. const hasTranslationMinMax =
  1137. defined(attributes.TRANSLATION) &&
  1138. defined(gltf.accessors[attributes.TRANSLATION].min) &&
  1139. defined(gltf.accessors[attributes.TRANSLATION].max);
  1140. for (const semantic in attributes) {
  1141. if (attributes.hasOwnProperty(semantic)) {
  1142. // If the instances have rotations load the attributes as typed arrays
  1143. // so that instance matrices are computed on the CPU. This avoids the
  1144. // expensive quaternion -> rotation matrix conversion in the shader.
  1145. // If the translation accessor does not have a min and max, load the
  1146. // attributes as typed arrays, so the values can be used for computing
  1147. // an accurate bounding volume. Feature ID attributes are also loaded as
  1148. // typed arrays because we want to be able to add the instance's feature ID to
  1149. // the pick object. Load as typed arrays if GPU instancing is not supported.
  1150. const loadAsTypedArrayPacked =
  1151. loader._loadAsTypedArray ||
  1152. !frameState.context.instancedArrays ||
  1153. ((hasRotation || !hasTranslationMinMax) &&
  1154. (semantic === InstanceAttributeSemantic.TRANSLATION ||
  1155. semantic === InstanceAttributeSemantic.ROTATION ||
  1156. semantic === InstanceAttributeSemantic.SCALE)) ||
  1157. semantic.indexOf(InstanceAttributeSemantic.FEATURE_ID) >= 0;
  1158. const accessorId = attributes[semantic];
  1159. instances.attributes.push(
  1160. loadInstancedAttribute(
  1161. loader,
  1162. gltf,
  1163. accessorId,
  1164. semantic,
  1165. loadAsTypedArrayPacked
  1166. )
  1167. );
  1168. }
  1169. }
  1170. }
  1171. const instancingExtExtensions = defaultValue(
  1172. instancingExtension.extensions,
  1173. defaultValue.EMPTY_OBJECT
  1174. );
  1175. const instanceFeatures = nodeExtensions.EXT_instance_features;
  1176. const featureMetadataLegacy = instancingExtExtensions.EXT_feature_metadata;
  1177. if (defined(instanceFeatures)) {
  1178. loadInstanceFeatures(instances, instanceFeatures);
  1179. } else if (defined(featureMetadataLegacy)) {
  1180. loadInstanceFeaturesLegacy(
  1181. gltf,
  1182. instances,
  1183. featureMetadataLegacy,
  1184. loader._sortedPropertyTableIds
  1185. );
  1186. }
  1187. return instances;
  1188. }
  1189. // For EXT_mesh_features
  1190. function loadInstanceFeatures(instances, instanceFeaturesExtension) {
  1191. // feature IDs are required in EXT_instance_features
  1192. const featureIdsArray = instanceFeaturesExtension.featureIds;
  1193. for (let i = 0; i < featureIdsArray.length; i++) {
  1194. const featureIds = featureIdsArray[i];
  1195. const label = `instanceFeatureId_${i}`;
  1196. let featureIdComponent;
  1197. if (defined(featureIds.attribute)) {
  1198. featureIdComponent = loadFeatureIdAttribute(featureIds, label);
  1199. } else {
  1200. // in EXT_instance_features, the default is to assign IDs by instance
  1201. // ID. This can be expressed with offset: 0, repeat: 1
  1202. featureIdComponent = loadDefaultFeatureIds(featureIds, label);
  1203. }
  1204. instances.featureIds.push(featureIdComponent);
  1205. }
  1206. }
  1207. // For backwards-compatibility with EXT_feature_metadata
  1208. function loadInstanceFeaturesLegacy(
  1209. gltf,
  1210. instances,
  1211. metadataExtension,
  1212. sortedPropertyTableIds
  1213. ) {
  1214. // For looking up the featureCount for each set of feature IDs
  1215. const featureTables = gltf.extensions.EXT_feature_metadata.featureTables;
  1216. const featureIdAttributes = metadataExtension.featureIdAttributes;
  1217. if (defined(featureIdAttributes)) {
  1218. const featureIdAttributesLength = featureIdAttributes.length;
  1219. for (let i = 0; i < featureIdAttributesLength; ++i) {
  1220. const featureIdAttribute = featureIdAttributes[i];
  1221. const featureTableId = featureIdAttribute.featureTable;
  1222. const propertyTableId = sortedPropertyTableIds.indexOf(featureTableId);
  1223. const featureCount = featureTables[featureTableId].count;
  1224. const label = `instanceFeatureId_${i}`;
  1225. let featureIdComponent;
  1226. if (defined(featureIdAttribute.featureIds.attribute)) {
  1227. featureIdComponent = loadFeatureIdAttributeLegacy(
  1228. featureIdAttribute,
  1229. propertyTableId,
  1230. featureCount,
  1231. label
  1232. );
  1233. } else {
  1234. featureIdComponent = loadFeatureIdImplicitRangeLegacy(
  1235. featureIdAttribute,
  1236. propertyTableId,
  1237. featureCount,
  1238. label
  1239. );
  1240. }
  1241. instances.featureIds.push(featureIdComponent);
  1242. }
  1243. }
  1244. }
  1245. function loadNode(loader, gltf, gltfNode, supportedImageFormats, frameState) {
  1246. const node = new Node();
  1247. node.name = gltfNode.name;
  1248. node.matrix = fromArray(Matrix4, gltfNode.matrix);
  1249. node.translation = fromArray(Cartesian3, gltfNode.translation);
  1250. node.rotation = fromArray(Quaternion, gltfNode.rotation);
  1251. node.scale = fromArray(Cartesian3, gltfNode.scale);
  1252. const meshId = gltfNode.mesh;
  1253. if (defined(meshId)) {
  1254. const mesh = gltf.meshes[meshId];
  1255. const primitives = mesh.primitives;
  1256. const primitivesLength = primitives.length;
  1257. for (let i = 0; i < primitivesLength; ++i) {
  1258. node.primitives.push(
  1259. loadPrimitive(loader, gltf, primitives[i], supportedImageFormats)
  1260. );
  1261. }
  1262. // If the node has no weights array, it will look for the weights array provided
  1263. // by the mesh. If both are undefined, it will default to an array of zero weights.
  1264. const morphWeights = defaultValue(gltfNode.weights, mesh.weights);
  1265. const targets = node.primitives[0].morphTargets;
  1266. const targetsLength = targets.length;
  1267. // Since meshes are not stored as separate components, the mesh weights will still
  1268. // be stored at the node level.
  1269. node.morphWeights = defined(morphWeights)
  1270. ? morphWeights.slice()
  1271. : arrayFill(new Array(targetsLength), 0.0);
  1272. }
  1273. const nodeExtensions = defaultValue(
  1274. gltfNode.extensions,
  1275. defaultValue.EMPTY_OBJECT
  1276. );
  1277. const instancingExtension = nodeExtensions.EXT_mesh_gpu_instancing;
  1278. if (defined(instancingExtension)) {
  1279. node.instances = loadInstances(loader, gltf, nodeExtensions, frameState);
  1280. }
  1281. return node;
  1282. }
  1283. function loadNodes(loader, gltf, supportedImageFormats, frameState) {
  1284. let i;
  1285. let j;
  1286. const nodesLength = gltf.nodes.length;
  1287. const nodes = new Array(nodesLength);
  1288. for (i = 0; i < nodesLength; ++i) {
  1289. const node = loadNode(
  1290. loader,
  1291. gltf,
  1292. gltf.nodes[i],
  1293. supportedImageFormats,
  1294. frameState
  1295. );
  1296. node.index = i;
  1297. nodes[i] = node;
  1298. }
  1299. for (i = 0; i < nodesLength; ++i) {
  1300. const childrenNodeIds = gltf.nodes[i].children;
  1301. if (defined(childrenNodeIds)) {
  1302. const childrenLength = childrenNodeIds.length;
  1303. for (j = 0; j < childrenLength; ++j) {
  1304. nodes[i].children.push(nodes[childrenNodeIds[j]]);
  1305. }
  1306. }
  1307. }
  1308. return nodes;
  1309. }
  1310. function loadSkin(loader, gltf, gltfSkin, nodes) {
  1311. const skin = new Skin();
  1312. const jointIds = gltfSkin.joints;
  1313. const jointsLength = jointIds.length;
  1314. const joints = new Array(jointsLength);
  1315. for (let i = 0; i < jointsLength; ++i) {
  1316. joints[i] = nodes[jointIds[i]];
  1317. }
  1318. skin.joints = joints;
  1319. const inverseBindMatricesAccessorId = gltfSkin.inverseBindMatrices;
  1320. if (defined(inverseBindMatricesAccessorId)) {
  1321. skin.inverseBindMatrices = loadAccessor(
  1322. loader,
  1323. gltf,
  1324. inverseBindMatricesAccessorId
  1325. );
  1326. } else {
  1327. skin.inverseBindMatrices = arrayFill(
  1328. new Array(jointsLength),
  1329. Matrix4.IDENTITY
  1330. );
  1331. }
  1332. return skin;
  1333. }
  1334. function loadSkins(loader, gltf, nodes) {
  1335. let i;
  1336. const gltfSkins = gltf.skins;
  1337. if (!defined(gltfSkins)) {
  1338. return [];
  1339. }
  1340. const skinsLength = gltf.skins.length;
  1341. const skins = new Array(skinsLength);
  1342. for (i = 0; i < skinsLength; ++i) {
  1343. const skin = loadSkin(loader, gltf, gltf.skins[i], nodes);
  1344. skin.index = i;
  1345. skins[i] = skin;
  1346. }
  1347. const nodesLength = nodes.length;
  1348. for (i = 0; i < nodesLength; ++i) {
  1349. const skinId = gltf.nodes[i].skin;
  1350. if (defined(skinId)) {
  1351. nodes[i].skin = skins[skinId];
  1352. }
  1353. }
  1354. return skins;
  1355. }
  1356. function loadStructuralMetadata(
  1357. loader,
  1358. gltf,
  1359. extension,
  1360. extensionLegacy,
  1361. supportedImageFormats
  1362. ) {
  1363. const structuralMetadataLoader = new GltfStructuralMetadataLoader({
  1364. gltf: gltf,
  1365. extension: extension,
  1366. extensionLegacy: extensionLegacy,
  1367. gltfResource: loader._gltfResource,
  1368. baseResource: loader._baseResource,
  1369. supportedImageFormats: supportedImageFormats,
  1370. asynchronous: loader._asynchronous,
  1371. });
  1372. structuralMetadataLoader.load();
  1373. loader._structuralMetadataLoader = structuralMetadataLoader;
  1374. return structuralMetadataLoader;
  1375. }
  1376. function loadAnimationSampler(loader, gltf, gltfSampler) {
  1377. const animationSampler = new AnimationSampler();
  1378. const inputAccessorId = gltfSampler.input;
  1379. animationSampler.input = loadAccessor(loader, gltf, inputAccessorId);
  1380. const gltfInterpolation = gltfSampler.interpolation;
  1381. animationSampler.interpolation = defaultValue(
  1382. InterpolationType[gltfInterpolation],
  1383. InterpolationType.LINEAR
  1384. );
  1385. const outputAccessorId = gltfSampler.output;
  1386. animationSampler.output = loadAccessor(loader, gltf, outputAccessorId, true);
  1387. return animationSampler;
  1388. }
  1389. function loadAnimationTarget(gltfTarget, nodes) {
  1390. const animationTarget = new AnimationTarget();
  1391. const nodeIndex = gltfTarget.node;
  1392. // If the node isn't defined, the animation channel should be ignored.
  1393. // It's easiest to signal this by returning undefined.
  1394. if (!defined(nodeIndex)) {
  1395. return undefined;
  1396. }
  1397. animationTarget.node = nodes[nodeIndex];
  1398. const path = gltfTarget.path.toUpperCase();
  1399. animationTarget.path = AnimatedPropertyType[path];
  1400. return animationTarget;
  1401. }
  1402. function loadAnimationChannel(gltfChannel, samplers, nodes) {
  1403. const animationChannel = new AnimationChannel();
  1404. const samplerIndex = gltfChannel.sampler;
  1405. animationChannel.sampler = samplers[samplerIndex];
  1406. animationChannel.target = loadAnimationTarget(gltfChannel.target, nodes);
  1407. return animationChannel;
  1408. }
  1409. function loadAnimation(loader, gltf, gltfAnimation, nodes) {
  1410. let i;
  1411. const animation = new Animation();
  1412. animation.name = gltfAnimation.name;
  1413. const gltfSamplers = gltfAnimation.samplers;
  1414. const samplersLength = gltfSamplers.length;
  1415. const samplers = new Array(samplersLength);
  1416. for (i = 0; i < samplersLength; i++) {
  1417. const sampler = loadAnimationSampler(loader, gltf, gltfSamplers[i]);
  1418. sampler.index = i;
  1419. samplers[i] = sampler;
  1420. }
  1421. const gltfChannels = gltfAnimation.channels;
  1422. const channelsLength = gltfChannels.length;
  1423. const channels = new Array(channelsLength);
  1424. for (i = 0; i < channelsLength; i++) {
  1425. channels[i] = loadAnimationChannel(gltfChannels[i], samplers, nodes);
  1426. }
  1427. animation.samplers = samplers;
  1428. animation.channels = channels;
  1429. return animation;
  1430. }
  1431. function loadAnimations(loader, gltf, nodes) {
  1432. let i;
  1433. const gltfAnimations = gltf.animations;
  1434. if (!defined(gltfAnimations)) {
  1435. return [];
  1436. }
  1437. const animationsLength = gltf.animations.length;
  1438. const animations = new Array(animationsLength);
  1439. for (i = 0; i < animationsLength; ++i) {
  1440. const animation = loadAnimation(loader, gltf, gltf.animations[i], nodes);
  1441. animation.index = i;
  1442. animations[i] = animation;
  1443. }
  1444. return animations;
  1445. }
  1446. function getSceneNodeIds(gltf) {
  1447. let nodesIds;
  1448. if (defined(gltf.scenes) && defined(gltf.scene)) {
  1449. nodesIds = gltf.scenes[gltf.scene].nodes;
  1450. }
  1451. nodesIds = defaultValue(nodesIds, gltf.nodes);
  1452. nodesIds = defined(nodesIds) ? nodesIds : [];
  1453. return nodesIds;
  1454. }
  1455. function loadScene(gltf, nodes) {
  1456. const scene = new Scene();
  1457. const sceneNodeIds = getSceneNodeIds(gltf);
  1458. scene.nodes = sceneNodeIds.map(function (sceneNodeId) {
  1459. return nodes[sceneNodeId];
  1460. });
  1461. return scene;
  1462. }
  1463. function parse(loader, gltf, supportedImageFormats, frameState) {
  1464. const extensions = defaultValue(gltf.extensions, defaultValue.EMPTY_OBJECT);
  1465. const structuralMetadataExtension = extensions.EXT_structural_metadata;
  1466. const featureMetadataExtensionLegacy = extensions.EXT_feature_metadata;
  1467. if (defined(featureMetadataExtensionLegacy)) {
  1468. // If the old EXT_feature_metadata extension is present, sort the IDs of the
  1469. // feature tables and feature textures so we don't have to do this once
  1470. // per primitive.
  1471. //
  1472. // This must run before loadNodes so these IDs are available when
  1473. // attributes are processed.
  1474. const featureTables = featureMetadataExtensionLegacy.featureTables;
  1475. const featureTextures = featureMetadataExtensionLegacy.featureTextures;
  1476. const allPropertyTableIds = defined(featureTables) ? featureTables : [];
  1477. const allFeatureTextureIds = defined(featureTextures)
  1478. ? featureTextures
  1479. : [];
  1480. loader._sortedPropertyTableIds = Object.keys(allPropertyTableIds).sort();
  1481. loader._sortedFeatureTextureIds = Object.keys(allFeatureTextureIds).sort();
  1482. }
  1483. const nodes = loadNodes(loader, gltf, supportedImageFormats, frameState);
  1484. const skins = loadSkins(loader, gltf, nodes);
  1485. const animations = loadAnimations(loader, gltf, nodes);
  1486. const scene = loadScene(gltf, nodes);
  1487. const components = new Components();
  1488. const asset = new Asset();
  1489. const copyright = gltf.asset.copyright;
  1490. if (defined(copyright)) {
  1491. const credits = copyright.split(";").map(function (string) {
  1492. return new Credit(string.trim());
  1493. });
  1494. asset.credits = credits;
  1495. }
  1496. components.asset = asset;
  1497. components.scene = scene;
  1498. components.nodes = nodes;
  1499. components.skins = skins;
  1500. components.animations = animations;
  1501. components.upAxis = loader._upAxis;
  1502. components.forwardAxis = loader._forwardAxis;
  1503. loader._components = components;
  1504. // Load structural metadata (property tables and property textures)
  1505. if (
  1506. defined(structuralMetadataExtension) ||
  1507. defined(featureMetadataExtensionLegacy)
  1508. ) {
  1509. const structuralMetadataLoader = loadStructuralMetadata(
  1510. loader,
  1511. gltf,
  1512. structuralMetadataExtension,
  1513. featureMetadataExtensionLegacy,
  1514. supportedImageFormats
  1515. );
  1516. structuralMetadataLoader.promise.then(function (structuralMetadataLoader) {
  1517. if (loader.isDestroyed()) {
  1518. return;
  1519. }
  1520. components.structuralMetadata =
  1521. structuralMetadataLoader.structuralMetadata;
  1522. });
  1523. }
  1524. // Gather promises and reject if any promises fail.
  1525. const loaders = [];
  1526. loaders.push.apply(loaders, loader._bufferViewLoaders);
  1527. loaders.push.apply(loaders, loader._geometryLoaders);
  1528. if (defined(loader._structuralMetadataLoader)) {
  1529. loaders.push(loader._structuralMetadataLoader);
  1530. }
  1531. if (!loader._incrementallyLoadTextures) {
  1532. loaders.push.apply(loaders, loader._textureLoaders);
  1533. }
  1534. const readyPromises = loaders.map(function (loader) {
  1535. return loader.promise;
  1536. });
  1537. // Separate promise will resolve once textures are loaded.
  1538. const texturePromises = loader._textureLoaders.map(function (loader) {
  1539. return loader.promise;
  1540. });
  1541. Promise.all(readyPromises)
  1542. .then(function () {
  1543. if (loader.isDestroyed()) {
  1544. return;
  1545. }
  1546. loader._state = GltfLoaderState.PROCESSED;
  1547. })
  1548. .catch(function (error) {
  1549. if (loader.isDestroyed()) {
  1550. return;
  1551. }
  1552. handleError(loader, error);
  1553. });
  1554. Promise.all(texturePromises).then(function () {
  1555. if (loader.isDestroyed()) {
  1556. return;
  1557. }
  1558. loader._textureState = GltfLoaderState.PROCESSED;
  1559. });
  1560. }
  1561. function unloadTextures(loader) {
  1562. const textureLoaders = loader._textureLoaders;
  1563. const textureLoadersLength = textureLoaders.length;
  1564. for (let i = 0; i < textureLoadersLength; ++i) {
  1565. ResourceCache.unload(textureLoaders[i]);
  1566. }
  1567. loader._textureLoaders.length = 0;
  1568. }
  1569. function unloadBufferViews(loader) {
  1570. const bufferViewLoaders = loader._bufferViewLoaders;
  1571. const bufferViewLoadersLength = bufferViewLoaders.length;
  1572. for (let i = 0; i < bufferViewLoadersLength; ++i) {
  1573. ResourceCache.unload(bufferViewLoaders[i]);
  1574. }
  1575. loader._bufferViewLoaders.length = 0;
  1576. }
  1577. function unloadGeometry(loader) {
  1578. const geometryLoaders = loader._geometryLoaders;
  1579. const geometryLoadersLength = geometryLoaders.length;
  1580. for (let i = 0; i < geometryLoadersLength; ++i) {
  1581. ResourceCache.unload(geometryLoaders[i]);
  1582. }
  1583. loader._geometryLoaders.length = 0;
  1584. }
  1585. function unloadStructuralMetadata(loader) {
  1586. if (defined(loader._structuralMetadataLoader)) {
  1587. loader._structuralMetadataLoader.destroy();
  1588. loader._structuralMetadataLoader = undefined;
  1589. }
  1590. }
  1591. /**
  1592. * Unloads the resource.
  1593. * @private
  1594. */
  1595. GltfLoader.prototype.unload = function () {
  1596. if (defined(this._gltfJsonLoader)) {
  1597. ResourceCache.unload(this._gltfJsonLoader);
  1598. }
  1599. this._gltfJsonLoader = undefined;
  1600. unloadTextures(this);
  1601. unloadBufferViews(this);
  1602. unloadGeometry(this);
  1603. unloadStructuralMetadata(this);
  1604. this._components = undefined;
  1605. };