GltfLoader.js 80 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744
  1. import ArticulationStageType from "../Core/ArticulationStageType.js";
  2. import Cartesian2 from "../Core/Cartesian2.js";
  3. import Cartesian3 from "../Core/Cartesian3.js";
  4. import Cartesian4 from "../Core/Cartesian4.js";
  5. import Check from "../Core/Check.js";
  6. import ComponentDatatype from "../Core/ComponentDatatype.js";
  7. import Credit from "../Core/Credit.js";
  8. import defaultValue from "../Core/defaultValue.js";
  9. import defined from "../Core/defined.js";
  10. import FeatureDetection from "../Core/FeatureDetection.js";
  11. import InterpolationType from "../Core/InterpolationType.js";
  12. import Matrix4 from "../Core/Matrix4.js";
  13. import PrimitiveType from "../Core/PrimitiveType.js";
  14. import Quaternion from "../Core/Quaternion.js";
  15. import RuntimeError from "../Core/RuntimeError.js";
  16. import Sampler from "../Renderer/Sampler.js";
  17. import getAccessorByteStride from "./GltfPipeline/getAccessorByteStride.js";
  18. import getComponentReader from "./GltfPipeline/getComponentReader.js";
  19. import numberOfComponentsForType from "./GltfPipeline/numberOfComponentsForType.js";
  20. import GltfStructuralMetadataLoader from "./GltfStructuralMetadataLoader.js";
  21. import AttributeType from "./AttributeType.js";
  22. import Axis from "./Axis.js";
  23. import GltfLoaderUtil from "./GltfLoaderUtil.js";
  24. import hasExtension from "./hasExtension.js";
  25. import InstanceAttributeSemantic from "./InstanceAttributeSemantic.js";
  26. import ModelComponents from "./ModelComponents.js";
  27. import PrimitiveLoadPlan from "./PrimitiveLoadPlan.js";
  28. import ResourceCache from "./ResourceCache.js";
  29. import ResourceLoader from "./ResourceLoader.js";
  30. import SupportedImageFormats from "./SupportedImageFormats.js";
  31. import VertexAttributeSemantic from "./VertexAttributeSemantic.js";
  32. const Attribute = ModelComponents.Attribute;
  33. const Indices = ModelComponents.Indices;
  34. const FeatureIdAttribute = ModelComponents.FeatureIdAttribute;
  35. const FeatureIdTexture = ModelComponents.FeatureIdTexture;
  36. const FeatureIdImplicitRange = ModelComponents.FeatureIdImplicitRange;
  37. const MorphTarget = ModelComponents.MorphTarget;
  38. const Primitive = ModelComponents.Primitive;
  39. const Instances = ModelComponents.Instances;
  40. const Skin = ModelComponents.Skin;
  41. const Node = ModelComponents.Node;
  42. const AnimatedPropertyType = ModelComponents.AnimatedPropertyType;
  43. const AnimationSampler = ModelComponents.AnimationSampler;
  44. const AnimationTarget = ModelComponents.AnimationTarget;
  45. const AnimationChannel = ModelComponents.AnimationChannel;
  46. const Animation = ModelComponents.Animation;
  47. const ArticulationStage = ModelComponents.ArticulationStage;
  48. const Articulation = ModelComponents.Articulation;
  49. const Asset = ModelComponents.Asset;
  50. const Scene = ModelComponents.Scene;
  51. const Components = ModelComponents.Components;
  52. const MetallicRoughness = ModelComponents.MetallicRoughness;
  53. const SpecularGlossiness = ModelComponents.SpecularGlossiness;
  54. const Material = ModelComponents.Material;
  55. /**
  56. * States of the glTF loading process. These states also apply to
  57. * asynchronous texture loading unless otherwise noted
  58. *
  59. * @enum {number}
  60. *
  61. * @private
  62. */
  63. const GltfLoaderState = {
  64. /**
  65. * The initial state of the glTF loader before load() is called.
  66. *
  67. * @type {number}
  68. * @constant
  69. *
  70. * @private
  71. */
  72. NOT_LOADED: 0,
  73. /**
  74. * The state of the loader while waiting for the glTF JSON loader promise
  75. * to resolve.
  76. *
  77. * @type {number}
  78. * @constant
  79. *
  80. * @private
  81. */
  82. LOADING: 1,
  83. /**
  84. * The state of the loader once the glTF JSON is loaded but before
  85. * process() is called.
  86. *
  87. * @type {number}
  88. * @constant
  89. *
  90. * @private
  91. */
  92. LOADED: 2,
  93. /**
  94. * The state of the loader while parsing the glTF and creating GPU resources
  95. * as needed.
  96. *
  97. * @type {number}
  98. * @constant
  99. *
  100. * @private
  101. */
  102. PROCESSING: 3,
  103. /**
  104. * For some features like handling CESIUM_primitive_outlines, the geometry
  105. * must be modified after it is loaded. The post-processing state handles
  106. * any geometry modification (if needed).
  107. * <p>
  108. * This state is not used for asynchronous texture loading.
  109. * </p>
  110. *
  111. * @type {number}
  112. * @constant
  113. *
  114. * @private
  115. */
  116. POST_PROCESSING: 4,
  117. /**
  118. * Once the processing/post-processing states are finished, the loader
  119. * enters the processed state (sometimes from a promise chain). The next
  120. * call to process() will advance to the ready state.
  121. *
  122. * @type {number}
  123. * @constant
  124. *
  125. * @private
  126. */
  127. PROCESSED: 5,
  128. /**
  129. * When the loader reaches the ready state, the loaders' promise will be
  130. * resolved.
  131. *
  132. * @type {number}
  133. * @constant
  134. *
  135. * @private
  136. */
  137. READY: 6,
  138. /**
  139. * If an error occurs at any point, the loader switches to the failed state.
  140. *
  141. * @type {number}
  142. * @constant
  143. *
  144. * @private
  145. */
  146. FAILED: 7,
  147. /**
  148. * If unload() is called, the loader switches to the unloaded state.
  149. *
  150. * @type {number}
  151. * @constant
  152. *
  153. * @private
  154. */
  155. UNLOADED: 8,
  156. };
  157. /**
  158. * Loads a glTF model.
  159. * <p>
  160. * Implements the {@link ResourceLoader} interface.
  161. * </p>
  162. *
  163. * @alias GltfLoader
  164. * @constructor
  165. * @augments ResourceLoader
  166. *
  167. * @param {object} options Object with the following properties:
  168. * @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.
  169. * @param {Resource} [options.baseResource] The {@link Resource} that paths in the glTF JSON are relative to.
  170. * @param {Uint8Array} [options.typedArray] The typed array containing the glTF contents, e.g. from a .b3dm, .i3dm, or .cmpt file.
  171. * @param {object} [options.gltfJson] A parsed glTF JSON file instead of passing it in as a typed array.
  172. * @param {boolean} [options.releaseGltfJson=false] When true, the glTF JSON is released once the glTF is loaded. This is especially useful for cases like 3D Tiles, where each .gltf model is unique and caching the glTF JSON is not effective.
  173. * @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.
  174. * @param {boolean} [options.incrementallyLoadTextures=true] Determine if textures may continue to stream in after the glTF is loaded.
  175. * @param {Axis} [options.upAxis=Axis.Y] The up-axis of the glTF model.
  176. * @param {Axis} [options.forwardAxis=Axis.Z] The forward-axis of the glTF model.
  177. * @param {boolean} [options.loadAttributesAsTypedArray=false] Load all attributes and indices as typed arrays instead of GPU buffers. If the attributes are interleaved in the glTF they will be de-interleaved in the typed array.
  178. * @param {boolean} [options.loadAttributesFor2D=false] If <code>true</code>, load the positions buffer and any instanced attribute buffers as typed arrays for accurately projecting models to 2D.
  179. * @param {boolean} [options.loadIndicesForWireframe=false] If <code>true</code>, load the index buffer as both a buffer and typed array. The latter is useful for creating wireframe indices in WebGL1.
  180. * @param {boolean} [options.loadPrimitiveOutline=true] If <code>true</code>, load outlines from the {@link https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/CESIUM_primitive_outline|CESIUM_primitive_outline} extension. This can be set false to avoid post-processing geometry at load time.
  181. * @param {boolean} [options.loadForClassification=false] If <code>true</code> and if the model has feature IDs, load the feature IDs and indices as typed arrays. This is useful for batching features for classification.
  182. * @param {boolean} [options.renameBatchIdSemantic=false] If <code>true</code>, rename _BATCHID or BATCHID to _FEATURE_ID_0. This is used for .b3dm models
  183. * @private
  184. */
  185. function GltfLoader(options) {
  186. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  187. const gltfResource = options.gltfResource;
  188. let baseResource = options.baseResource;
  189. const typedArray = options.typedArray;
  190. const releaseGltfJson = defaultValue(options.releaseGltfJson, false);
  191. const asynchronous = defaultValue(options.asynchronous, true);
  192. const incrementallyLoadTextures = defaultValue(
  193. options.incrementallyLoadTextures,
  194. true
  195. );
  196. const upAxis = defaultValue(options.upAxis, Axis.Y);
  197. const forwardAxis = defaultValue(options.forwardAxis, Axis.Z);
  198. const loadAttributesAsTypedArray = defaultValue(
  199. options.loadAttributesAsTypedArray,
  200. false
  201. );
  202. const loadAttributesFor2D = defaultValue(options.loadAttributesFor2D, false);
  203. const loadIndicesForWireframe = defaultValue(
  204. options.loadIndicesForWireframe,
  205. false
  206. );
  207. const loadPrimitiveOutline = defaultValue(options.loadPrimitiveOutline, true);
  208. const loadForClassification = defaultValue(
  209. options.loadForClassification,
  210. false
  211. );
  212. const renameBatchIdSemantic = defaultValue(
  213. options.renameBatchIdSemantic,
  214. false
  215. );
  216. //>>includeStart('debug', pragmas.debug);
  217. Check.typeOf.object("options.gltfResource", gltfResource);
  218. //>>includeEnd('debug');
  219. baseResource = defined(baseResource) ? baseResource : gltfResource.clone();
  220. this._gltfJson = options.gltfJson;
  221. this._gltfResource = gltfResource;
  222. this._baseResource = baseResource;
  223. this._typedArray = typedArray;
  224. this._releaseGltfJson = releaseGltfJson;
  225. this._asynchronous = asynchronous;
  226. this._incrementallyLoadTextures = incrementallyLoadTextures;
  227. this._upAxis = upAxis;
  228. this._forwardAxis = forwardAxis;
  229. this._loadAttributesAsTypedArray = loadAttributesAsTypedArray;
  230. this._loadAttributesFor2D = loadAttributesFor2D;
  231. this._loadIndicesForWireframe = loadIndicesForWireframe;
  232. this._loadPrimitiveOutline = loadPrimitiveOutline;
  233. this._loadForClassification = loadForClassification;
  234. this._renameBatchIdSemantic = renameBatchIdSemantic;
  235. // When loading EXT_feature_metadata, the feature tables and textures
  236. // are now stored as arrays like the newer EXT_structural_metadata extension.
  237. // This requires sorting the dictionary keys for a consistent ordering.
  238. this._sortedPropertyTableIds = undefined;
  239. this._sortedFeatureTextureIds = undefined;
  240. this._gltfJsonLoader = undefined;
  241. this._state = GltfLoaderState.NOT_LOADED;
  242. this._textureState = GltfLoaderState.NOT_LOADED;
  243. this._promise = undefined;
  244. this._processError = undefined;
  245. this._textureErrors = [];
  246. // Information about whether to load primitives as typed arrays or buffers,
  247. // and whether post-processing is needed after loading (e.g. for
  248. // generating outlines)
  249. this._primitiveLoadPlans = [];
  250. // Loaders that need to be processed before the glTF becomes ready
  251. this._loaderPromises = [];
  252. this._textureLoaders = [];
  253. this._texturesPromises = [];
  254. this._textureCallbacks = [];
  255. this._bufferViewLoaders = [];
  256. this._geometryLoaders = [];
  257. this._geometryCallbacks = [];
  258. this._structuralMetadataLoader = undefined;
  259. this._loadResourcesPromise = undefined;
  260. this._resourcesLoaded = false;
  261. this._texturesLoaded = false;
  262. // In some cases where geometry post-processing is needed (like generating
  263. // outlines) new attributes are added that may have GPU resources attached.
  264. // The GltfLoader will own the resources and store them here.
  265. this._postProcessBuffers = [];
  266. // Loaded results
  267. this._components = undefined;
  268. }
  269. if (defined(Object.create)) {
  270. GltfLoader.prototype = Object.create(ResourceLoader.prototype);
  271. GltfLoader.prototype.constructor = GltfLoader;
  272. }
  273. Object.defineProperties(GltfLoader.prototype, {
  274. /**
  275. * The cache key of the resource.
  276. *
  277. * @memberof GltfLoader.prototype
  278. *
  279. * @type {string}
  280. * @readonly
  281. * @private
  282. */
  283. cacheKey: {
  284. get: function () {
  285. return undefined;
  286. },
  287. },
  288. /**
  289. * The loaded components.
  290. *
  291. * @memberof GltfLoader.prototype
  292. *
  293. * @type {ModelComponents.Components}
  294. * @readonly
  295. * @private
  296. */
  297. components: {
  298. get: function () {
  299. return this._components;
  300. },
  301. },
  302. /**
  303. * The loaded glTF json.
  304. *
  305. * @memberof GltfLoader.prototype
  306. *
  307. * @type {object}
  308. * @readonly
  309. * @private
  310. */
  311. gltfJson: {
  312. get: function () {
  313. if (defined(this._gltfJsonLoader)) {
  314. return this._gltfJsonLoader.gltf;
  315. }
  316. return this._gltfJson;
  317. },
  318. },
  319. /**
  320. * Returns true if textures are loaded separately from the other glTF resources.
  321. *
  322. * @memberof GltfLoader.prototype
  323. *
  324. * @type {boolean}
  325. * @readonly
  326. * @private
  327. */
  328. incrementallyLoadTextures: {
  329. get: function () {
  330. return this._incrementallyLoadTextures;
  331. },
  332. },
  333. /**
  334. * true if textures are loaded, useful when incrementallyLoadTextures is true
  335. *
  336. * @memberof GltfLoader.prototype
  337. *
  338. * @type {boolean}
  339. * @readonly
  340. * @private
  341. */
  342. texturesLoaded: {
  343. get: function () {
  344. return this._texturesLoaded;
  345. },
  346. },
  347. });
  348. /**
  349. * Loads the gltf object
  350. */
  351. async function loadGltfJson(loader) {
  352. loader._state = GltfLoaderState.LOADING;
  353. loader._textureState = GltfLoaderState.LOADING;
  354. try {
  355. const gltfJsonLoader = ResourceCache.getGltfJsonLoader({
  356. gltfResource: loader._gltfResource,
  357. baseResource: loader._baseResource,
  358. typedArray: loader._typedArray,
  359. gltfJson: loader._gltfJson,
  360. });
  361. loader._gltfJsonLoader = gltfJsonLoader;
  362. await gltfJsonLoader.load();
  363. if (
  364. loader.isDestroyed() ||
  365. loader.isUnloaded() ||
  366. gltfJsonLoader.isDestroyed()
  367. ) {
  368. return;
  369. }
  370. loader._state = GltfLoaderState.LOADED;
  371. loader._textureState = GltfLoaderState.LOADED;
  372. return loader;
  373. } catch (error) {
  374. if (loader.isDestroyed()) {
  375. return;
  376. }
  377. loader._state = GltfLoaderState.FAILED;
  378. loader._textureState = GltfLoaderState.FAILED;
  379. handleError(loader, error);
  380. }
  381. }
  382. async function loadResources(loader, frameState) {
  383. if (!FeatureDetection.supportsWebP.initialized) {
  384. await FeatureDetection.supportsWebP.initialize();
  385. }
  386. const supportedImageFormats = new SupportedImageFormats({
  387. webp: FeatureDetection.supportsWebP(),
  388. basis: frameState.context.supportsBasis,
  389. });
  390. // Parse the glTF which populates the loaders arrays. Loading promises will be created, and will
  391. // resolve once the loaders are ready (i.e. all external resources
  392. // have been fetched and all GPU resources have been created). Loaders that
  393. // create GPU resources need to be processed every frame until they become
  394. // ready since the JobScheduler is not able to execute all jobs in a single
  395. // frame. Any promise failures are collected, and will be handled synchronously in process(). Also note that it's fine to call process before a loader is ready
  396. // to process or after it has failed; nothing will happen.
  397. const gltf = loader.gltfJson;
  398. const promise = parse(loader, gltf, supportedImageFormats, frameState);
  399. // All resource loaders have been created, so we can begin processing
  400. loader._state = GltfLoaderState.PROCESSING;
  401. loader._textureState = GltfLoaderState.PROCESSING;
  402. if (defined(loader._gltfJsonLoader) && loader._releaseGltfJson) {
  403. // Check that the glTF JSON loader is still defined before trying to unload it.
  404. // It can be unloaded if the glTF loader is destroyed.
  405. ResourceCache.unload(loader._gltfJsonLoader);
  406. loader._gltfJsonLoader = undefined;
  407. }
  408. return promise;
  409. }
  410. /**
  411. * Loads the resource.
  412. * @returns {Promise.<GltfLoader>} A promise which resolves to the loader when the resource loading is completed.
  413. * @exception {RuntimeError} Unsupported glTF version
  414. * @exception {RuntimeError} Unsupported glTF Extension
  415. * @private
  416. */
  417. GltfLoader.prototype.load = async function () {
  418. if (defined(this._promise)) {
  419. return this._promise;
  420. }
  421. this._promise = loadGltfJson(this);
  422. return this._promise;
  423. };
  424. function handleError(gltfLoader, error) {
  425. gltfLoader.unload();
  426. const errorMessage = "Failed to load glTF";
  427. throw gltfLoader.getError(errorMessage, error);
  428. }
  429. function processLoaders(loader, frameState) {
  430. let i;
  431. let ready = true;
  432. const geometryLoaders = loader._geometryLoaders;
  433. const geometryLoadersLength = geometryLoaders.length;
  434. for (i = 0; i < geometryLoadersLength; ++i) {
  435. const geometryReady = geometryLoaders[i].process(frameState);
  436. if (geometryReady && defined(loader._geometryCallbacks[i])) {
  437. loader._geometryCallbacks[i]();
  438. loader._geometryCallbacks[i] = undefined;
  439. }
  440. ready = ready && geometryReady;
  441. }
  442. const structuralMetadataLoader = loader._structuralMetadataLoader;
  443. if (defined(structuralMetadataLoader)) {
  444. const metadataReady = structuralMetadataLoader.process(frameState);
  445. if (metadataReady) {
  446. loader._components.structuralMetadata =
  447. structuralMetadataLoader.structuralMetadata;
  448. }
  449. ready = ready && metadataReady;
  450. }
  451. if (ready) {
  452. // Geometry requires further processing
  453. loader._state = GltfLoaderState.POST_PROCESSING;
  454. }
  455. }
  456. function postProcessGeometry(loader, context) {
  457. // Apply post-processing steps on geometry such as
  458. // updating attributes for rendering outlines.
  459. const loadPlans = loader._primitiveLoadPlans;
  460. const length = loadPlans.length;
  461. for (let i = 0; i < length; i++) {
  462. const loadPlan = loadPlans[i];
  463. loadPlan.postProcess(context);
  464. if (loadPlan.needsOutlines) {
  465. // The glTF loader takes ownership of any buffers generated in the
  466. // post-process stage since they were created after the geometry loaders
  467. // finished. This way they can be destroyed when the loader is destroyed.
  468. gatherPostProcessBuffers(loader, loadPlan);
  469. }
  470. }
  471. }
  472. function gatherPostProcessBuffers(loader, primitiveLoadPlan) {
  473. const buffers = loader._postProcessBuffers;
  474. const primitive = primitiveLoadPlan.primitive;
  475. const outlineCoordinates = primitive.outlineCoordinates;
  476. if (defined(outlineCoordinates)) {
  477. // outline coordinates are always loaded as a buffer.
  478. buffers.push(outlineCoordinates.buffer);
  479. }
  480. // to do post-processing, all the attributes are loaded as typed arrays
  481. // so if a buffer exists, it was newly generated
  482. const attributes = primitive.attributes;
  483. const length = attributes.length;
  484. for (let i = 0; i < length; i++) {
  485. const attribute = attributes[i];
  486. if (defined(attribute.buffer)) {
  487. buffers.push(attribute.buffer);
  488. }
  489. }
  490. // Similarly for the indices.
  491. const indices = primitive.indices;
  492. if (defined(indices) && defined(indices.buffer)) {
  493. buffers.push(indices.buffer);
  494. }
  495. }
  496. /**
  497. * Process loaders other than textures
  498. * @private
  499. */
  500. GltfLoader.prototype._process = function (frameState) {
  501. if (this._state === GltfLoaderState.READY) {
  502. return true;
  503. }
  504. if (this._state === GltfLoaderState.PROCESSING) {
  505. processLoaders(this, frameState);
  506. }
  507. if (
  508. this._resourcesLoaded &&
  509. this._state === GltfLoaderState.POST_PROCESSING
  510. ) {
  511. postProcessGeometry(this, frameState.context);
  512. this._state = GltfLoaderState.PROCESSED;
  513. }
  514. if (this._resourcesLoaded && this._state === GltfLoaderState.PROCESSED) {
  515. // The buffer views can be unloaded once the data is copied.
  516. unloadBufferViewLoaders(this);
  517. // Similarly, if the glTF was loaded from a typed array, release the memory
  518. this._typedArray = undefined;
  519. this._state = GltfLoaderState.READY;
  520. return true;
  521. }
  522. return false;
  523. };
  524. /**
  525. * Process textures other than textures
  526. * @private
  527. */
  528. GltfLoader.prototype._processTextures = function (frameState) {
  529. if (this._textureState === GltfLoaderState.READY) {
  530. return true;
  531. }
  532. if (this._textureState !== GltfLoaderState.PROCESSING) {
  533. return false;
  534. }
  535. let i;
  536. let ready = true;
  537. const textureLoaders = this._textureLoaders;
  538. const textureLoadersLength = textureLoaders.length;
  539. for (i = 0; i < textureLoadersLength; ++i) {
  540. const textureReady = textureLoaders[i].process(frameState);
  541. if (textureReady && defined(this._textureCallbacks[i])) {
  542. this._textureCallbacks[i]();
  543. this._textureCallbacks[i] = undefined;
  544. }
  545. ready = ready && textureReady;
  546. }
  547. if (!ready) {
  548. return false;
  549. }
  550. this._textureState = GltfLoaderState.READY;
  551. this._texturesLoaded = true;
  552. return true;
  553. };
  554. /**
  555. * Processes the resource until it becomes ready.
  556. *
  557. * @param {FrameState} frameState The frame state.
  558. * @private
  559. */
  560. GltfLoader.prototype.process = function (frameState) {
  561. //>>includeStart('debug', pragmas.debug);
  562. Check.typeOf.object("frameState", frameState);
  563. //>>includeEnd('debug');
  564. if (
  565. this._state === GltfLoaderState.LOADED &&
  566. !defined(this._loadResourcesPromise)
  567. ) {
  568. this._loadResourcesPromise = loadResources(this, frameState)
  569. .then(() => {
  570. this._resourcesLoaded = true;
  571. })
  572. .catch((error) => {
  573. this._processError = error;
  574. });
  575. }
  576. if (defined(this._processError)) {
  577. this._state = GltfLoaderState.FAILED;
  578. const error = this._processError;
  579. this._processError = undefined;
  580. handleError(this, error);
  581. }
  582. // Pop the next error of the list in case there are multiple
  583. const textureError = this._textureErrors.pop();
  584. if (defined(textureError)) {
  585. // There shouldn't be the need to completely unload in this case. Just throw the error.
  586. const error = this.getError("Failed to load glTF texture", textureError);
  587. error.name = "TextureError";
  588. throw error;
  589. }
  590. if (this._state === GltfLoaderState.FAILED) {
  591. return false;
  592. }
  593. let ready = false;
  594. try {
  595. ready = this._process(frameState);
  596. } catch (error) {
  597. this._state = GltfLoaderState.FAILED;
  598. handleError(this, error);
  599. }
  600. // Since textures can be loaded independently and are handled through a separate promise, they are processed in their own function
  601. let texturesReady = false;
  602. try {
  603. texturesReady = this._processTextures(frameState);
  604. } catch (error) {
  605. this._textureState = GltfLoaderState.FAILED;
  606. handleError(this, error);
  607. }
  608. if (this._incrementallyLoadTextures) {
  609. return ready;
  610. }
  611. return ready && texturesReady;
  612. };
  613. function getVertexBufferLoader(
  614. loader,
  615. gltf,
  616. accessorId,
  617. semantic,
  618. draco,
  619. loadBuffer,
  620. loadTypedArray,
  621. frameState
  622. ) {
  623. const accessor = gltf.accessors[accessorId];
  624. const bufferViewId = accessor.bufferView;
  625. const vertexBufferLoader = ResourceCache.getVertexBufferLoader({
  626. gltf: gltf,
  627. gltfResource: loader._gltfResource,
  628. baseResource: loader._baseResource,
  629. frameState: frameState,
  630. bufferViewId: bufferViewId,
  631. draco: draco,
  632. attributeSemantic: semantic,
  633. accessorId: accessorId,
  634. asynchronous: loader._asynchronous,
  635. loadBuffer: loadBuffer,
  636. loadTypedArray: loadTypedArray,
  637. });
  638. return vertexBufferLoader;
  639. }
  640. function getIndexBufferLoader(
  641. loader,
  642. gltf,
  643. accessorId,
  644. draco,
  645. loadBuffer,
  646. loadTypedArray,
  647. frameState
  648. ) {
  649. const indexBufferLoader = ResourceCache.getIndexBufferLoader({
  650. gltf: gltf,
  651. accessorId: accessorId,
  652. gltfResource: loader._gltfResource,
  653. baseResource: loader._baseResource,
  654. frameState: frameState,
  655. draco: draco,
  656. asynchronous: loader._asynchronous,
  657. loadBuffer: loadBuffer,
  658. loadTypedArray: loadTypedArray,
  659. });
  660. return indexBufferLoader;
  661. }
  662. function getBufferViewLoader(loader, gltf, bufferViewId) {
  663. const bufferViewLoader = ResourceCache.getBufferViewLoader({
  664. gltf: gltf,
  665. bufferViewId: bufferViewId,
  666. gltfResource: loader._gltfResource,
  667. baseResource: loader._baseResource,
  668. });
  669. loader._bufferViewLoaders.push(bufferViewLoader);
  670. return bufferViewLoader;
  671. }
  672. function getPackedTypedArray(gltf, accessor, bufferViewTypedArray) {
  673. let byteOffset = accessor.byteOffset;
  674. const byteStride = getAccessorByteStride(gltf, accessor);
  675. const count = accessor.count;
  676. const componentCount = numberOfComponentsForType(accessor.type);
  677. const componentType = accessor.componentType;
  678. const componentByteLength = ComponentDatatype.getSizeInBytes(componentType);
  679. const defaultByteStride = componentByteLength * componentCount;
  680. const componentsLength = count * componentCount;
  681. if (byteStride === defaultByteStride) {
  682. // Copy the typed array and let the underlying ArrayBuffer be freed
  683. bufferViewTypedArray = new Uint8Array(bufferViewTypedArray);
  684. return ComponentDatatype.createArrayBufferView(
  685. componentType,
  686. bufferViewTypedArray.buffer,
  687. bufferViewTypedArray.byteOffset + byteOffset,
  688. componentsLength
  689. );
  690. }
  691. const accessorTypedArray = ComponentDatatype.createTypedArray(
  692. componentType,
  693. componentsLength
  694. );
  695. const dataView = new DataView(bufferViewTypedArray.buffer);
  696. const components = new Array(componentCount);
  697. const componentReader = getComponentReader(accessor.componentType);
  698. byteOffset = bufferViewTypedArray.byteOffset + byteOffset;
  699. for (let i = 0; i < count; ++i) {
  700. componentReader(
  701. dataView,
  702. byteOffset,
  703. componentCount,
  704. componentByteLength,
  705. components
  706. );
  707. for (let j = 0; j < componentCount; ++j) {
  708. accessorTypedArray[i * componentCount + j] = components[j];
  709. }
  710. byteOffset += byteStride;
  711. }
  712. return accessorTypedArray;
  713. }
  714. function loadDefaultAccessorValues(accessor, values) {
  715. const accessorType = accessor.type;
  716. if (accessorType === AttributeType.SCALAR) {
  717. return values.fill(0);
  718. }
  719. const MathType = AttributeType.getMathType(accessorType);
  720. return values.fill(MathType.clone(MathType.ZERO));
  721. }
  722. function loadAccessorValues(accessor, typedArray, values, useQuaternion) {
  723. const accessorType = accessor.type;
  724. const accessorCount = accessor.count;
  725. if (accessorType === AttributeType.SCALAR) {
  726. for (let i = 0; i < accessorCount; i++) {
  727. values[i] = typedArray[i];
  728. }
  729. } else if (accessorType === AttributeType.VEC4 && useQuaternion) {
  730. for (let i = 0; i < accessorCount; i++) {
  731. values[i] = Quaternion.unpack(typedArray, i * 4);
  732. }
  733. } else {
  734. const MathType = AttributeType.getMathType(accessorType);
  735. const numberOfComponents = AttributeType.getNumberOfComponents(
  736. accessorType
  737. );
  738. for (let i = 0; i < accessorCount; i++) {
  739. values[i] = MathType.unpack(typedArray, i * numberOfComponents);
  740. }
  741. }
  742. return values;
  743. }
  744. async function loadAccessorBufferView(
  745. loader,
  746. bufferViewLoader,
  747. gltf,
  748. accessor,
  749. useQuaternion,
  750. values
  751. ) {
  752. await bufferViewLoader.load();
  753. if (loader.isDestroyed()) {
  754. return;
  755. }
  756. const bufferViewTypedArray = bufferViewLoader.typedArray;
  757. const typedArray = getPackedTypedArray(gltf, accessor, bufferViewTypedArray);
  758. useQuaternion = defaultValue(useQuaternion, false);
  759. loadAccessorValues(accessor, typedArray, values, useQuaternion);
  760. }
  761. function loadAccessor(loader, gltf, accessorId, useQuaternion) {
  762. const accessor = gltf.accessors[accessorId];
  763. const accessorCount = accessor.count;
  764. const values = new Array(accessorCount);
  765. const bufferViewId = accessor.bufferView;
  766. if (defined(bufferViewId)) {
  767. const bufferViewLoader = getBufferViewLoader(loader, gltf, bufferViewId);
  768. const promise = loadAccessorBufferView(
  769. loader,
  770. bufferViewLoader,
  771. gltf,
  772. accessor,
  773. useQuaternion,
  774. values
  775. );
  776. loader._loaderPromises.push(promise);
  777. return values;
  778. }
  779. return loadDefaultAccessorValues(accessor, values);
  780. }
  781. function fromArray(MathType, values) {
  782. if (!defined(values)) {
  783. return undefined;
  784. }
  785. if (MathType === Number) {
  786. return values[0];
  787. }
  788. return MathType.unpack(values);
  789. }
  790. function getDefault(MathType) {
  791. if (MathType === Number) {
  792. return 0.0;
  793. }
  794. return new MathType(); // defaults to 0.0 for all types
  795. }
  796. function getQuantizationDivisor(componentDatatype) {
  797. switch (componentDatatype) {
  798. case ComponentDatatype.BYTE:
  799. return 127;
  800. case ComponentDatatype.UNSIGNED_BYTE:
  801. return 255;
  802. case ComponentDatatype.SHORT:
  803. return 32767;
  804. case ComponentDatatype.UNSIGNED_SHORT:
  805. return 65535;
  806. default:
  807. return 1.0;
  808. }
  809. }
  810. const minimumBoundsByType = {
  811. VEC2: new Cartesian2(-1.0, -1.0),
  812. VEC3: new Cartesian3(-1.0, -1.0, -1.0),
  813. VEC4: new Cartesian4(-1.0, -1.0, -1.0, -1.0),
  814. };
  815. function dequantizeMinMax(attribute, VectorType) {
  816. const divisor = getQuantizationDivisor(attribute.componentDatatype);
  817. const minimumBound = minimumBoundsByType[attribute.type];
  818. // dequantized = max(quantized / divisor, -1.0)
  819. let min = attribute.min;
  820. if (defined(min)) {
  821. min = VectorType.divideByScalar(min, divisor, min);
  822. min = VectorType.maximumByComponent(min, minimumBound, min);
  823. }
  824. let max = attribute.max;
  825. if (defined(max)) {
  826. max = VectorType.divideByScalar(max, divisor, max);
  827. max = VectorType.maximumByComponent(max, minimumBound, max);
  828. }
  829. attribute.min = min;
  830. attribute.max = max;
  831. }
  832. function setQuantizationFromWeb3dQuantizedAttributes(
  833. extension,
  834. attribute,
  835. MathType
  836. ) {
  837. const decodeMatrix = extension.decodeMatrix;
  838. const decodedMin = fromArray(MathType, extension.decodedMin);
  839. const decodedMax = fromArray(MathType, extension.decodedMax);
  840. if (defined(decodedMin) && defined(decodedMax)) {
  841. attribute.min = decodedMin;
  842. attribute.max = decodedMax;
  843. }
  844. const quantization = new ModelComponents.Quantization();
  845. quantization.componentDatatype = attribute.componentDatatype;
  846. quantization.type = attribute.type;
  847. if (decodeMatrix.length === 4) {
  848. quantization.quantizedVolumeOffset = decodeMatrix[2];
  849. quantization.quantizedVolumeStepSize = decodeMatrix[0];
  850. } else if (decodeMatrix.length === 9) {
  851. quantization.quantizedVolumeOffset = new Cartesian2(
  852. decodeMatrix[6],
  853. decodeMatrix[7]
  854. );
  855. quantization.quantizedVolumeStepSize = new Cartesian2(
  856. decodeMatrix[0],
  857. decodeMatrix[4]
  858. );
  859. } else if (decodeMatrix.length === 16) {
  860. quantization.quantizedVolumeOffset = new Cartesian3(
  861. decodeMatrix[12],
  862. decodeMatrix[13],
  863. decodeMatrix[14]
  864. );
  865. quantization.quantizedVolumeStepSize = new Cartesian3(
  866. decodeMatrix[0],
  867. decodeMatrix[5],
  868. decodeMatrix[10]
  869. );
  870. } else if (decodeMatrix.length === 25) {
  871. quantization.quantizedVolumeOffset = new Cartesian4(
  872. decodeMatrix[20],
  873. decodeMatrix[21],
  874. decodeMatrix[22],
  875. decodeMatrix[23]
  876. );
  877. quantization.quantizedVolumeStepSize = new Cartesian4(
  878. decodeMatrix[0],
  879. decodeMatrix[6],
  880. decodeMatrix[12],
  881. decodeMatrix[18]
  882. );
  883. }
  884. attribute.quantization = quantization;
  885. }
  886. function createAttribute(gltf, accessorId, name, semantic, setIndex) {
  887. const accessor = gltf.accessors[accessorId];
  888. const MathType = AttributeType.getMathType(accessor.type);
  889. const normalized = defaultValue(accessor.normalized, false);
  890. const attribute = new Attribute();
  891. attribute.name = name;
  892. attribute.semantic = semantic;
  893. attribute.setIndex = setIndex;
  894. attribute.constant = getDefault(MathType);
  895. attribute.componentDatatype = accessor.componentType;
  896. attribute.normalized = normalized;
  897. attribute.count = accessor.count;
  898. attribute.type = accessor.type;
  899. attribute.min = fromArray(MathType, accessor.min);
  900. attribute.max = fromArray(MathType, accessor.max);
  901. attribute.byteOffset = accessor.byteOffset;
  902. attribute.byteStride = getAccessorByteStride(gltf, accessor);
  903. if (hasExtension(accessor, "WEB3D_quantized_attributes")) {
  904. setQuantizationFromWeb3dQuantizedAttributes(
  905. accessor.extensions.WEB3D_quantized_attributes,
  906. attribute,
  907. MathType
  908. );
  909. }
  910. const isQuantizable =
  911. attribute.semantic === VertexAttributeSemantic.POSITION ||
  912. attribute.semantic === VertexAttributeSemantic.NORMAL ||
  913. attribute.semantic === VertexAttributeSemantic.TANGENT ||
  914. attribute.semantic === VertexAttributeSemantic.TEXCOORD;
  915. // In the glTF 2.0 spec, min and max are not affected by the normalized flag.
  916. // However, for KHR_mesh_quantization, min and max must be dequantized for
  917. // normalized values, else the bounding sphere will be computed incorrectly.
  918. const hasKhrMeshQuantization = gltf.extensionsRequired?.includes(
  919. "KHR_mesh_quantization"
  920. );
  921. if (hasKhrMeshQuantization && normalized && isQuantizable) {
  922. dequantizeMinMax(attribute, MathType);
  923. }
  924. return attribute;
  925. }
  926. function getSetIndex(gltfSemantic) {
  927. const setIndexRegex = /^\w+_(\d+)$/;
  928. const setIndexMatch = setIndexRegex.exec(gltfSemantic);
  929. if (setIndexMatch !== null) {
  930. return parseInt(setIndexMatch[1]);
  931. }
  932. return undefined;
  933. }
  934. const scratchSemanticInfo = {
  935. gltfSemantic: undefined,
  936. renamedSemantic: undefined,
  937. modelSemantic: undefined,
  938. };
  939. function getSemanticInfo(loader, semanticType, gltfSemantic) {
  940. // For .b3dm, rename _BATCHID (or the legacy BATCHID) to _FEATURE_ID_0
  941. // in the generated model components for compatibility with EXT_mesh_features
  942. let renamedSemantic = gltfSemantic;
  943. if (
  944. loader._renameBatchIdSemantic &&
  945. (gltfSemantic === "_BATCHID" || gltfSemantic === "BATCHID")
  946. ) {
  947. renamedSemantic = "_FEATURE_ID_0";
  948. }
  949. const modelSemantic = semanticType.fromGltfSemantic(renamedSemantic);
  950. const semanticInfo = scratchSemanticInfo;
  951. semanticInfo.gltfSemantic = gltfSemantic;
  952. semanticInfo.renamedSemantic = renamedSemantic;
  953. semanticInfo.modelSemantic = modelSemantic;
  954. return semanticInfo;
  955. }
  956. function isClassificationAttribute(attributeSemantic) {
  957. // Classification models only use the position, texcoord, and feature ID attributes.
  958. const isPositionAttribute =
  959. attributeSemantic === VertexAttributeSemantic.POSITION;
  960. const isFeatureIdAttribute =
  961. attributeSemantic === VertexAttributeSemantic.FEATURE_ID;
  962. const isTexcoordAttribute =
  963. attributeSemantic === VertexAttributeSemantic.TEXCOORD;
  964. return isPositionAttribute || isFeatureIdAttribute || isTexcoordAttribute;
  965. }
  966. function finalizeDracoAttribute(
  967. attribute,
  968. vertexBufferLoader,
  969. loadBuffer,
  970. loadTypedArray
  971. ) {
  972. // The accessor's byteOffset and byteStride should be ignored for draco.
  973. // Each attribute is tightly packed in its own buffer after decode.
  974. attribute.byteOffset = 0;
  975. attribute.byteStride = undefined;
  976. attribute.quantization = vertexBufferLoader.quantization;
  977. if (loadBuffer) {
  978. attribute.buffer = vertexBufferLoader.buffer;
  979. }
  980. if (loadTypedArray) {
  981. const componentDatatype = defined(vertexBufferLoader.quantization)
  982. ? vertexBufferLoader.quantization.componentDatatype
  983. : attribute.componentDatatype;
  984. attribute.typedArray = ComponentDatatype.createArrayBufferView(
  985. componentDatatype,
  986. vertexBufferLoader.typedArray.buffer
  987. );
  988. }
  989. }
  990. function finalizeAttribute(
  991. gltf,
  992. accessor,
  993. attribute,
  994. vertexBufferLoader,
  995. loadBuffer,
  996. loadTypedArray
  997. ) {
  998. if (loadBuffer) {
  999. attribute.buffer = vertexBufferLoader.buffer;
  1000. }
  1001. if (loadTypedArray) {
  1002. const bufferViewTypedArray = vertexBufferLoader.typedArray;
  1003. attribute.typedArray = getPackedTypedArray(
  1004. gltf,
  1005. accessor,
  1006. bufferViewTypedArray
  1007. );
  1008. if (!loadBuffer) {
  1009. // If the buffer isn't loaded, then the accessor's byteOffset and
  1010. // byteStride should be ignored, since values are only available in a
  1011. // tightly packed typed array
  1012. attribute.byteOffset = 0;
  1013. attribute.byteStride = undefined;
  1014. }
  1015. }
  1016. }
  1017. function loadAttribute(
  1018. loader,
  1019. gltf,
  1020. accessorId,
  1021. semanticInfo,
  1022. draco,
  1023. loadBuffer,
  1024. loadTypedArray,
  1025. frameState
  1026. ) {
  1027. const accessor = gltf.accessors[accessorId];
  1028. const bufferViewId = accessor.bufferView;
  1029. const gltfSemantic = semanticInfo.gltfSemantic;
  1030. const renamedSemantic = semanticInfo.renamedSemantic;
  1031. const modelSemantic = semanticInfo.modelSemantic;
  1032. const setIndex = defined(modelSemantic)
  1033. ? getSetIndex(renamedSemantic)
  1034. : undefined;
  1035. const name = gltfSemantic;
  1036. const attribute = createAttribute(
  1037. gltf,
  1038. accessorId,
  1039. name,
  1040. modelSemantic,
  1041. setIndex
  1042. );
  1043. if (!defined(draco) && !defined(bufferViewId)) {
  1044. return attribute;
  1045. }
  1046. const vertexBufferLoader = getVertexBufferLoader(
  1047. loader,
  1048. gltf,
  1049. accessorId,
  1050. gltfSemantic,
  1051. draco,
  1052. loadBuffer,
  1053. loadTypedArray,
  1054. frameState
  1055. );
  1056. const index = loader._geometryLoaders.length;
  1057. loader._geometryLoaders.push(vertexBufferLoader);
  1058. const promise = vertexBufferLoader.load();
  1059. loader._loaderPromises.push(promise);
  1060. // This can only execute once vertexBufferLoader.process() has run and returns true
  1061. // Save this finish callback by the loader index so it can be called
  1062. // in process().
  1063. loader._geometryCallbacks[index] = () => {
  1064. if (
  1065. defined(draco) &&
  1066. defined(draco.attributes) &&
  1067. defined(draco.attributes[gltfSemantic])
  1068. ) {
  1069. finalizeDracoAttribute(
  1070. attribute,
  1071. vertexBufferLoader,
  1072. loadBuffer,
  1073. loadTypedArray
  1074. );
  1075. } else {
  1076. finalizeAttribute(
  1077. gltf,
  1078. accessor,
  1079. attribute,
  1080. vertexBufferLoader,
  1081. loadBuffer,
  1082. loadTypedArray
  1083. );
  1084. }
  1085. };
  1086. return attribute;
  1087. }
  1088. function loadVertexAttribute(
  1089. loader,
  1090. gltf,
  1091. accessorId,
  1092. semanticInfo,
  1093. draco,
  1094. hasInstances,
  1095. needsPostProcessing,
  1096. frameState
  1097. ) {
  1098. const modelSemantic = semanticInfo.modelSemantic;
  1099. const isPositionAttribute =
  1100. modelSemantic === VertexAttributeSemantic.POSITION;
  1101. const isFeatureIdAttribute =
  1102. modelSemantic === VertexAttributeSemantic.FEATURE_ID;
  1103. const loadTypedArrayFor2D =
  1104. isPositionAttribute &&
  1105. !hasInstances &&
  1106. loader._loadAttributesFor2D &&
  1107. !frameState.scene3DOnly;
  1108. const loadTypedArrayForClassification =
  1109. loader._loadForClassification && isFeatureIdAttribute;
  1110. // Whether the final output should be a buffer or typed array
  1111. // after loading and post-processing.
  1112. const outputTypedArrayOnly = loader._loadAttributesAsTypedArray;
  1113. const outputBuffer = !outputTypedArrayOnly;
  1114. const outputTypedArray =
  1115. outputTypedArrayOnly ||
  1116. loadTypedArrayFor2D ||
  1117. loadTypedArrayForClassification;
  1118. // Determine what to load right now:
  1119. //
  1120. // - If post-processing is needed, load a packed typed array for
  1121. // further processing, and defer the buffer loading until later.
  1122. // - On the other hand, if post-processing is not needed,
  1123. // set the load flags directly
  1124. const loadBuffer = needsPostProcessing ? false : outputBuffer;
  1125. const loadTypedArray = needsPostProcessing ? true : outputTypedArray;
  1126. const attribute = loadAttribute(
  1127. loader,
  1128. gltf,
  1129. accessorId,
  1130. semanticInfo,
  1131. draco,
  1132. loadBuffer,
  1133. loadTypedArray,
  1134. frameState
  1135. );
  1136. const attributePlan = new PrimitiveLoadPlan.AttributeLoadPlan(attribute);
  1137. attributePlan.loadBuffer = outputBuffer;
  1138. attributePlan.loadTypedArray = outputTypedArray;
  1139. return attributePlan;
  1140. }
  1141. function loadInstancedAttribute(
  1142. loader,
  1143. gltf,
  1144. accessorId,
  1145. attributes,
  1146. gltfSemantic,
  1147. frameState
  1148. ) {
  1149. const hasRotation = defined(attributes.ROTATION);
  1150. const hasTranslationMinMax =
  1151. defined(attributes.TRANSLATION) &&
  1152. defined(gltf.accessors[attributes.TRANSLATION].min) &&
  1153. defined(gltf.accessors[attributes.TRANSLATION].max);
  1154. const semanticInfo = getSemanticInfo(
  1155. loader,
  1156. InstanceAttributeSemantic,
  1157. gltfSemantic
  1158. );
  1159. const modelSemantic = semanticInfo.modelSemantic;
  1160. const isTransformAttribute =
  1161. modelSemantic === InstanceAttributeSemantic.TRANSLATION ||
  1162. modelSemantic === InstanceAttributeSemantic.ROTATION ||
  1163. modelSemantic === InstanceAttributeSemantic.SCALE;
  1164. const isTranslationAttribute =
  1165. modelSemantic === InstanceAttributeSemantic.TRANSLATION;
  1166. // Load the attributes as typed arrays only if:
  1167. // - loadAttributesAsTypedArray is true
  1168. // - the instances have rotations. This only applies to the transform attributes,
  1169. // since The instance matrices are computed on the CPU. This avoids the
  1170. // expensive quaternion -> rotation matrix conversion in the shader.
  1171. // - GPU instancing is not supported.
  1172. const loadAsTypedArrayOnly =
  1173. loader._loadAttributesAsTypedArray ||
  1174. (hasRotation && isTransformAttribute) ||
  1175. !frameState.context.instancedArrays;
  1176. const loadBuffer = !loadAsTypedArrayOnly;
  1177. // Load the translations as a typed array in addition to the buffer if
  1178. // - the accessor does not have a min and max. The values will be used
  1179. // for computing an accurate bounding volume.
  1180. // - the model will be projected to 2D.
  1181. const loadFor2D = loader._loadAttributesFor2D && !frameState.scene3DOnly;
  1182. const loadTranslationAsTypedArray =
  1183. isTranslationAttribute && (!hasTranslationMinMax || loadFor2D);
  1184. const loadTypedArray = loadAsTypedArrayOnly || loadTranslationAsTypedArray;
  1185. // Don't pass in draco object since instanced attributes can't be draco compressed
  1186. return loadAttribute(
  1187. loader,
  1188. gltf,
  1189. accessorId,
  1190. semanticInfo,
  1191. undefined,
  1192. loadBuffer,
  1193. loadTypedArray,
  1194. frameState
  1195. );
  1196. }
  1197. function loadIndices(
  1198. loader,
  1199. gltf,
  1200. accessorId,
  1201. draco,
  1202. hasFeatureIds,
  1203. needsPostProcessing,
  1204. frameState
  1205. ) {
  1206. const accessor = gltf.accessors[accessorId];
  1207. const bufferViewId = accessor.bufferView;
  1208. if (!defined(draco) && !defined(bufferViewId)) {
  1209. return undefined;
  1210. }
  1211. const indices = new Indices();
  1212. indices.count = accessor.count;
  1213. const loadAttributesAsTypedArray = loader._loadAttributesAsTypedArray;
  1214. // Load the index buffer as a typed array to generate wireframes in WebGL1.
  1215. const loadForWireframe =
  1216. loader._loadIndicesForWireframe && !frameState.context.webgl2;
  1217. // Load the index buffer as a typed array to batch features together for classification.
  1218. const loadForClassification = loader._loadForClassification && hasFeatureIds;
  1219. // Whether the final output should be a buffer or typed array
  1220. // after loading and post-processing.
  1221. const outputTypedArrayOnly = loadAttributesAsTypedArray;
  1222. const outputBuffer = !outputTypedArrayOnly;
  1223. const outputTypedArray =
  1224. loadAttributesAsTypedArray || loadForWireframe || loadForClassification;
  1225. // Determine what to load right now:
  1226. //
  1227. // - If post-processing is needed, load a packed typed array for
  1228. // further processing, and defer the buffer loading until later.
  1229. // - On the other hand, if post-processing is not needed, set the load
  1230. // flags directly
  1231. const loadBuffer = needsPostProcessing ? false : outputBuffer;
  1232. const loadTypedArray = needsPostProcessing ? true : outputTypedArray;
  1233. const indexBufferLoader = getIndexBufferLoader(
  1234. loader,
  1235. gltf,
  1236. accessorId,
  1237. draco,
  1238. loadBuffer,
  1239. loadTypedArray,
  1240. frameState
  1241. );
  1242. const index = loader._geometryLoaders.length;
  1243. loader._geometryLoaders.push(indexBufferLoader);
  1244. const promise = indexBufferLoader.load();
  1245. loader._loaderPromises.push(promise);
  1246. // This can only execute once indexBufferLoader.process() has run and returns true
  1247. // Save this finish callback by the loader index so it can be called
  1248. // in process().
  1249. loader._geometryCallbacks[index] = () => {
  1250. indices.indexDatatype = indexBufferLoader.indexDatatype;
  1251. indices.buffer = indexBufferLoader.buffer;
  1252. indices.typedArray = indexBufferLoader.typedArray;
  1253. };
  1254. const indicesPlan = new PrimitiveLoadPlan.IndicesLoadPlan(indices);
  1255. indicesPlan.loadBuffer = outputBuffer;
  1256. indicesPlan.loadTypedArray = outputTypedArray;
  1257. return indicesPlan;
  1258. }
  1259. function loadTexture(
  1260. loader,
  1261. gltf,
  1262. textureInfo,
  1263. supportedImageFormats,
  1264. frameState,
  1265. samplerOverride
  1266. ) {
  1267. const imageId = GltfLoaderUtil.getImageIdFromTexture({
  1268. gltf: gltf,
  1269. textureId: textureInfo.index,
  1270. supportedImageFormats: supportedImageFormats,
  1271. });
  1272. if (!defined(imageId)) {
  1273. return undefined;
  1274. }
  1275. const textureLoader = ResourceCache.getTextureLoader({
  1276. gltf: gltf,
  1277. textureInfo: textureInfo,
  1278. gltfResource: loader._gltfResource,
  1279. baseResource: loader._baseResource,
  1280. supportedImageFormats: supportedImageFormats,
  1281. frameState: frameState,
  1282. asynchronous: loader._asynchronous,
  1283. });
  1284. const textureReader = GltfLoaderUtil.createModelTextureReader({
  1285. textureInfo: textureInfo,
  1286. });
  1287. const index = loader._textureLoaders.length;
  1288. loader._textureLoaders.push(textureLoader);
  1289. const promise = textureLoader.load().catch((error) => {
  1290. if (loader.isDestroyed()) {
  1291. return;
  1292. }
  1293. if (!loader._incrementallyLoadTextures) {
  1294. // If incrementallyLoadTextures is false, throw the error to ensure the loader state
  1295. // immediately is set to have failed
  1296. throw error;
  1297. }
  1298. // Otherwise, save the error so it can be thrown next
  1299. loader._textureState = GltfLoaderState.FAILED;
  1300. loader._textureErrors.push(error);
  1301. });
  1302. loader._texturesPromises.push(promise);
  1303. // This can only execute once textureLoader.process() has run and returns true
  1304. // Save this finish callback by the loader index so it can be called
  1305. // in process().
  1306. loader._textureCallbacks[index] = () => {
  1307. textureReader.texture = textureLoader.texture;
  1308. if (defined(samplerOverride)) {
  1309. textureReader.texture.sampler = samplerOverride;
  1310. }
  1311. };
  1312. return textureReader;
  1313. }
  1314. function loadMaterial(
  1315. loader,
  1316. gltf,
  1317. gltfMaterial,
  1318. supportedImageFormats,
  1319. frameState
  1320. ) {
  1321. const material = new Material();
  1322. const extensions = defaultValue(
  1323. gltfMaterial.extensions,
  1324. defaultValue.EMPTY_OBJECT
  1325. );
  1326. const pbrSpecularGlossiness = extensions.KHR_materials_pbrSpecularGlossiness;
  1327. const pbrMetallicRoughness = gltfMaterial.pbrMetallicRoughness;
  1328. material.unlit = defined(extensions.KHR_materials_unlit);
  1329. if (defined(pbrSpecularGlossiness)) {
  1330. const specularGlossiness = new SpecularGlossiness();
  1331. material.specularGlossiness = specularGlossiness;
  1332. if (defined(pbrSpecularGlossiness.diffuseTexture)) {
  1333. specularGlossiness.diffuseTexture = loadTexture(
  1334. loader,
  1335. gltf,
  1336. pbrSpecularGlossiness.diffuseTexture,
  1337. supportedImageFormats,
  1338. frameState
  1339. );
  1340. }
  1341. if (defined(pbrSpecularGlossiness.specularGlossinessTexture)) {
  1342. if (defined(pbrSpecularGlossiness.specularGlossinessTexture)) {
  1343. specularGlossiness.specularGlossinessTexture = loadTexture(
  1344. loader,
  1345. gltf,
  1346. pbrSpecularGlossiness.specularGlossinessTexture,
  1347. supportedImageFormats,
  1348. frameState
  1349. );
  1350. }
  1351. }
  1352. specularGlossiness.diffuseFactor = fromArray(
  1353. Cartesian4,
  1354. pbrSpecularGlossiness.diffuseFactor
  1355. );
  1356. specularGlossiness.specularFactor = fromArray(
  1357. Cartesian3,
  1358. pbrSpecularGlossiness.specularFactor
  1359. );
  1360. specularGlossiness.glossinessFactor =
  1361. pbrSpecularGlossiness.glossinessFactor;
  1362. material.pbrSpecularGlossiness = pbrSpecularGlossiness;
  1363. } else if (defined(pbrMetallicRoughness)) {
  1364. const metallicRoughness = new MetallicRoughness();
  1365. if (defined(pbrMetallicRoughness.baseColorTexture)) {
  1366. metallicRoughness.baseColorTexture = loadTexture(
  1367. loader,
  1368. gltf,
  1369. pbrMetallicRoughness.baseColorTexture,
  1370. supportedImageFormats,
  1371. frameState
  1372. );
  1373. }
  1374. if (defined(pbrMetallicRoughness.metallicRoughnessTexture)) {
  1375. metallicRoughness.metallicRoughnessTexture = loadTexture(
  1376. loader,
  1377. gltf,
  1378. pbrMetallicRoughness.metallicRoughnessTexture,
  1379. supportedImageFormats,
  1380. frameState
  1381. );
  1382. }
  1383. metallicRoughness.baseColorFactor = fromArray(
  1384. Cartesian4,
  1385. pbrMetallicRoughness.baseColorFactor
  1386. );
  1387. metallicRoughness.metallicFactor = pbrMetallicRoughness.metallicFactor;
  1388. metallicRoughness.roughnessFactor = pbrMetallicRoughness.roughnessFactor;
  1389. material.metallicRoughness = metallicRoughness;
  1390. }
  1391. // Top level textures
  1392. if (defined(gltfMaterial.emissiveTexture)) {
  1393. material.emissiveTexture = loadTexture(
  1394. loader,
  1395. gltf,
  1396. gltfMaterial.emissiveTexture,
  1397. supportedImageFormats,
  1398. frameState
  1399. );
  1400. }
  1401. // Normals aren't used for classification, so don't load the normal texture.
  1402. if (defined(gltfMaterial.normalTexture) && !loader._loadForClassification) {
  1403. material.normalTexture = loadTexture(
  1404. loader,
  1405. gltf,
  1406. gltfMaterial.normalTexture,
  1407. supportedImageFormats,
  1408. frameState
  1409. );
  1410. }
  1411. if (defined(gltfMaterial.occlusionTexture)) {
  1412. material.occlusionTexture = loadTexture(
  1413. loader,
  1414. gltf,
  1415. gltfMaterial.occlusionTexture,
  1416. supportedImageFormats,
  1417. frameState
  1418. );
  1419. }
  1420. material.emissiveFactor = fromArray(Cartesian3, gltfMaterial.emissiveFactor);
  1421. material.alphaMode = gltfMaterial.alphaMode;
  1422. material.alphaCutoff = gltfMaterial.alphaCutoff;
  1423. material.doubleSided = gltfMaterial.doubleSided;
  1424. return material;
  1425. }
  1426. // for EXT_mesh_features
  1427. function loadFeatureIdAttribute(featureIds, positionalLabel) {
  1428. const featureIdAttribute = new FeatureIdAttribute();
  1429. featureIdAttribute.featureCount = featureIds.featureCount;
  1430. featureIdAttribute.nullFeatureId = featureIds.nullFeatureId;
  1431. featureIdAttribute.propertyTableId = featureIds.propertyTable;
  1432. featureIdAttribute.setIndex = featureIds.attribute;
  1433. featureIdAttribute.label = featureIds.label;
  1434. featureIdAttribute.positionalLabel = positionalLabel;
  1435. return featureIdAttribute;
  1436. }
  1437. // for backwards compatibility with EXT_feature_metadata
  1438. function loadFeatureIdAttributeLegacy(
  1439. gltfFeatureIdAttribute,
  1440. featureTableId,
  1441. featureCount,
  1442. positionalLabel
  1443. ) {
  1444. const featureIdAttribute = new FeatureIdAttribute();
  1445. const featureIds = gltfFeatureIdAttribute.featureIds;
  1446. featureIdAttribute.featureCount = featureCount;
  1447. featureIdAttribute.propertyTableId = featureTableId;
  1448. featureIdAttribute.setIndex = getSetIndex(featureIds.attribute);
  1449. featureIdAttribute.positionalLabel = positionalLabel;
  1450. return featureIdAttribute;
  1451. }
  1452. // implicit ranges do not exist in EXT_mesh_features and EXT_instance_features,
  1453. // but both default to the vertex/instance ID which is like
  1454. // an implicit range of {offset: 0, repeat: 1}
  1455. function loadDefaultFeatureIds(featureIds, positionalLabel) {
  1456. const featureIdRange = new FeatureIdImplicitRange();
  1457. featureIdRange.propertyTableId = featureIds.propertyTable;
  1458. featureIdRange.featureCount = featureIds.featureCount;
  1459. featureIdRange.nullFeatureId = featureIds.nullFeatureId;
  1460. featureIdRange.label = featureIds.label;
  1461. featureIdRange.positionalLabel = positionalLabel;
  1462. featureIdRange.offset = 0;
  1463. featureIdRange.repeat = 1;
  1464. return featureIdRange;
  1465. }
  1466. // for backwards compatibility with EXT_feature_metadata
  1467. function loadFeatureIdImplicitRangeLegacy(
  1468. gltfFeatureIdAttribute,
  1469. featureTableId,
  1470. featureCount,
  1471. positionalLabel
  1472. ) {
  1473. const featureIdRange = new FeatureIdImplicitRange();
  1474. const featureIds = gltfFeatureIdAttribute.featureIds;
  1475. featureIdRange.propertyTableId = featureTableId;
  1476. featureIdRange.featureCount = featureCount;
  1477. // constant/divisor was renamed to offset/repeat
  1478. featureIdRange.offset = defaultValue(featureIds.constant, 0);
  1479. // The default is now undefined
  1480. const divisor = defaultValue(featureIds.divisor, 0);
  1481. featureIdRange.repeat = divisor === 0 ? undefined : divisor;
  1482. featureIdRange.positionalLabel = positionalLabel;
  1483. return featureIdRange;
  1484. }
  1485. // for EXT_mesh_features
  1486. function loadFeatureIdTexture(
  1487. loader,
  1488. gltf,
  1489. gltfFeatureIdTexture,
  1490. supportedImageFormats,
  1491. frameState,
  1492. positionalLabel
  1493. ) {
  1494. const featureIdTexture = new FeatureIdTexture();
  1495. featureIdTexture.featureCount = gltfFeatureIdTexture.featureCount;
  1496. featureIdTexture.nullFeatureId = gltfFeatureIdTexture.nullFeatureId;
  1497. featureIdTexture.propertyTableId = gltfFeatureIdTexture.propertyTable;
  1498. featureIdTexture.label = gltfFeatureIdTexture.label;
  1499. featureIdTexture.positionalLabel = positionalLabel;
  1500. const textureInfo = gltfFeatureIdTexture.texture;
  1501. featureIdTexture.textureReader = loadTexture(
  1502. loader,
  1503. gltf,
  1504. textureInfo,
  1505. supportedImageFormats,
  1506. frameState,
  1507. Sampler.NEAREST // Feature ID textures require nearest sampling
  1508. );
  1509. // Though the new channel index is more future-proof, this implementation
  1510. // only supports RGBA textures. At least for now, the string representation
  1511. // is more useful for generating shader code.
  1512. const channels = defined(textureInfo.channels) ? textureInfo.channels : [0];
  1513. const channelString = channels
  1514. .map(function (channelIndex) {
  1515. return "rgba".charAt(channelIndex);
  1516. })
  1517. .join("");
  1518. featureIdTexture.textureReader.channels = channelString;
  1519. return featureIdTexture;
  1520. }
  1521. // for backwards compatibility with EXT_feature_metadata
  1522. function loadFeatureIdTextureLegacy(
  1523. loader,
  1524. gltf,
  1525. gltfFeatureIdTexture,
  1526. featureTableId,
  1527. supportedImageFormats,
  1528. frameState,
  1529. featureCount,
  1530. positionalLabel
  1531. ) {
  1532. const featureIdTexture = new FeatureIdTexture();
  1533. const featureIds = gltfFeatureIdTexture.featureIds;
  1534. const textureInfo = featureIds.texture;
  1535. featureIdTexture.featureCount = featureCount;
  1536. featureIdTexture.propertyTableId = featureTableId;
  1537. featureIdTexture.textureReader = loadTexture(
  1538. loader,
  1539. gltf,
  1540. textureInfo,
  1541. supportedImageFormats,
  1542. frameState,
  1543. Sampler.NEAREST // Feature ID textures require nearest sampling
  1544. );
  1545. featureIdTexture.textureReader.channels = featureIds.channels;
  1546. featureIdTexture.positionalLabel = positionalLabel;
  1547. return featureIdTexture;
  1548. }
  1549. function loadMorphTarget(
  1550. loader,
  1551. gltf,
  1552. target,
  1553. needsPostProcessing,
  1554. primitiveLoadPlan,
  1555. frameState
  1556. ) {
  1557. const morphTarget = new MorphTarget();
  1558. // Don't pass in draco object since morph targets can't be draco compressed
  1559. const draco = undefined;
  1560. const hasInstances = false;
  1561. for (const semantic in target) {
  1562. if (target.hasOwnProperty(semantic)) {
  1563. const accessorId = target[semantic];
  1564. const semanticInfo = getSemanticInfo(
  1565. loader,
  1566. VertexAttributeSemantic,
  1567. semantic
  1568. );
  1569. const attributePlan = loadVertexAttribute(
  1570. loader,
  1571. gltf,
  1572. accessorId,
  1573. semanticInfo,
  1574. draco,
  1575. hasInstances,
  1576. needsPostProcessing,
  1577. frameState
  1578. );
  1579. morphTarget.attributes.push(attributePlan.attribute);
  1580. // The load plan doesn't need to distinguish morph target attributes from
  1581. // regular attributes
  1582. primitiveLoadPlan.attributePlans.push(attributePlan);
  1583. }
  1584. }
  1585. return morphTarget;
  1586. }
  1587. function loadPrimitive(
  1588. loader,
  1589. gltf,
  1590. gltfPrimitive,
  1591. hasInstances,
  1592. supportedImageFormats,
  1593. frameState
  1594. ) {
  1595. const primitive = new Primitive();
  1596. const primitivePlan = new PrimitiveLoadPlan(primitive);
  1597. loader._primitiveLoadPlans.push(primitivePlan);
  1598. const materialId = gltfPrimitive.material;
  1599. if (defined(materialId)) {
  1600. primitive.material = loadMaterial(
  1601. loader,
  1602. gltf,
  1603. gltf.materials[materialId],
  1604. supportedImageFormats,
  1605. frameState
  1606. );
  1607. }
  1608. const extensions = defaultValue(
  1609. gltfPrimitive.extensions,
  1610. defaultValue.EMPTY_OBJECT
  1611. );
  1612. let needsPostProcessing = false;
  1613. const outlineExtension = extensions.CESIUM_primitive_outline;
  1614. if (loader._loadPrimitiveOutline && defined(outlineExtension)) {
  1615. needsPostProcessing = true;
  1616. primitivePlan.needsOutlines = true;
  1617. primitivePlan.outlineIndices = loadPrimitiveOutline(
  1618. loader,
  1619. gltf,
  1620. outlineExtension,
  1621. primitivePlan
  1622. );
  1623. }
  1624. const loadForClassification = loader._loadForClassification;
  1625. const draco = extensions.KHR_draco_mesh_compression;
  1626. let hasFeatureIds = false;
  1627. const attributes = gltfPrimitive.attributes;
  1628. if (defined(attributes)) {
  1629. for (const semantic in attributes) {
  1630. if (attributes.hasOwnProperty(semantic)) {
  1631. const accessorId = attributes[semantic];
  1632. const semanticInfo = getSemanticInfo(
  1633. loader,
  1634. VertexAttributeSemantic,
  1635. semantic
  1636. );
  1637. const modelSemantic = semanticInfo.modelSemantic;
  1638. if (
  1639. loadForClassification &&
  1640. !isClassificationAttribute(modelSemantic)
  1641. ) {
  1642. continue;
  1643. }
  1644. if (modelSemantic === VertexAttributeSemantic.FEATURE_ID) {
  1645. hasFeatureIds = true;
  1646. }
  1647. const attributePlan = loadVertexAttribute(
  1648. loader,
  1649. gltf,
  1650. accessorId,
  1651. semanticInfo,
  1652. draco,
  1653. hasInstances,
  1654. needsPostProcessing,
  1655. frameState
  1656. );
  1657. primitivePlan.attributePlans.push(attributePlan);
  1658. primitive.attributes.push(attributePlan.attribute);
  1659. }
  1660. }
  1661. }
  1662. const targets = gltfPrimitive.targets;
  1663. // Morph targets are disabled for classification models.
  1664. if (defined(targets) && !loadForClassification) {
  1665. const targetsLength = targets.length;
  1666. for (let i = 0; i < targetsLength; ++i) {
  1667. primitive.morphTargets.push(
  1668. loadMorphTarget(
  1669. loader,
  1670. gltf,
  1671. targets[i],
  1672. needsPostProcessing,
  1673. primitivePlan,
  1674. frameState
  1675. )
  1676. );
  1677. }
  1678. }
  1679. const indices = gltfPrimitive.indices;
  1680. if (defined(indices)) {
  1681. const indicesPlan = loadIndices(
  1682. loader,
  1683. gltf,
  1684. indices,
  1685. draco,
  1686. hasFeatureIds,
  1687. needsPostProcessing,
  1688. frameState
  1689. );
  1690. if (defined(indicesPlan)) {
  1691. primitivePlan.indicesPlan = indicesPlan;
  1692. primitive.indices = indicesPlan.indices;
  1693. }
  1694. }
  1695. // With the latest revision, feature IDs are defined in EXT_mesh_features
  1696. // while EXT_structural_metadata is for defining property textures and
  1697. // property mappings. In the legacy EXT_feature_metadata, these concepts
  1698. // were all in one extension.
  1699. const structuralMetadata = extensions.EXT_structural_metadata;
  1700. const meshFeatures = extensions.EXT_mesh_features;
  1701. const featureMetadataLegacy = extensions.EXT_feature_metadata;
  1702. const hasFeatureMetadataLegacy = defined(featureMetadataLegacy);
  1703. // Load feature Ids
  1704. if (defined(meshFeatures)) {
  1705. loadPrimitiveFeatures(
  1706. loader,
  1707. gltf,
  1708. primitive,
  1709. meshFeatures,
  1710. supportedImageFormats,
  1711. frameState
  1712. );
  1713. } else if (hasFeatureMetadataLegacy) {
  1714. loadPrimitiveFeaturesLegacy(
  1715. loader,
  1716. gltf,
  1717. primitive,
  1718. featureMetadataLegacy,
  1719. supportedImageFormats,
  1720. frameState
  1721. );
  1722. }
  1723. // Load structural metadata
  1724. if (defined(structuralMetadata)) {
  1725. loadPrimitiveMetadata(primitive, structuralMetadata);
  1726. } else if (hasFeatureMetadataLegacy) {
  1727. loadPrimitiveMetadataLegacy(loader, primitive, featureMetadataLegacy);
  1728. }
  1729. const primitiveType = gltfPrimitive.mode;
  1730. if (loadForClassification && primitiveType !== PrimitiveType.TRIANGLES) {
  1731. throw new RuntimeError(
  1732. "Only triangle meshes can be used for classification."
  1733. );
  1734. }
  1735. primitive.primitiveType = primitiveType;
  1736. return primitive;
  1737. }
  1738. function loadPrimitiveOutline(loader, gltf, outlineExtension) {
  1739. const accessorId = outlineExtension.indices;
  1740. const useQuaternion = false;
  1741. return loadAccessor(loader, gltf, accessorId, useQuaternion);
  1742. }
  1743. // For EXT_mesh_features
  1744. function loadPrimitiveFeatures(
  1745. loader,
  1746. gltf,
  1747. primitive,
  1748. meshFeaturesExtension,
  1749. supportedImageFormats,
  1750. frameState
  1751. ) {
  1752. let featureIdsArray;
  1753. if (
  1754. defined(meshFeaturesExtension) &&
  1755. defined(meshFeaturesExtension.featureIds)
  1756. ) {
  1757. featureIdsArray = meshFeaturesExtension.featureIds;
  1758. } else {
  1759. featureIdsArray = [];
  1760. }
  1761. for (let i = 0; i < featureIdsArray.length; i++) {
  1762. const featureIds = featureIdsArray[i];
  1763. const label = `featureId_${i}`;
  1764. let featureIdComponent;
  1765. if (defined(featureIds.texture)) {
  1766. featureIdComponent = loadFeatureIdTexture(
  1767. loader,
  1768. gltf,
  1769. featureIds,
  1770. supportedImageFormats,
  1771. frameState,
  1772. label
  1773. );
  1774. } else if (defined(featureIds.attribute)) {
  1775. featureIdComponent = loadFeatureIdAttribute(featureIds, label);
  1776. } else {
  1777. // default to vertex ID, in other words an implicit range with
  1778. // offset: 0, repeat: 1
  1779. featureIdComponent = loadDefaultFeatureIds(featureIds, label);
  1780. }
  1781. primitive.featureIds.push(featureIdComponent);
  1782. }
  1783. }
  1784. // For EXT_feature_metadata
  1785. function loadPrimitiveFeaturesLegacy(
  1786. loader,
  1787. gltf,
  1788. primitive,
  1789. metadataExtension,
  1790. supportedImageFormats,
  1791. frameState
  1792. ) {
  1793. // For looking up the featureCount for each set of feature IDs
  1794. const featureTables = gltf.extensions.EXT_feature_metadata.featureTables;
  1795. let nextFeatureIdIndex = 0;
  1796. // Feature ID Attributes
  1797. const featureIdAttributes = metadataExtension.featureIdAttributes;
  1798. if (defined(featureIdAttributes)) {
  1799. const featureIdAttributesLength = featureIdAttributes.length;
  1800. for (let i = 0; i < featureIdAttributesLength; ++i) {
  1801. const featureIdAttribute = featureIdAttributes[i];
  1802. const featureTableId = featureIdAttribute.featureTable;
  1803. const propertyTableId = loader._sortedPropertyTableIds.indexOf(
  1804. featureTableId
  1805. );
  1806. const featureCount = featureTables[featureTableId].count;
  1807. const label = `featureId_${nextFeatureIdIndex}`;
  1808. nextFeatureIdIndex++;
  1809. let featureIdComponent;
  1810. if (defined(featureIdAttribute.featureIds.attribute)) {
  1811. featureIdComponent = loadFeatureIdAttributeLegacy(
  1812. featureIdAttribute,
  1813. propertyTableId,
  1814. featureCount,
  1815. label
  1816. );
  1817. } else {
  1818. featureIdComponent = loadFeatureIdImplicitRangeLegacy(
  1819. featureIdAttribute,
  1820. propertyTableId,
  1821. featureCount,
  1822. label
  1823. );
  1824. }
  1825. primitive.featureIds.push(featureIdComponent);
  1826. }
  1827. }
  1828. // Feature ID Textures
  1829. const featureIdTextures = metadataExtension.featureIdTextures;
  1830. if (defined(featureIdTextures)) {
  1831. const featureIdTexturesLength = featureIdTextures.length;
  1832. for (let i = 0; i < featureIdTexturesLength; ++i) {
  1833. const featureIdTexture = featureIdTextures[i];
  1834. const featureTableId = featureIdTexture.featureTable;
  1835. const propertyTableId = loader._sortedPropertyTableIds.indexOf(
  1836. featureTableId
  1837. );
  1838. const featureCount = featureTables[featureTableId].count;
  1839. const featureIdLabel = `featureId_${nextFeatureIdIndex}`;
  1840. nextFeatureIdIndex++;
  1841. const featureIdComponent = loadFeatureIdTextureLegacy(
  1842. loader,
  1843. gltf,
  1844. featureIdTexture,
  1845. propertyTableId,
  1846. supportedImageFormats,
  1847. frameState,
  1848. featureCount,
  1849. featureIdLabel
  1850. );
  1851. // Feature ID textures are added after feature ID attributes in the list
  1852. primitive.featureIds.push(featureIdComponent);
  1853. }
  1854. }
  1855. }
  1856. // For primitive-level EXT_structural_metadata
  1857. function loadPrimitiveMetadata(primitive, structuralMetadataExtension) {
  1858. if (!defined(structuralMetadataExtension)) {
  1859. return;
  1860. }
  1861. // Property Textures
  1862. if (defined(structuralMetadataExtension.propertyTextures)) {
  1863. primitive.propertyTextureIds = structuralMetadataExtension.propertyTextures;
  1864. }
  1865. // Property Attributes
  1866. if (defined(structuralMetadataExtension.propertyAttributes)) {
  1867. primitive.propertyAttributeIds =
  1868. structuralMetadataExtension.propertyAttributes;
  1869. }
  1870. }
  1871. // For EXT_feature_metadata
  1872. function loadPrimitiveMetadataLegacy(loader, primitive, metadataExtension) {
  1873. // Feature Textures
  1874. if (defined(metadataExtension.featureTextures)) {
  1875. // feature textures are now identified by an integer index. To convert the
  1876. // string IDs to integers, find their place in the sorted list of feature
  1877. // table names
  1878. primitive.propertyTextureIds = metadataExtension.featureTextures.map(
  1879. function (id) {
  1880. return loader._sortedFeatureTextureIds.indexOf(id);
  1881. }
  1882. );
  1883. }
  1884. }
  1885. function loadInstances(loader, gltf, nodeExtensions, frameState) {
  1886. const instancingExtension = nodeExtensions.EXT_mesh_gpu_instancing;
  1887. const instances = new Instances();
  1888. const attributes = instancingExtension.attributes;
  1889. if (defined(attributes)) {
  1890. for (const semantic in attributes) {
  1891. if (attributes.hasOwnProperty(semantic)) {
  1892. const accessorId = attributes[semantic];
  1893. instances.attributes.push(
  1894. loadInstancedAttribute(
  1895. loader,
  1896. gltf,
  1897. accessorId,
  1898. attributes,
  1899. semantic,
  1900. frameState
  1901. )
  1902. );
  1903. }
  1904. }
  1905. }
  1906. const instancingExtExtensions = defaultValue(
  1907. instancingExtension.extensions,
  1908. defaultValue.EMPTY_OBJECT
  1909. );
  1910. const instanceFeatures = nodeExtensions.EXT_instance_features;
  1911. const featureMetadataLegacy = instancingExtExtensions.EXT_feature_metadata;
  1912. if (defined(instanceFeatures)) {
  1913. loadInstanceFeatures(instances, instanceFeatures);
  1914. } else if (defined(featureMetadataLegacy)) {
  1915. loadInstanceFeaturesLegacy(
  1916. gltf,
  1917. instances,
  1918. featureMetadataLegacy,
  1919. loader._sortedPropertyTableIds
  1920. );
  1921. }
  1922. return instances;
  1923. }
  1924. // For EXT_mesh_features
  1925. function loadInstanceFeatures(instances, instanceFeaturesExtension) {
  1926. // feature IDs are required in EXT_instance_features
  1927. const featureIdsArray = instanceFeaturesExtension.featureIds;
  1928. for (let i = 0; i < featureIdsArray.length; i++) {
  1929. const featureIds = featureIdsArray[i];
  1930. const label = `instanceFeatureId_${i}`;
  1931. let featureIdComponent;
  1932. if (defined(featureIds.attribute)) {
  1933. featureIdComponent = loadFeatureIdAttribute(featureIds, label);
  1934. } else {
  1935. // in EXT_instance_features, the default is to assign IDs by instance
  1936. // ID. This can be expressed with offset: 0, repeat: 1
  1937. featureIdComponent = loadDefaultFeatureIds(featureIds, label);
  1938. }
  1939. instances.featureIds.push(featureIdComponent);
  1940. }
  1941. }
  1942. // For backwards-compatibility with EXT_feature_metadata
  1943. function loadInstanceFeaturesLegacy(
  1944. gltf,
  1945. instances,
  1946. metadataExtension,
  1947. sortedPropertyTableIds
  1948. ) {
  1949. // For looking up the featureCount for each set of feature IDs
  1950. const featureTables = gltf.extensions.EXT_feature_metadata.featureTables;
  1951. const featureIdAttributes = metadataExtension.featureIdAttributes;
  1952. if (defined(featureIdAttributes)) {
  1953. const featureIdAttributesLength = featureIdAttributes.length;
  1954. for (let i = 0; i < featureIdAttributesLength; ++i) {
  1955. const featureIdAttribute = featureIdAttributes[i];
  1956. const featureTableId = featureIdAttribute.featureTable;
  1957. const propertyTableId = sortedPropertyTableIds.indexOf(featureTableId);
  1958. const featureCount = featureTables[featureTableId].count;
  1959. const label = `instanceFeatureId_${i}`;
  1960. let featureIdComponent;
  1961. if (defined(featureIdAttribute.featureIds.attribute)) {
  1962. featureIdComponent = loadFeatureIdAttributeLegacy(
  1963. featureIdAttribute,
  1964. propertyTableId,
  1965. featureCount,
  1966. label
  1967. );
  1968. } else {
  1969. featureIdComponent = loadFeatureIdImplicitRangeLegacy(
  1970. featureIdAttribute,
  1971. propertyTableId,
  1972. featureCount,
  1973. label
  1974. );
  1975. }
  1976. instances.featureIds.push(featureIdComponent);
  1977. }
  1978. }
  1979. }
  1980. function loadNode(loader, gltf, gltfNode, supportedImageFormats, frameState) {
  1981. const node = new Node();
  1982. node.name = gltfNode.name;
  1983. node.matrix = fromArray(Matrix4, gltfNode.matrix);
  1984. node.translation = fromArray(Cartesian3, gltfNode.translation);
  1985. node.rotation = fromArray(Quaternion, gltfNode.rotation);
  1986. node.scale = fromArray(Cartesian3, gltfNode.scale);
  1987. const nodeExtensions = defaultValue(
  1988. gltfNode.extensions,
  1989. defaultValue.EMPTY_OBJECT
  1990. );
  1991. const instancingExtension = nodeExtensions.EXT_mesh_gpu_instancing;
  1992. const articulationsExtension = nodeExtensions.AGI_articulations;
  1993. if (defined(instancingExtension)) {
  1994. if (loader._loadForClassification) {
  1995. throw new RuntimeError(
  1996. "Models with the EXT_mesh_gpu_instancing extension cannot be used for classification."
  1997. );
  1998. }
  1999. node.instances = loadInstances(loader, gltf, nodeExtensions, frameState);
  2000. }
  2001. if (defined(articulationsExtension)) {
  2002. node.articulationName = articulationsExtension.articulationName;
  2003. }
  2004. const meshId = gltfNode.mesh;
  2005. if (defined(meshId)) {
  2006. const mesh = gltf.meshes[meshId];
  2007. const primitives = mesh.primitives;
  2008. const primitivesLength = primitives.length;
  2009. for (let i = 0; i < primitivesLength; ++i) {
  2010. node.primitives.push(
  2011. loadPrimitive(
  2012. loader,
  2013. gltf,
  2014. primitives[i],
  2015. defined(node.instances),
  2016. supportedImageFormats,
  2017. frameState
  2018. )
  2019. );
  2020. }
  2021. // If the node has no weights array, it will look for the weights array provided
  2022. // by the mesh. If both are undefined, it will default to an array of zero weights.
  2023. const morphWeights = defaultValue(gltfNode.weights, mesh.weights);
  2024. const targets = node.primitives[0].morphTargets;
  2025. const targetsLength = targets.length;
  2026. // Since meshes are not stored as separate components, the mesh weights will still
  2027. // be stored at the node level.
  2028. node.morphWeights = defined(morphWeights)
  2029. ? morphWeights.slice()
  2030. : new Array(targetsLength).fill(0.0);
  2031. }
  2032. return node;
  2033. }
  2034. function loadNodes(loader, gltf, supportedImageFormats, frameState) {
  2035. if (!defined(gltf.nodes)) {
  2036. return [];
  2037. }
  2038. let i;
  2039. let j;
  2040. const nodesLength = gltf.nodes.length;
  2041. const nodes = new Array(nodesLength);
  2042. for (i = 0; i < nodesLength; ++i) {
  2043. const node = loadNode(
  2044. loader,
  2045. gltf,
  2046. gltf.nodes[i],
  2047. supportedImageFormats,
  2048. frameState
  2049. );
  2050. node.index = i;
  2051. nodes[i] = node;
  2052. }
  2053. for (i = 0; i < nodesLength; ++i) {
  2054. const childrenNodeIds = gltf.nodes[i].children;
  2055. if (defined(childrenNodeIds)) {
  2056. const childrenLength = childrenNodeIds.length;
  2057. for (j = 0; j < childrenLength; ++j) {
  2058. nodes[i].children.push(nodes[childrenNodeIds[j]]);
  2059. }
  2060. }
  2061. }
  2062. return nodes;
  2063. }
  2064. function loadSkin(loader, gltf, gltfSkin, nodes) {
  2065. const skin = new Skin();
  2066. const jointIds = gltfSkin.joints;
  2067. const jointsLength = jointIds.length;
  2068. const joints = new Array(jointsLength);
  2069. for (let i = 0; i < jointsLength; ++i) {
  2070. joints[i] = nodes[jointIds[i]];
  2071. }
  2072. skin.joints = joints;
  2073. const inverseBindMatricesAccessorId = gltfSkin.inverseBindMatrices;
  2074. if (defined(inverseBindMatricesAccessorId)) {
  2075. skin.inverseBindMatrices = loadAccessor(
  2076. loader,
  2077. gltf,
  2078. inverseBindMatricesAccessorId
  2079. );
  2080. } else {
  2081. skin.inverseBindMatrices = new Array(jointsLength).fill(Matrix4.IDENTITY);
  2082. }
  2083. return skin;
  2084. }
  2085. function loadSkins(loader, gltf, nodes) {
  2086. const gltfSkins = gltf.skins;
  2087. // Skins are disabled for classification models.
  2088. if (loader._loadForClassification || !defined(gltfSkins)) {
  2089. return [];
  2090. }
  2091. const skinsLength = gltf.skins.length;
  2092. const skins = new Array(skinsLength);
  2093. for (let i = 0; i < skinsLength; ++i) {
  2094. const skin = loadSkin(loader, gltf, gltf.skins[i], nodes);
  2095. skin.index = i;
  2096. skins[i] = skin;
  2097. }
  2098. const nodesLength = nodes.length;
  2099. for (let i = 0; i < nodesLength; ++i) {
  2100. const skinId = gltf.nodes[i].skin;
  2101. if (defined(skinId)) {
  2102. nodes[i].skin = skins[skinId];
  2103. }
  2104. }
  2105. return skins;
  2106. }
  2107. async function loadStructuralMetadata(
  2108. loader,
  2109. gltf,
  2110. extension,
  2111. extensionLegacy,
  2112. supportedImageFormats,
  2113. frameState
  2114. ) {
  2115. const structuralMetadataLoader = new GltfStructuralMetadataLoader({
  2116. gltf: gltf,
  2117. extension: extension,
  2118. extensionLegacy: extensionLegacy,
  2119. gltfResource: loader._gltfResource,
  2120. baseResource: loader._baseResource,
  2121. supportedImageFormats: supportedImageFormats,
  2122. frameState: frameState,
  2123. asynchronous: loader._asynchronous,
  2124. });
  2125. loader._structuralMetadataLoader = structuralMetadataLoader;
  2126. return structuralMetadataLoader.load();
  2127. }
  2128. function loadAnimationSampler(loader, gltf, gltfSampler) {
  2129. const animationSampler = new AnimationSampler();
  2130. const inputAccessorId = gltfSampler.input;
  2131. animationSampler.input = loadAccessor(loader, gltf, inputAccessorId);
  2132. const gltfInterpolation = gltfSampler.interpolation;
  2133. animationSampler.interpolation = defaultValue(
  2134. InterpolationType[gltfInterpolation],
  2135. InterpolationType.LINEAR
  2136. );
  2137. const outputAccessorId = gltfSampler.output;
  2138. animationSampler.output = loadAccessor(loader, gltf, outputAccessorId, true);
  2139. return animationSampler;
  2140. }
  2141. function loadAnimationTarget(gltfTarget, nodes) {
  2142. const animationTarget = new AnimationTarget();
  2143. const nodeIndex = gltfTarget.node;
  2144. // If the node isn't defined, the animation channel should be ignored.
  2145. // It's easiest to signal this by returning undefined.
  2146. if (!defined(nodeIndex)) {
  2147. return undefined;
  2148. }
  2149. animationTarget.node = nodes[nodeIndex];
  2150. const path = gltfTarget.path.toUpperCase();
  2151. animationTarget.path = AnimatedPropertyType[path];
  2152. return animationTarget;
  2153. }
  2154. function loadAnimationChannel(gltfChannel, samplers, nodes) {
  2155. const animationChannel = new AnimationChannel();
  2156. const samplerIndex = gltfChannel.sampler;
  2157. animationChannel.sampler = samplers[samplerIndex];
  2158. animationChannel.target = loadAnimationTarget(gltfChannel.target, nodes);
  2159. return animationChannel;
  2160. }
  2161. function loadAnimation(loader, gltf, gltfAnimation, nodes) {
  2162. let i;
  2163. const animation = new Animation();
  2164. animation.name = gltfAnimation.name;
  2165. const gltfSamplers = gltfAnimation.samplers;
  2166. const samplersLength = gltfSamplers.length;
  2167. const samplers = new Array(samplersLength);
  2168. for (i = 0; i < samplersLength; i++) {
  2169. const sampler = loadAnimationSampler(loader, gltf, gltfSamplers[i]);
  2170. sampler.index = i;
  2171. samplers[i] = sampler;
  2172. }
  2173. const gltfChannels = gltfAnimation.channels;
  2174. const channelsLength = gltfChannels.length;
  2175. const channels = new Array(channelsLength);
  2176. for (i = 0; i < channelsLength; i++) {
  2177. channels[i] = loadAnimationChannel(gltfChannels[i], samplers, nodes);
  2178. }
  2179. animation.samplers = samplers;
  2180. animation.channels = channels;
  2181. return animation;
  2182. }
  2183. function loadAnimations(loader, gltf, nodes) {
  2184. const gltfAnimations = gltf.animations;
  2185. // Animations are disabled for classification models.
  2186. if (loader._loadForClassification || !defined(gltfAnimations)) {
  2187. return [];
  2188. }
  2189. const animationsLength = gltf.animations.length;
  2190. const animations = new Array(animationsLength);
  2191. for (let i = 0; i < animationsLength; ++i) {
  2192. const animation = loadAnimation(loader, gltf, gltf.animations[i], nodes);
  2193. animation.index = i;
  2194. animations[i] = animation;
  2195. }
  2196. return animations;
  2197. }
  2198. function loadArticulationStage(gltfStage) {
  2199. const stage = new ArticulationStage();
  2200. stage.name = gltfStage.name;
  2201. const type = gltfStage.type.toUpperCase();
  2202. stage.type = ArticulationStageType[type];
  2203. stage.minimumValue = gltfStage.minimumValue;
  2204. stage.maximumValue = gltfStage.maximumValue;
  2205. stage.initialValue = gltfStage.initialValue;
  2206. return stage;
  2207. }
  2208. function loadArticulation(gltfArticulation) {
  2209. const articulation = new Articulation();
  2210. articulation.name = gltfArticulation.name;
  2211. const gltfStages = gltfArticulation.stages;
  2212. const gltfStagesLength = gltfStages.length;
  2213. const stages = new Array(gltfStagesLength);
  2214. for (let i = 0; i < gltfStagesLength; i++) {
  2215. const stage = loadArticulationStage(gltfStages[i]);
  2216. stages[i] = stage;
  2217. }
  2218. articulation.stages = stages;
  2219. return articulation;
  2220. }
  2221. function loadArticulations(gltf) {
  2222. const extensions = defaultValue(gltf.extensions, defaultValue.EMPTY_OBJECT);
  2223. const articulationsExtension = extensions.AGI_articulations;
  2224. if (!defined(articulationsExtension)) {
  2225. return [];
  2226. }
  2227. const gltfArticulations = articulationsExtension.articulations;
  2228. if (!defined(gltfArticulations)) {
  2229. return [];
  2230. }
  2231. const gltfArticulationsLength = gltfArticulations.length;
  2232. const articulations = new Array(gltfArticulationsLength);
  2233. for (let i = 0; i < gltfArticulationsLength; i++) {
  2234. const articulation = loadArticulation(gltfArticulations[i]);
  2235. articulations[i] = articulation;
  2236. }
  2237. return articulations;
  2238. }
  2239. function getSceneNodeIds(gltf) {
  2240. let nodesIds;
  2241. if (defined(gltf.scenes) && defined(gltf.scene)) {
  2242. nodesIds = gltf.scenes[gltf.scene].nodes;
  2243. }
  2244. nodesIds = defaultValue(nodesIds, gltf.nodes);
  2245. nodesIds = defined(nodesIds) ? nodesIds : [];
  2246. return nodesIds;
  2247. }
  2248. function loadScene(gltf, nodes) {
  2249. const scene = new Scene();
  2250. const sceneNodeIds = getSceneNodeIds(gltf);
  2251. scene.nodes = sceneNodeIds.map(function (sceneNodeId) {
  2252. return nodes[sceneNodeId];
  2253. });
  2254. return scene;
  2255. }
  2256. const scratchCenter = new Cartesian3();
  2257. function parse(loader, gltf, supportedImageFormats, frameState) {
  2258. const extensions = defaultValue(gltf.extensions, defaultValue.EMPTY_OBJECT);
  2259. const structuralMetadataExtension = extensions.EXT_structural_metadata;
  2260. const featureMetadataExtensionLegacy = extensions.EXT_feature_metadata;
  2261. const cesiumRtcExtension = extensions.CESIUM_RTC;
  2262. if (defined(featureMetadataExtensionLegacy)) {
  2263. // If the old EXT_feature_metadata extension is present, sort the IDs of the
  2264. // feature tables and feature textures so we don't have to do this once
  2265. // per primitive.
  2266. //
  2267. // This must run before loadNodes so these IDs are available when
  2268. // attributes are processed.
  2269. const featureTables = featureMetadataExtensionLegacy.featureTables;
  2270. const featureTextures = featureMetadataExtensionLegacy.featureTextures;
  2271. const allPropertyTableIds = defined(featureTables) ? featureTables : [];
  2272. const allFeatureTextureIds = defined(featureTextures)
  2273. ? featureTextures
  2274. : [];
  2275. loader._sortedPropertyTableIds = Object.keys(allPropertyTableIds).sort();
  2276. loader._sortedFeatureTextureIds = Object.keys(allFeatureTextureIds).sort();
  2277. }
  2278. const nodes = loadNodes(loader, gltf, supportedImageFormats, frameState);
  2279. const skins = loadSkins(loader, gltf, nodes);
  2280. const animations = loadAnimations(loader, gltf, nodes);
  2281. const articulations = loadArticulations(gltf);
  2282. const scene = loadScene(gltf, nodes);
  2283. const components = new Components();
  2284. const asset = new Asset();
  2285. const copyright = gltf.asset.copyright;
  2286. if (defined(copyright)) {
  2287. const credits = copyright.split(";").map(function (string) {
  2288. return new Credit(string.trim());
  2289. });
  2290. asset.credits = credits;
  2291. }
  2292. components.asset = asset;
  2293. components.scene = scene;
  2294. components.nodes = nodes;
  2295. components.skins = skins;
  2296. components.animations = animations;
  2297. components.articulations = articulations;
  2298. components.upAxis = loader._upAxis;
  2299. components.forwardAxis = loader._forwardAxis;
  2300. if (defined(cesiumRtcExtension)) {
  2301. // CESIUM_RTC is almost always WGS84 coordinates so no axis conversion needed
  2302. const center = Cartesian3.fromArray(
  2303. cesiumRtcExtension.center,
  2304. 0,
  2305. scratchCenter
  2306. );
  2307. components.transform = Matrix4.fromTranslation(
  2308. center,
  2309. components.transform
  2310. );
  2311. }
  2312. loader._components = components;
  2313. // Load structural metadata (property tables and property textures)
  2314. if (
  2315. defined(structuralMetadataExtension) ||
  2316. defined(featureMetadataExtensionLegacy)
  2317. ) {
  2318. const promise = loadStructuralMetadata(
  2319. loader,
  2320. gltf,
  2321. structuralMetadataExtension,
  2322. featureMetadataExtensionLegacy,
  2323. supportedImageFormats,
  2324. frameState
  2325. );
  2326. loader._loaderPromises.push(promise);
  2327. }
  2328. // Gather promises and handle any errors
  2329. const readyPromises = [];
  2330. readyPromises.push.apply(readyPromises, loader._loaderPromises);
  2331. // When incrementallyLoadTextures is true, the errors are caught and thrown individually
  2332. // since it doesn't affect the overall loader state
  2333. if (!loader._incrementallyLoadTextures) {
  2334. readyPromises.push.apply(readyPromises, loader._texturesPromises);
  2335. }
  2336. return Promise.all(readyPromises);
  2337. }
  2338. function unloadTextures(loader) {
  2339. const textureLoaders = loader._textureLoaders;
  2340. const textureLoadersLength = textureLoaders.length;
  2341. for (let i = 0; i < textureLoadersLength; ++i) {
  2342. textureLoaders[i] =
  2343. !textureLoaders[i].isDestroyed() &&
  2344. ResourceCache.unload(textureLoaders[i]);
  2345. }
  2346. loader._textureLoaders.length = 0;
  2347. }
  2348. function unloadBufferViewLoaders(loader) {
  2349. const bufferViewLoaders = loader._bufferViewLoaders;
  2350. const bufferViewLoadersLength = bufferViewLoaders.length;
  2351. for (let i = 0; i < bufferViewLoadersLength; ++i) {
  2352. bufferViewLoaders[i] =
  2353. !bufferViewLoaders[i].isDestroyed() &&
  2354. ResourceCache.unload(bufferViewLoaders[i]);
  2355. }
  2356. loader._bufferViewLoaders.length = 0;
  2357. }
  2358. function unloadGeometry(loader) {
  2359. const geometryLoaders = loader._geometryLoaders;
  2360. const geometryLoadersLength = geometryLoaders.length;
  2361. for (let i = 0; i < geometryLoadersLength; ++i) {
  2362. geometryLoaders[i] =
  2363. !geometryLoaders[i].isDestroyed() &&
  2364. ResourceCache.unload(geometryLoaders[i]);
  2365. }
  2366. loader._geometryLoaders.length = 0;
  2367. }
  2368. function unloadGeneratedAttributes(loader) {
  2369. const buffers = loader._postProcessBuffers;
  2370. const length = buffers.length;
  2371. for (let i = 0; i < length; i++) {
  2372. const buffer = buffers[i];
  2373. if (!buffer.isDestroyed()) {
  2374. buffer.destroy();
  2375. }
  2376. }
  2377. buffers.length = 0;
  2378. }
  2379. function unloadStructuralMetadata(loader) {
  2380. if (
  2381. defined(loader._structuralMetadataLoader) &&
  2382. !loader._structuralMetadataLoader.isDestroyed()
  2383. ) {
  2384. loader._structuralMetadataLoader.destroy();
  2385. loader._structuralMetadataLoader = undefined;
  2386. }
  2387. }
  2388. /**
  2389. * Returns whether the resource has been unloaded.
  2390. * @private
  2391. */
  2392. GltfLoader.prototype.isUnloaded = function () {
  2393. return this._state === GltfLoaderState.UNLOADED;
  2394. };
  2395. /**
  2396. * Unloads the resource.
  2397. * @private
  2398. */
  2399. GltfLoader.prototype.unload = function () {
  2400. if (defined(this._gltfJsonLoader) && !this._gltfJsonLoader.isDestroyed()) {
  2401. ResourceCache.unload(this._gltfJsonLoader);
  2402. }
  2403. this._gltfJsonLoader = undefined;
  2404. unloadTextures(this);
  2405. unloadBufferViewLoaders(this);
  2406. unloadGeometry(this);
  2407. unloadGeneratedAttributes(this);
  2408. unloadStructuralMetadata(this);
  2409. this._components = undefined;
  2410. this._typedArray = undefined;
  2411. this._state = GltfLoaderState.UNLOADED;
  2412. };
  2413. export default GltfLoader;