babylon.glTFLoader.ts 72 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621
  1. /// <reference path="../../../../dist/preview release/babylon.d.ts"/>
  2. module BABYLON.GLTF2 {
  3. interface IFileRequestInfo extends IFileRequest {
  4. _lengthComputable?: boolean;
  5. _loaded?: number;
  6. _total?: number;
  7. }
  8. interface TypedArrayConstructor<T extends TypedArray> {
  9. readonly prototype: T;
  10. new(length: number): T;
  11. new(array: ArrayLike<number>): T;
  12. new(buffer: ArrayBuffer, byteOffset?: number, length?: number): T;
  13. readonly BYTES_PER_ELEMENT: number;
  14. }
  15. export class GLTFLoader implements IGLTFLoader {
  16. public _gltf: ILoaderGLTF;
  17. public _babylonScene: Scene;
  18. public _completePromises = new Array<Promise<void>>();
  19. private _disposed = false;
  20. private _state: Nullable<GLTFLoaderState> = null;
  21. private _extensions: { [name: string]: GLTFLoaderExtension } = {};
  22. private _rootUrl: string;
  23. private _rootBabylonMesh: Mesh;
  24. private _defaultSampler = {} as ILoaderSampler;
  25. private _progressCallback?: (event: SceneLoaderProgressEvent) => void;
  26. private _requests = new Array<IFileRequestInfo>();
  27. private static _Names = new Array<string>();
  28. private static _Factories: { [name: string]: (loader: GLTFLoader) => GLTFLoaderExtension } = {};
  29. public static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void {
  30. if (GLTFLoader._Factories[name]) {
  31. Tools.Error(`Extension with the name '${name}' already exists`);
  32. return;
  33. }
  34. GLTFLoader._Factories[name] = factory;
  35. // Keep the order of registration so that extensions registered first are called first.
  36. GLTFLoader._Names.push(name);
  37. }
  38. public coordinateSystemMode = GLTFLoaderCoordinateSystemMode.AUTO;
  39. public animationStartMode = GLTFLoaderAnimationStartMode.FIRST;
  40. public compileMaterials = false;
  41. public useClipPlane = false;
  42. public compileShadowGenerators = false;
  43. public readonly onDisposeObservable = new Observable<IGLTFLoader>();
  44. public readonly onMeshLoadedObservable = new Observable<AbstractMesh>();
  45. public readonly onTextureLoadedObservable = new Observable<BaseTexture>();
  46. public readonly onMaterialLoadedObservable = new Observable<Material>();
  47. public readonly onAnimationGroupLoadedObservable = new Observable<AnimationGroup>();
  48. public readonly onExtensionLoadedObservable = new Observable<IGLTFLoaderExtension>();
  49. public readonly onCompleteObservable = new Observable<IGLTFLoader>();
  50. public get state(): Nullable<GLTFLoaderState> {
  51. return this._state;
  52. }
  53. public dispose(): void {
  54. if (this._disposed) {
  55. return;
  56. }
  57. this._disposed = true;
  58. this.onDisposeObservable.notifyObservers(this);
  59. this.onDisposeObservable.clear();
  60. this._clear();
  61. }
  62. public importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{ meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[] }> {
  63. return Promise.resolve().then(() => {
  64. let nodes: Nullable<Array<ILoaderNode>> = null;
  65. if (meshesNames) {
  66. const nodeMap: { [name: string]: ILoaderNode } = {};
  67. if (this._gltf.nodes) {
  68. for (const node of this._gltf.nodes) {
  69. if (node.name) {
  70. nodeMap[node.name] = node;
  71. }
  72. }
  73. }
  74. const names = (meshesNames instanceof Array) ? meshesNames : [meshesNames];
  75. nodes = names.map(name => {
  76. const node = nodeMap[name];
  77. if (!node) {
  78. throw new Error(`Failed to find node '${name}'`);
  79. }
  80. return node;
  81. });
  82. }
  83. return this._loadAsync(nodes, scene, data, rootUrl, onProgress).then(() => {
  84. return {
  85. meshes: this._getMeshes(),
  86. particleSystems: [],
  87. skeletons: this._getSkeletons(),
  88. };
  89. });
  90. });
  91. }
  92. public loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void> {
  93. return this._loadAsync(null, scene, data, rootUrl, onProgress);
  94. }
  95. private _loadAsync(nodes: Nullable<Array<ILoaderNode>>, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void> {
  96. return Promise.resolve().then(() => {
  97. this._loadExtensions();
  98. this._babylonScene = scene;
  99. this._rootUrl = rootUrl;
  100. this._progressCallback = onProgress;
  101. this._state = GLTFLoaderState.Loading;
  102. this._loadData(data);
  103. this._checkExtensions();
  104. const promises = new Array<Promise<void>>();
  105. if (nodes) {
  106. promises.push(this._loadNodesAsync(nodes));
  107. }
  108. else {
  109. const scene = GLTFLoader._GetProperty(`#/scene`, this._gltf.scenes, this._gltf.scene || 0);
  110. promises.push(this._loadSceneAsync(`#/scenes/${scene._index}`, scene));
  111. }
  112. if (this.compileMaterials) {
  113. promises.push(this._compileMaterialsAsync());
  114. }
  115. if (this.compileShadowGenerators) {
  116. promises.push(this._compileShadowGeneratorsAsync());
  117. }
  118. const resultPromise = Promise.all(promises).then(() => {
  119. this._state = GLTFLoaderState.Ready;
  120. this._startAnimations();
  121. });
  122. resultPromise.then(() => {
  123. this._rootBabylonMesh.setEnabled(true);
  124. Tools.SetImmediate(() => {
  125. if (!this._disposed) {
  126. Promise.all(this._completePromises).then(() => {
  127. this._state = GLTFLoaderState.Complete;
  128. this.onCompleteObservable.notifyObservers(this);
  129. this.onCompleteObservable.clear();
  130. this._clear();
  131. }).catch(error => {
  132. Tools.Error(`glTF Loader: ${error.message}`);
  133. this._clear();
  134. });
  135. }
  136. });
  137. });
  138. return resultPromise;
  139. }).catch(error => {
  140. Tools.Error(`glTF Loader: ${error.message}`);
  141. this._clear();
  142. throw error;
  143. });
  144. }
  145. private _loadExtensions(): void {
  146. for (const name of GLTFLoader._Names) {
  147. const extension = GLTFLoader._Factories[name](this);
  148. this._extensions[name] = extension;
  149. this.onExtensionLoadedObservable.notifyObservers(extension);
  150. }
  151. this.onExtensionLoadedObservable.clear();
  152. }
  153. private _loadData(data: IGLTFLoaderData): void {
  154. this._gltf = data.json as ILoaderGLTF;
  155. this._setupData();
  156. if (data.bin) {
  157. const buffers = this._gltf.buffers;
  158. if (buffers && buffers[0] && !buffers[0].uri) {
  159. const binaryBuffer = buffers[0];
  160. if (binaryBuffer.byteLength < data.bin.byteLength - 3 || binaryBuffer.byteLength > data.bin.byteLength) {
  161. Tools.Warn(`Binary buffer length (${binaryBuffer.byteLength}) from JSON does not match chunk length (${data.bin.byteLength})`);
  162. }
  163. binaryBuffer._data = Promise.resolve(data.bin);
  164. }
  165. else {
  166. Tools.Warn("Unexpected BIN chunk");
  167. }
  168. }
  169. }
  170. private _setupData(): void {
  171. ArrayItem.Assign(this._gltf.accessors);
  172. ArrayItem.Assign(this._gltf.animations);
  173. ArrayItem.Assign(this._gltf.buffers);
  174. ArrayItem.Assign(this._gltf.bufferViews);
  175. ArrayItem.Assign(this._gltf.cameras);
  176. ArrayItem.Assign(this._gltf.images);
  177. ArrayItem.Assign(this._gltf.materials);
  178. ArrayItem.Assign(this._gltf.meshes);
  179. ArrayItem.Assign(this._gltf.nodes);
  180. ArrayItem.Assign(this._gltf.samplers);
  181. ArrayItem.Assign(this._gltf.scenes);
  182. ArrayItem.Assign(this._gltf.skins);
  183. ArrayItem.Assign(this._gltf.textures);
  184. if (this._gltf.nodes) {
  185. const nodeParents: { [index: number]: number } = {};
  186. for (const node of this._gltf.nodes) {
  187. if (node.children) {
  188. for (const index of node.children) {
  189. nodeParents[index] = node._index;
  190. }
  191. }
  192. }
  193. const rootNode = this._createRootNode();
  194. for (const node of this._gltf.nodes) {
  195. const parentIndex = nodeParents[node._index];
  196. node._parent = parentIndex === undefined ? rootNode : this._gltf.nodes[parentIndex];
  197. }
  198. }
  199. }
  200. private _checkExtensions(): void {
  201. if (this._gltf.extensionsRequired) {
  202. for (const name of this._gltf.extensionsRequired) {
  203. const extension = this._extensions[name];
  204. if (!extension || !extension.enabled) {
  205. throw new Error(`Require extension ${name} is not available`);
  206. }
  207. }
  208. }
  209. }
  210. private _createRootNode(): ILoaderNode {
  211. this._rootBabylonMesh = new Mesh("__root__", this._babylonScene);
  212. this._rootBabylonMesh.setEnabled(false);
  213. const rootNode = { _babylonMesh: this._rootBabylonMesh } as ILoaderNode;
  214. switch (this.coordinateSystemMode) {
  215. case GLTFLoaderCoordinateSystemMode.AUTO: {
  216. if (!this._babylonScene.useRightHandedSystem) {
  217. rootNode.rotation = [0, 1, 0, 0];
  218. rootNode.scale = [1, 1, -1];
  219. GLTFLoader._LoadTransform(rootNode, this._rootBabylonMesh);
  220. }
  221. break;
  222. }
  223. case GLTFLoaderCoordinateSystemMode.FORCE_RIGHT_HANDED: {
  224. this._babylonScene.useRightHandedSystem = true;
  225. break;
  226. }
  227. default: {
  228. throw new Error(`Invalid coordinate system mode (${this.coordinateSystemMode})`);
  229. }
  230. }
  231. this.onMeshLoadedObservable.notifyObservers(this._rootBabylonMesh);
  232. return rootNode;
  233. }
  234. private _loadNodesAsync(nodes: ILoaderNode[], ): Promise<void> {
  235. const promises = new Array<Promise<void>>();
  236. for (let node of nodes) {
  237. promises.push(this._loadNodeAsync(`#/nodes/${node._index}`, node));
  238. }
  239. promises.push(this._loadAnimationsAsync());
  240. return Promise.all(promises).then(() => {});
  241. }
  242. public _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void> {
  243. const promise = GLTFLoaderExtension._LoadSceneAsync(this, context, scene);
  244. if (promise) {
  245. return promise;
  246. }
  247. const promises = new Array<Promise<void>>();
  248. for (let index of scene.nodes) {
  249. const node = GLTFLoader._GetProperty(`${context}/nodes/${index}`, this._gltf.nodes, index);
  250. promises.push(this._loadNodeAsync(`#/nodes/${node._index}`, node));
  251. }
  252. promises.push(this._loadAnimationsAsync());
  253. return Promise.all(promises).then(() => {});
  254. }
  255. private _forEachNodeMesh(node: ILoaderNode, callback: (babylonMesh: Mesh) => void): void {
  256. if (node._babylonMesh) {
  257. callback(node._babylonMesh);
  258. }
  259. if (node._primitiveBabylonMeshes) {
  260. for (const babylonMesh of node._primitiveBabylonMeshes) {
  261. callback(babylonMesh);
  262. }
  263. }
  264. }
  265. private _getMeshes(): Mesh[] {
  266. const meshes = new Array<Mesh>();
  267. // Root mesh is always first.
  268. meshes.push(this._rootBabylonMesh);
  269. const nodes = this._gltf.nodes;
  270. if (nodes) {
  271. for (const node of nodes) {
  272. this._forEachNodeMesh(node, mesh => {
  273. meshes.push(mesh);
  274. });
  275. }
  276. }
  277. return meshes;
  278. }
  279. private _getSkeletons(): Skeleton[] {
  280. const skeletons = new Array<Skeleton>();
  281. const skins = this._gltf.skins;
  282. if (skins) {
  283. for (const skin of skins) {
  284. if (skin._babylonSkeleton) {
  285. skeletons.push(skin._babylonSkeleton);
  286. }
  287. }
  288. }
  289. return skeletons;
  290. }
  291. private _startAnimations(): void {
  292. const animations = this._gltf.animations;
  293. if (!animations) {
  294. return;
  295. }
  296. switch (this.animationStartMode) {
  297. case GLTFLoaderAnimationStartMode.NONE: {
  298. // do nothing
  299. break;
  300. }
  301. case GLTFLoaderAnimationStartMode.FIRST: {
  302. const animation = animations[0];
  303. animation._babylonAnimationGroup!.start(true);
  304. break;
  305. }
  306. case GLTFLoaderAnimationStartMode.ALL: {
  307. for (const animation of animations) {
  308. animation._babylonAnimationGroup!.start(true);
  309. }
  310. break;
  311. }
  312. default: {
  313. Tools.Error(`Invalid animation start mode (${this.animationStartMode})`);
  314. return;
  315. }
  316. }
  317. }
  318. public _loadNodeAsync(context: string, node: ILoaderNode): Promise<void> {
  319. const promise = GLTFLoaderExtension._LoadNodeAsync(this, context, node);
  320. if (promise) {
  321. return promise;
  322. }
  323. if (node._babylonMesh) {
  324. throw new Error(`${context}: Invalid recursive node hierarchy`);
  325. }
  326. const promises = new Array<Promise<void>>();
  327. const babylonMesh = new Mesh(node.name || `node${node._index}`, this._babylonScene, node._parent._babylonMesh);
  328. node._babylonMesh = babylonMesh;
  329. node._babylonAnimationTargets = node._babylonAnimationTargets || [];
  330. node._babylonAnimationTargets.push(babylonMesh);
  331. GLTFLoader._LoadTransform(node, babylonMesh);
  332. if (node.mesh != undefined) {
  333. const mesh = GLTFLoader._GetProperty(`${context}/mesh`, this._gltf.meshes, node.mesh);
  334. promises.push(this._loadMeshAsync(`#/meshes/${mesh._index}`, node, mesh, babylonMesh));
  335. }
  336. if (node.children) {
  337. for (const index of node.children) {
  338. const childNode = GLTFLoader._GetProperty(`${context}/children/${index}`, this._gltf.nodes, index);
  339. promises.push(this._loadNodeAsync(`#/nodes/${index}`, childNode));
  340. }
  341. }
  342. this.onMeshLoadedObservable.notifyObservers(babylonMesh);
  343. return Promise.all(promises).then(() => {});
  344. }
  345. private _loadMeshAsync(context: string, node: ILoaderNode, mesh: ILoaderMesh, babylonMesh: Mesh): Promise<void> {
  346. // TODO: instancing
  347. const promises = new Array<Promise<void>>();
  348. const primitives = mesh.primitives;
  349. if (!primitives || primitives.length === 0) {
  350. throw new Error(`${context}: Primitives are missing`);
  351. }
  352. ArrayItem.Assign(primitives);
  353. if (primitives.length === 1) {
  354. const primitive = primitives[0];
  355. promises.push(this._loadPrimitiveAsync(`${context}/primitives/${primitive._index}`, node, mesh, primitive, babylonMesh));
  356. }
  357. else {
  358. node._primitiveBabylonMeshes = [];
  359. for (const primitive of primitives) {
  360. const primitiveBabylonMesh = new Mesh(`${mesh.name || babylonMesh.name}_${primitive._index}`, this._babylonScene, babylonMesh);
  361. node._primitiveBabylonMeshes.push(babylonMesh);
  362. promises.push(this._loadPrimitiveAsync(`${context}/primitives/${primitive._index}`, node, mesh, primitive, primitiveBabylonMesh));
  363. this.onMeshLoadedObservable.notifyObservers(babylonMesh);
  364. }
  365. }
  366. if (node.skin != undefined) {
  367. const skin = GLTFLoader._GetProperty(`${context}/skin`, this._gltf.skins, node.skin);
  368. promises.push(this._loadSkinAsync(`#/skins/${skin._index}`, node, mesh, skin));
  369. }
  370. return Promise.all(promises).then(() => {
  371. this._forEachNodeMesh(node, babylonMesh => {
  372. babylonMesh._refreshBoundingInfo(true);
  373. });
  374. });
  375. }
  376. private _loadPrimitiveAsync(context: string, node: ILoaderNode, mesh: ILoaderMesh, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Promise<void> {
  377. const promises = new Array<Promise<void>>();
  378. this._createMorphTargets(context, node, mesh, primitive, babylonMesh);
  379. promises.push(this._loadVertexDataAsync(context, primitive, babylonMesh).then(babylonVertexData => {
  380. new Geometry(babylonMesh.name, this._babylonScene, babylonVertexData, false, babylonMesh);
  381. return this._loadMorphTargetsAsync(context, primitive, babylonMesh, babylonVertexData);
  382. }));
  383. if (primitive.material == undefined) {
  384. babylonMesh.material = this._getDefaultMaterial();
  385. }
  386. else {
  387. const material = GLTFLoader._GetProperty(`${context}/material}`, this._gltf.materials, primitive.material);
  388. promises.push(this._loadMaterialAsync(`#/materials/${material._index}`, material, babylonMesh, babylonMaterial => {
  389. babylonMesh.material = babylonMaterial;
  390. }));
  391. }
  392. return Promise.all(promises).then(() => {});
  393. }
  394. private _loadVertexDataAsync(context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Promise<VertexData> {
  395. const promise = GLTFLoaderExtension._LoadVertexDataAsync(this, context, primitive, babylonMesh);
  396. if (promise) {
  397. return promise;
  398. }
  399. const attributes = primitive.attributes;
  400. if (!attributes) {
  401. throw new Error(`${context}: Attributes are missing`);
  402. }
  403. if (primitive.mode != undefined && primitive.mode !== MeshPrimitiveMode.TRIANGLES) {
  404. // TODO: handle other primitive modes
  405. throw new Error(`${context}: Mode (${primitive.mode}) is not currently supported`);
  406. }
  407. const promises = new Array<Promise<void>>();
  408. const babylonVertexData = new VertexData();
  409. if (primitive.indices == undefined) {
  410. const positionAccessorIndex = attributes["POSITION"];
  411. if (positionAccessorIndex != undefined) {
  412. const accessor = GLTFLoader._GetProperty(`${context}/attributes/POSITION`, this._gltf.accessors, positionAccessorIndex);
  413. babylonVertexData.indices = new Uint32Array(accessor.count);
  414. for (let i = 0; i < babylonVertexData.indices.length; i++) {
  415. babylonVertexData.indices[i] = i;
  416. }
  417. }
  418. }
  419. else {
  420. const indicesAccessor = GLTFLoader._GetProperty(`${context}/indices`, this._gltf.accessors, primitive.indices);
  421. promises.push(this._loadAccessorAsync(`#/accessors/${indicesAccessor._index}`, indicesAccessor).then(data => {
  422. babylonVertexData.indices = data as IndicesArray;
  423. }));
  424. }
  425. const loadAttribute = (attribute: string, kind: string) => {
  426. if (attributes[attribute] == undefined) {
  427. return;
  428. }
  429. babylonMesh._delayInfo = babylonMesh._delayInfo || [];
  430. if (babylonMesh._delayInfo.indexOf(kind) === -1) {
  431. babylonMesh._delayInfo.push(kind);
  432. }
  433. if (attribute === "COLOR_0") {
  434. // Assume vertex color has alpha on the mesh. The alphaMode of the material controls whether the material should use alpha or not.
  435. babylonMesh.hasVertexAlpha = true;
  436. }
  437. const accessor = GLTFLoader._GetProperty(`${context}/attributes/${attribute}`, this._gltf.accessors, attributes[attribute]);
  438. promises.push(this._loadAccessorAsync(`#/accessors/${accessor._index}`, accessor).then(data => {
  439. let attributeData = GLTFLoader._ConvertToFloat32Array(context, accessor, data);
  440. if (attribute === "COLOR_0" && accessor.type === "VEC3") {
  441. attributeData = GLTFLoader._ConvertVec3ToVec4(context, attributeData);
  442. }
  443. babylonVertexData.set(attributeData, kind);
  444. }));
  445. };
  446. loadAttribute("POSITION", VertexBuffer.PositionKind);
  447. loadAttribute("NORMAL", VertexBuffer.NormalKind);
  448. loadAttribute("TANGENT", VertexBuffer.TangentKind);
  449. loadAttribute("TEXCOORD_0", VertexBuffer.UVKind);
  450. loadAttribute("TEXCOORD_1", VertexBuffer.UV2Kind);
  451. loadAttribute("JOINTS_0", VertexBuffer.MatricesIndicesKind);
  452. loadAttribute("WEIGHTS_0", VertexBuffer.MatricesWeightsKind);
  453. loadAttribute("COLOR_0", VertexBuffer.ColorKind);
  454. return Promise.all(promises).then(() => {
  455. return babylonVertexData;
  456. });
  457. }
  458. private _createMorphTargets(context: string, node: ILoaderNode, mesh: ILoaderMesh, primitive: IMeshPrimitive, babylonMesh: Mesh): void {
  459. if (!primitive.targets) {
  460. return;
  461. }
  462. if (node._numMorphTargets == undefined) {
  463. node._numMorphTargets = primitive.targets.length;
  464. }
  465. else if (primitive.targets.length !== node._numMorphTargets) {
  466. throw new Error(`${context}: Primitives do not have the same number of targets`);
  467. }
  468. babylonMesh.morphTargetManager = new MorphTargetManager();
  469. for (let index = 0; index < primitive.targets.length; index++) {
  470. const weight = node.weights ? node.weights[index] : mesh.weights ? mesh.weights[index] : 0;
  471. babylonMesh.morphTargetManager.addTarget(new MorphTarget(`morphTarget${index}`, weight));
  472. // TODO: tell the target whether it has positions, normals, tangents
  473. }
  474. }
  475. private _loadMorphTargetsAsync(context: string, primitive: IMeshPrimitive, babylonMesh: Mesh, babylonVertexData: VertexData): Promise<void> {
  476. if (!primitive.targets) {
  477. return Promise.resolve();
  478. }
  479. const promises = new Array<Promise<void>>();
  480. const morphTargetManager = babylonMesh.morphTargetManager!;
  481. for (let index = 0; index < morphTargetManager.numTargets; index++) {
  482. const babylonMorphTarget = morphTargetManager.getTarget(index);
  483. promises.push(this._loadMorphTargetVertexDataAsync(`${context}/targets/${index}`, babylonVertexData, primitive.targets[index], babylonMorphTarget));
  484. }
  485. return Promise.all(promises).then(() => {});
  486. }
  487. private _loadMorphTargetVertexDataAsync(context: string, babylonVertexData: VertexData, attributes: { [name: string]: number }, babylonMorphTarget: MorphTarget): Promise<void> {
  488. const promises = new Array<Promise<void>>();
  489. const loadAttribute = (attribute: string, setData: (data: Float32Array) => void) => {
  490. if (attributes[attribute] == undefined) {
  491. return;
  492. }
  493. const accessor = GLTFLoader._GetProperty(`${context}/${attribute}`, this._gltf.accessors, attributes[attribute]);
  494. promises.push(this._loadAccessorAsync(`#/accessors/${accessor._index}`, accessor).then(data => {
  495. setData(data as Float32Array);
  496. }));
  497. };
  498. loadAttribute("POSITION", data => {
  499. if (babylonVertexData.positions) {
  500. for (let i = 0; i < data.length; i++) {
  501. data[i] += babylonVertexData.positions[i];
  502. }
  503. babylonMorphTarget.setPositions(data);
  504. }
  505. });
  506. loadAttribute("NORMAL", data => {
  507. if (babylonVertexData.normals) {
  508. for (let i = 0; i < data.length; i++) {
  509. data[i] += babylonVertexData.normals[i];
  510. }
  511. babylonMorphTarget.setNormals(data);
  512. }
  513. });
  514. loadAttribute("TANGENT", data => {
  515. if (babylonVertexData.tangents) {
  516. // Tangent data for morph targets is stored as xyz delta.
  517. // The vertexData.tangent is stored as xyzw.
  518. // So we need to skip every fourth vertexData.tangent.
  519. for (let i = 0, j = 0; i < data.length; i++) {
  520. data[i] += babylonVertexData.tangents[j++];
  521. if ((i + 1) % 3 == 0) {
  522. j++;
  523. }
  524. }
  525. babylonMorphTarget.setTangents(data);
  526. }
  527. });
  528. return Promise.all(promises).then(() => {});
  529. }
  530. private static _ConvertToFloat32Array(context: string, accessor: ILoaderAccessor, data: TypedArray): Float32Array {
  531. if (accessor.componentType == AccessorComponentType.FLOAT) {
  532. return data as Float32Array;
  533. }
  534. let factor = 1;
  535. if (accessor.normalized) {
  536. switch (accessor.componentType) {
  537. case AccessorComponentType.UNSIGNED_BYTE: {
  538. factor = 1 / 255;
  539. break;
  540. }
  541. case AccessorComponentType.UNSIGNED_SHORT: {
  542. factor = 1 / 65535;
  543. break;
  544. }
  545. default: {
  546. throw new Error(`${context}: Invalid component type (${accessor.componentType})`);
  547. }
  548. }
  549. }
  550. const result = new Float32Array(accessor.count * GLTFLoader._GetNumComponents(context, accessor.type));
  551. for (let i = 0; i < result.length; i++) {
  552. result[i] = data[i] * factor;
  553. }
  554. return result;
  555. }
  556. private static _ConvertVec3ToVec4(context: string, data: Float32Array): Float32Array {
  557. const result = new Float32Array(data.length / 3 * 4);
  558. let offset = 0;
  559. for (let i = 0; i < result.length; i++) {
  560. if ((i + 1) % 4 === 0) {
  561. result[i] = 1;
  562. }
  563. else {
  564. result[i] = data[offset++];
  565. }
  566. }
  567. return result;
  568. }
  569. private static _LoadTransform(node: ILoaderNode, babylonNode: TransformNode): void {
  570. let position = Vector3.Zero();
  571. let rotation = Quaternion.Identity();
  572. let scaling = Vector3.One();
  573. if (node.matrix) {
  574. const matrix = Matrix.FromArray(node.matrix);
  575. matrix.decompose(scaling, rotation, position);
  576. }
  577. else {
  578. if (node.translation) position = Vector3.FromArray(node.translation);
  579. if (node.rotation) rotation = Quaternion.FromArray(node.rotation);
  580. if (node.scale) scaling = Vector3.FromArray(node.scale);
  581. }
  582. babylonNode.position = position;
  583. babylonNode.rotationQuaternion = rotation;
  584. babylonNode.scaling = scaling;
  585. }
  586. private _loadSkinAsync(context: string, node: ILoaderNode, mesh: ILoaderMesh, skin: ILoaderSkin): Promise<void> {
  587. const assignSkeleton = () => {
  588. this._forEachNodeMesh(node, babylonMesh => {
  589. babylonMesh.skeleton = skin._babylonSkeleton;
  590. });
  591. node._babylonMesh!.parent = this._rootBabylonMesh;
  592. node._babylonMesh!.position = Vector3.Zero();
  593. node._babylonMesh!.rotationQuaternion = Quaternion.Identity();
  594. node._babylonMesh!.scaling = Vector3.One();
  595. };
  596. if (skin._loaded) {
  597. return skin._loaded.then(() => {
  598. assignSkeleton();
  599. });
  600. }
  601. // TODO: split into two parts so that bones are created before inverseBindMatricesData is loaded (for compiling materials).
  602. return (skin._loaded = this._loadSkinInverseBindMatricesDataAsync(context, skin).then(inverseBindMatricesData => {
  603. const skeletonId = `skeleton${skin._index}`;
  604. const babylonSkeleton = new Skeleton(skin.name || skeletonId, skeletonId, this._babylonScene);
  605. skin._babylonSkeleton = babylonSkeleton;
  606. this._loadBones(context, skin, inverseBindMatricesData);
  607. assignSkeleton();
  608. }));
  609. }
  610. private _loadSkinInverseBindMatricesDataAsync(context: string, skin: ILoaderSkin): Promise<Nullable<Float32Array>> {
  611. if (skin.inverseBindMatrices == undefined) {
  612. return Promise.resolve(null);
  613. }
  614. const accessor = GLTFLoader._GetProperty(`${context}/inverseBindMatrices`, this._gltf.accessors, skin.inverseBindMatrices);
  615. return this._loadAccessorAsync(`#/accessors/${accessor._index}`, accessor).then(data => {
  616. return data as Float32Array;
  617. });
  618. }
  619. private _createBone(node: ILoaderNode, skin: ILoaderSkin, parent: Nullable<Bone>, localMatrix: Matrix, baseMatrix: Matrix, index: number): Bone {
  620. const babylonBone = new Bone(node.name || `joint${node._index}`, skin._babylonSkeleton!, parent, localMatrix, null, baseMatrix, index);
  621. node._babylonAnimationTargets = node._babylonAnimationTargets || [];
  622. node._babylonAnimationTargets.push(babylonBone);
  623. return babylonBone;
  624. }
  625. private _loadBones(context: string, skin: ILoaderSkin, inverseBindMatricesData: Nullable<Float32Array>): void {
  626. const babylonBones: { [index: number]: Bone } = {};
  627. for (const index of skin.joints) {
  628. const node = GLTFLoader._GetProperty(`${context}/joints/${index}`, this._gltf.nodes, index);
  629. this._loadBone(node, skin, inverseBindMatricesData, babylonBones);
  630. }
  631. }
  632. private _loadBone(node: ILoaderNode, skin: ILoaderSkin, inverseBindMatricesData: Nullable<Float32Array>, babylonBones: { [index: number]: Bone }): Bone {
  633. let babylonBone = babylonBones[node._index];
  634. if (babylonBone) {
  635. return babylonBone;
  636. }
  637. const boneIndex = skin.joints.indexOf(node._index);
  638. let baseMatrix = Matrix.Identity();
  639. if (inverseBindMatricesData && boneIndex !== -1) {
  640. baseMatrix = Matrix.FromArray(inverseBindMatricesData, boneIndex * 16);
  641. baseMatrix.invertToRef(baseMatrix);
  642. }
  643. let babylonParentBone: Nullable<Bone> = null;
  644. if (node._parent._babylonMesh !== this._rootBabylonMesh) {
  645. babylonParentBone = this._loadBone(node._parent, skin, inverseBindMatricesData, babylonBones);
  646. baseMatrix.multiplyToRef(babylonParentBone.getInvertedAbsoluteTransform(), baseMatrix);
  647. }
  648. babylonBone = this._createBone(node, skin, babylonParentBone, this._getNodeMatrix(node), baseMatrix, boneIndex);
  649. babylonBones[node._index] = babylonBone;
  650. return babylonBone;
  651. }
  652. private _getNodeMatrix(node: ILoaderNode): Matrix {
  653. return node.matrix ?
  654. Matrix.FromArray(node.matrix) :
  655. Matrix.Compose(
  656. node.scale ? Vector3.FromArray(node.scale) : Vector3.One(),
  657. node.rotation ? Quaternion.FromArray(node.rotation) : Quaternion.Identity(),
  658. node.translation ? Vector3.FromArray(node.translation) : Vector3.Zero());
  659. }
  660. private _loadAnimationsAsync(): Promise<void> {
  661. const animations = this._gltf.animations;
  662. if (!animations) {
  663. return Promise.resolve();
  664. }
  665. const promises = new Array<Promise<void>>();
  666. for (let index = 0; index < animations.length; index++) {
  667. const animation = animations[index];
  668. promises.push(this._loadAnimationAsync(`#/animations/${index}`, animation));
  669. }
  670. return Promise.all(promises).then(() => {});
  671. }
  672. private _loadAnimationAsync(context: string, animation: ILoaderAnimation): Promise<void> {
  673. const babylonAnimationGroup = new AnimationGroup(animation.name || `animation${animation._index}`, this._babylonScene);
  674. animation._babylonAnimationGroup = babylonAnimationGroup;
  675. const promises = new Array<Promise<void>>();
  676. ArrayItem.Assign(animation.channels);
  677. ArrayItem.Assign(animation.samplers);
  678. for (const channel of animation.channels) {
  679. promises.push(this._loadAnimationChannelAsync(`${context}/channels/${channel._index}`, context, animation, channel, babylonAnimationGroup));
  680. }
  681. this.onAnimationGroupLoadedObservable.notifyObservers(babylonAnimationGroup);
  682. return Promise.all(promises).then(() => {
  683. babylonAnimationGroup.normalize();
  684. });
  685. }
  686. private _loadAnimationChannelAsync(context: string, animationContext: string, animation: ILoaderAnimation, channel: ILoaderAnimationChannel, babylonAnimationGroup: AnimationGroup): Promise<void> {
  687. const targetNode = GLTFLoader._GetProperty(`${context}/target/node`, this._gltf.nodes, channel.target.node);
  688. if (!targetNode._babylonMesh || targetNode.skin != undefined) {
  689. return Promise.resolve();
  690. }
  691. const sampler = GLTFLoader._GetProperty(`${context}/sampler`, animation.samplers, channel.sampler);
  692. return this._loadAnimationSamplerAsync(`${animationContext}/samplers/${channel.sampler}`, sampler).then(data => {
  693. let targetPath: string;
  694. let animationType: number;
  695. switch (channel.target.path) {
  696. case AnimationChannelTargetPath.TRANSLATION: {
  697. targetPath = "position";
  698. animationType = Animation.ANIMATIONTYPE_VECTOR3;
  699. break;
  700. }
  701. case AnimationChannelTargetPath.ROTATION: {
  702. targetPath = "rotationQuaternion";
  703. animationType = Animation.ANIMATIONTYPE_QUATERNION;
  704. break;
  705. }
  706. case AnimationChannelTargetPath.SCALE: {
  707. targetPath = "scaling";
  708. animationType = Animation.ANIMATIONTYPE_VECTOR3;
  709. break;
  710. }
  711. case AnimationChannelTargetPath.WEIGHTS: {
  712. targetPath = "influence";
  713. animationType = Animation.ANIMATIONTYPE_FLOAT;
  714. break;
  715. }
  716. default: {
  717. throw new Error(`${context}: Invalid target path (${channel.target.path})`);
  718. }
  719. }
  720. let outputBufferOffset = 0;
  721. let getNextOutputValue: () => Vector3 | Quaternion | Array<number>;
  722. switch (targetPath) {
  723. case "position": {
  724. getNextOutputValue = () => {
  725. const value = Vector3.FromArray(data.output, outputBufferOffset);
  726. outputBufferOffset += 3;
  727. return value;
  728. };
  729. break;
  730. }
  731. case "rotationQuaternion": {
  732. getNextOutputValue = () => {
  733. const value = Quaternion.FromArray(data.output, outputBufferOffset);
  734. outputBufferOffset += 4;
  735. return value;
  736. };
  737. break;
  738. }
  739. case "scaling": {
  740. getNextOutputValue = () => {
  741. const value = Vector3.FromArray(data.output, outputBufferOffset);
  742. outputBufferOffset += 3;
  743. return value;
  744. };
  745. break;
  746. }
  747. case "influence": {
  748. getNextOutputValue = () => {
  749. const value = new Array<number>(targetNode._numMorphTargets!);
  750. for (let i = 0; i < targetNode._numMorphTargets!; i++) {
  751. value[i] = data.output[outputBufferOffset++];
  752. }
  753. return value;
  754. };
  755. break;
  756. }
  757. }
  758. let getNextKey: (frameIndex: number) => IAnimationKey;
  759. switch (data.interpolation) {
  760. case AnimationSamplerInterpolation.STEP: {
  761. getNextKey = frameIndex => ({
  762. frame: data.input[frameIndex],
  763. value: getNextOutputValue(),
  764. interpolation: AnimationKeyInterpolation.STEP
  765. });
  766. break;
  767. }
  768. case AnimationSamplerInterpolation.LINEAR: {
  769. getNextKey = frameIndex => ({
  770. frame: data.input[frameIndex],
  771. value: getNextOutputValue()
  772. });
  773. break;
  774. }
  775. case AnimationSamplerInterpolation.CUBICSPLINE: {
  776. getNextKey = frameIndex => ({
  777. frame: data.input[frameIndex],
  778. inTangent: getNextOutputValue(),
  779. value: getNextOutputValue(),
  780. outTangent: getNextOutputValue()
  781. });
  782. break;
  783. }
  784. }
  785. let keys: Array<IAnimationKey>;
  786. if (data.input.length === 1) {
  787. let key = getNextKey!(0);
  788. keys = [
  789. { frame: key.frame, value: key.value },
  790. { frame: key.frame + 1, value: key.value }
  791. ];
  792. }
  793. else {
  794. keys = new Array(data.input.length);
  795. for (let frameIndex = 0; frameIndex < data.input.length; frameIndex++) {
  796. keys[frameIndex] = getNextKey!(frameIndex);
  797. }
  798. }
  799. if (targetPath === "influence") {
  800. for (let targetIndex = 0; targetIndex < targetNode._numMorphTargets!; targetIndex++) {
  801. const animationName = `${babylonAnimationGroup.name}_channel${babylonAnimationGroup.targetedAnimations.length}`;
  802. const babylonAnimation = new Animation(animationName, targetPath, 1, animationType);
  803. babylonAnimation.setKeys(keys.map(key => ({
  804. frame: key.frame,
  805. inTangent: key.inTangent ? key.inTangent[targetIndex] : undefined,
  806. value: key.value[targetIndex],
  807. outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
  808. })));
  809. this._forEachNodeMesh(targetNode, babylonMesh => {
  810. const morphTarget = babylonMesh.morphTargetManager!.getTarget(targetIndex);
  811. babylonAnimationGroup.addTargetedAnimation(babylonAnimation, morphTarget);
  812. });
  813. }
  814. }
  815. else {
  816. const animationName = `${babylonAnimationGroup.name}_channel${babylonAnimationGroup.targetedAnimations.length}`;
  817. const babylonAnimation = new Animation(animationName, targetPath, 1, animationType);
  818. babylonAnimation.setKeys(keys);
  819. if (targetNode._babylonAnimationTargets) {
  820. for (const target of targetNode._babylonAnimationTargets) {
  821. babylonAnimationGroup.addTargetedAnimation(babylonAnimation, target);
  822. }
  823. }
  824. }
  825. });
  826. }
  827. private _loadAnimationSamplerAsync(context: string, sampler: ILoaderAnimationSampler): Promise<ILoaderAnimationSamplerData> {
  828. if (sampler._data) {
  829. return sampler._data;
  830. }
  831. const interpolation = sampler.interpolation || AnimationSamplerInterpolation.LINEAR;
  832. switch (interpolation) {
  833. case AnimationSamplerInterpolation.STEP:
  834. case AnimationSamplerInterpolation.LINEAR:
  835. case AnimationSamplerInterpolation.CUBICSPLINE: {
  836. break;
  837. }
  838. default: {
  839. throw new Error(`${context}: Invalid interpolation (${sampler.interpolation})`);
  840. }
  841. }
  842. let inputData: Nullable<Float32Array>;
  843. let outputData: Nullable<Float32Array>;
  844. const inputAccessor = GLTFLoader._GetProperty(`${context}/input`, this._gltf.accessors, sampler.input);
  845. const outputAccessor = GLTFLoader._GetProperty(`${context}/output`, this._gltf.accessors, sampler.output);
  846. sampler._data = Promise.all([
  847. this._loadAccessorAsync(`#/accessors/${inputAccessor._index}`, inputAccessor).then(data => {
  848. inputData = data as Float32Array;
  849. }),
  850. this._loadAccessorAsync(`#/accessors/${outputAccessor._index}`, outputAccessor).then(data => {
  851. outputData = data as Float32Array;
  852. })
  853. ]).then(() => {
  854. return {
  855. input: inputData!,
  856. interpolation: interpolation,
  857. output: outputData!,
  858. };
  859. });
  860. return sampler._data;
  861. }
  862. private _loadBufferAsync(context: string, buffer: ILoaderBuffer): Promise<ArrayBufferView> {
  863. if (buffer._data) {
  864. return buffer._data;
  865. }
  866. if (!buffer.uri) {
  867. throw new Error(`${context}: Uri is missing`);
  868. }
  869. buffer._data = this._loadUriAsync(context, buffer.uri);
  870. return buffer._data;
  871. }
  872. public _loadBufferViewAsync(context: string, bufferView: ILoaderBufferView): Promise<ArrayBufferView> {
  873. if (bufferView._data) {
  874. return bufferView._data;
  875. }
  876. const buffer = GLTFLoader._GetProperty(`${context}/buffer`, this._gltf.buffers, bufferView.buffer);
  877. bufferView._data = this._loadBufferAsync(`#/buffers/${buffer._index}`, buffer).then(bufferData => {
  878. try {
  879. return new Uint8Array(bufferData.buffer, bufferData.byteOffset + (bufferView.byteOffset || 0), bufferView.byteLength);
  880. }
  881. catch (e) {
  882. throw new Error(`${context}: ${e.message}`);
  883. }
  884. });
  885. return bufferView._data;
  886. }
  887. private _loadAccessorAsync(context: string, accessor: ILoaderAccessor): Promise<TypedArray> {
  888. if (accessor.sparse) {
  889. throw new Error(`${context}: Sparse accessors are not currently supported`);
  890. }
  891. if (accessor._data) {
  892. return accessor._data;
  893. }
  894. const bufferView = GLTFLoader._GetProperty(`${context}/bufferView`, this._gltf.bufferViews, accessor.bufferView);
  895. accessor._data = this._loadBufferViewAsync(`#/bufferViews/${bufferView._index}`, bufferView).then(bufferViewData => {
  896. const numComponents = GLTFLoader._GetNumComponents(context, accessor.type);
  897. const byteOffset = accessor.byteOffset || 0;
  898. const byteStride = bufferView.byteStride;
  899. if (byteStride === 0) {
  900. Tools.Warn(`${context}: Byte stride of 0 is not valid`);
  901. }
  902. try {
  903. switch (accessor.componentType) {
  904. case AccessorComponentType.BYTE: {
  905. return this._buildArrayBuffer(Float32Array, bufferViewData, byteOffset, accessor.count, numComponents, byteStride);
  906. }
  907. case AccessorComponentType.UNSIGNED_BYTE: {
  908. return this._buildArrayBuffer(Uint8Array, bufferViewData, byteOffset, accessor.count, numComponents, byteStride);
  909. }
  910. case AccessorComponentType.SHORT: {
  911. return this._buildArrayBuffer(Int16Array, bufferViewData, byteOffset, accessor.count, numComponents, byteStride);
  912. }
  913. case AccessorComponentType.UNSIGNED_SHORT: {
  914. return this._buildArrayBuffer(Uint16Array, bufferViewData, byteOffset, accessor.count, numComponents, byteStride);
  915. }
  916. case AccessorComponentType.UNSIGNED_INT: {
  917. return this._buildArrayBuffer(Uint32Array, bufferViewData, byteOffset, accessor.count, numComponents, byteStride);
  918. }
  919. case AccessorComponentType.FLOAT: {
  920. return this._buildArrayBuffer(Float32Array, bufferViewData, byteOffset, accessor.count, numComponents, byteStride);
  921. }
  922. default: {
  923. throw new Error(`${context}: Invalid component type (${accessor.componentType})`);
  924. }
  925. }
  926. }
  927. catch (e) {
  928. throw new Error(`${context}: ${e.messsage}`);
  929. }
  930. });
  931. return accessor._data;
  932. }
  933. private _buildArrayBuffer<T extends TypedArray>(typedArray: TypedArrayConstructor<T>, data: ArrayBufferView, byteOffset: number, count: number, numComponents: number, byteStride?: number): T {
  934. byteOffset += data.byteOffset;
  935. const targetLength = count * numComponents;
  936. if (!byteStride || byteStride === numComponents * typedArray.BYTES_PER_ELEMENT) {
  937. return new typedArray(data.buffer, byteOffset, targetLength);
  938. }
  939. const elementStride = byteStride / typedArray.BYTES_PER_ELEMENT;
  940. const sourceBuffer = new typedArray(data.buffer, byteOffset, elementStride * count);
  941. const targetBuffer = new typedArray(targetLength);
  942. let sourceIndex = 0;
  943. let targetIndex = 0;
  944. while (targetIndex < targetLength) {
  945. for (let componentIndex = 0; componentIndex < numComponents; componentIndex++) {
  946. targetBuffer[targetIndex] = sourceBuffer[sourceIndex + componentIndex];
  947. targetIndex++;
  948. }
  949. sourceIndex += elementStride;
  950. }
  951. return targetBuffer;
  952. }
  953. private _getDefaultMaterial(): Material {
  954. const id = "__gltf_default";
  955. let babylonMaterial = <PBRMaterial>this._babylonScene.getMaterialByName(id);
  956. if (!babylonMaterial) {
  957. babylonMaterial = new PBRMaterial(id, this._babylonScene);
  958. babylonMaterial.transparencyMode = PBRMaterial.PBRMATERIAL_OPAQUE;
  959. babylonMaterial.sideOrientation = this._babylonScene.useRightHandedSystem ? Material.CounterClockWiseSideOrientation : Material.ClockWiseSideOrientation;
  960. babylonMaterial.metallic = 1;
  961. babylonMaterial.roughness = 1;
  962. this.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
  963. }
  964. return babylonMaterial;
  965. }
  966. private _loadMaterialMetallicRoughnessPropertiesAsync(context: string, material: ILoaderMaterial): Promise<void> {
  967. const promises = new Array<Promise<void>>();
  968. const babylonMaterial = material._babylonMaterial as PBRMaterial;
  969. // Ensure metallic workflow
  970. babylonMaterial.metallic = 1;
  971. babylonMaterial.roughness = 1;
  972. const properties = material.pbrMetallicRoughness;
  973. if (properties) {
  974. if (properties.baseColorFactor) {
  975. babylonMaterial.albedoColor = Color3.FromArray(properties.baseColorFactor);
  976. babylonMaterial.alpha = properties.baseColorFactor[3];
  977. }
  978. else {
  979. babylonMaterial.albedoColor = Color3.White();
  980. }
  981. babylonMaterial.metallic = properties.metallicFactor == undefined ? 1 : properties.metallicFactor;
  982. babylonMaterial.roughness = properties.roughnessFactor == undefined ? 1 : properties.roughnessFactor;
  983. if (properties.baseColorTexture) {
  984. promises.push(this._loadTextureAsync(`${context}/baseColorTexture`, properties.baseColorTexture, texture => {
  985. babylonMaterial.albedoTexture = texture;
  986. }));
  987. }
  988. if (properties.metallicRoughnessTexture) {
  989. promises.push(this._loadTextureAsync(`${context}/metallicRoughnessTexture`, properties.metallicRoughnessTexture, texture => {
  990. babylonMaterial.metallicTexture = texture;
  991. }));
  992. babylonMaterial.useMetallnessFromMetallicTextureBlue = true;
  993. babylonMaterial.useRoughnessFromMetallicTextureGreen = true;
  994. babylonMaterial.useRoughnessFromMetallicTextureAlpha = false;
  995. }
  996. }
  997. this._loadMaterialAlphaProperties(context, material);
  998. return Promise.all(promises).then(() => {});
  999. }
  1000. public _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh, assign: (babylonMaterial: Material) => void): Promise<void> {
  1001. const promise = GLTFLoaderExtension._LoadMaterialAsync(this, context, material, babylonMesh, assign);
  1002. if (promise) {
  1003. return promise;
  1004. }
  1005. material._babylonMeshes = material._babylonMeshes || [];
  1006. material._babylonMeshes.push(babylonMesh);
  1007. if (!material._loaded) {
  1008. const promises = new Array<Promise<void>>();
  1009. const babylonMaterial = this._createMaterial(material);
  1010. material._babylonMaterial = babylonMaterial;
  1011. promises.push(this._loadMaterialBasePropertiesAsync(context, material));
  1012. promises.push(this._loadMaterialMetallicRoughnessPropertiesAsync(context, material));
  1013. this.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
  1014. material._loaded = Promise.all(promises).then(() => {});
  1015. }
  1016. assign(material._babylonMaterial!);
  1017. return material._loaded;
  1018. }
  1019. public _createMaterial(material: ILoaderMaterial): PBRMaterial {
  1020. const babylonMaterial = new PBRMaterial(material.name || `material${material._index}`, this._babylonScene);
  1021. babylonMaterial.sideOrientation = this._babylonScene.useRightHandedSystem ? Material.CounterClockWiseSideOrientation : Material.ClockWiseSideOrientation;
  1022. return babylonMaterial;
  1023. }
  1024. public _loadMaterialBasePropertiesAsync(context: string, material: ILoaderMaterial): Promise<void> {
  1025. const promises = new Array<Promise<void>>();
  1026. const babylonMaterial = material._babylonMaterial as PBRMaterial;
  1027. babylonMaterial.emissiveColor = material.emissiveFactor ? Color3.FromArray(material.emissiveFactor) : new Color3(0, 0, 0);
  1028. if (material.doubleSided) {
  1029. babylonMaterial.backFaceCulling = false;
  1030. babylonMaterial.twoSidedLighting = true;
  1031. }
  1032. if (material.normalTexture) {
  1033. promises.push(this._loadTextureAsync(`${context}/normalTexture`, material.normalTexture, texture => {
  1034. babylonMaterial.bumpTexture = texture;
  1035. }));
  1036. babylonMaterial.invertNormalMapX = !this._babylonScene.useRightHandedSystem;
  1037. babylonMaterial.invertNormalMapY = this._babylonScene.useRightHandedSystem;
  1038. if (material.normalTexture.scale != undefined) {
  1039. babylonMaterial.bumpTexture.level = material.normalTexture.scale;
  1040. }
  1041. }
  1042. if (material.occlusionTexture) {
  1043. promises.push(this._loadTextureAsync(`${context}/occlusionTexture`, material.occlusionTexture, texture => {
  1044. babylonMaterial.ambientTexture = texture;
  1045. }));
  1046. babylonMaterial.useAmbientInGrayScale = true;
  1047. if (material.occlusionTexture.strength != undefined) {
  1048. babylonMaterial.ambientTextureStrength = material.occlusionTexture.strength;
  1049. }
  1050. }
  1051. if (material.emissiveTexture) {
  1052. promises.push(this._loadTextureAsync(`${context}/emissiveTexture`, material.emissiveTexture, texture => {
  1053. babylonMaterial.emissiveTexture = texture;
  1054. }));
  1055. }
  1056. return Promise.all(promises).then(() => {});
  1057. }
  1058. public _loadMaterialAlphaProperties(context: string, material: ILoaderMaterial): void {
  1059. const babylonMaterial = material._babylonMaterial as PBRMaterial;
  1060. const alphaMode = material.alphaMode || MaterialAlphaMode.OPAQUE;
  1061. switch (alphaMode) {
  1062. case MaterialAlphaMode.OPAQUE: {
  1063. babylonMaterial.transparencyMode = PBRMaterial.PBRMATERIAL_OPAQUE;
  1064. break;
  1065. }
  1066. case MaterialAlphaMode.MASK: {
  1067. babylonMaterial.transparencyMode = PBRMaterial.PBRMATERIAL_ALPHATEST;
  1068. babylonMaterial.alphaCutOff = (material.alphaCutoff == undefined ? 0.5 : material.alphaCutoff);
  1069. if (babylonMaterial.alpha) {
  1070. if (babylonMaterial.alpha === 0) {
  1071. babylonMaterial.alphaCutOff = 1;
  1072. }
  1073. else {
  1074. babylonMaterial.alphaCutOff /= babylonMaterial.alpha;
  1075. }
  1076. babylonMaterial.alpha = 1;
  1077. }
  1078. if (babylonMaterial.albedoTexture) {
  1079. babylonMaterial.albedoTexture.hasAlpha = true;
  1080. }
  1081. break;
  1082. }
  1083. case MaterialAlphaMode.BLEND: {
  1084. babylonMaterial.transparencyMode = PBRMaterial.PBRMATERIAL_ALPHABLEND;
  1085. if (babylonMaterial.albedoTexture) {
  1086. babylonMaterial.albedoTexture.hasAlpha = true;
  1087. babylonMaterial.useAlphaFromAlbedoTexture = true;
  1088. }
  1089. break;
  1090. }
  1091. default: {
  1092. throw new Error(`${context}: Invalid alpha mode (${material.alphaMode})`);
  1093. }
  1094. }
  1095. }
  1096. public _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Promise<void> {
  1097. const texture = GLTFLoader._GetProperty(`${context}/index`, this._gltf.textures, textureInfo.index);
  1098. context = `#/textures/${textureInfo.index}`;
  1099. const promises = new Array<Promise<void>>();
  1100. const sampler = (texture.sampler == undefined ? this._defaultSampler : GLTFLoader._GetProperty(`${context}/sampler`, this._gltf.samplers, texture.sampler));
  1101. const samplerData = this._loadSampler(`#/samplers/${sampler._index}`, sampler);
  1102. const deferred = new Deferred<void>();
  1103. const babylonTexture = new Texture(null, this._babylonScene, samplerData.noMipMaps, false, samplerData.samplingMode, () => {
  1104. if (!this._disposed) {
  1105. deferred.resolve();
  1106. }
  1107. }, (message, exception) => {
  1108. if (!this._disposed) {
  1109. deferred.reject(new Error(`${context}: ${(exception && exception.message) ? exception.message : message || "Failed to load texture"}`));
  1110. }
  1111. });
  1112. promises.push(deferred.promise);
  1113. babylonTexture.name = texture.name || `texture${texture._index}`;
  1114. babylonTexture.wrapU = samplerData.wrapU;
  1115. babylonTexture.wrapV = samplerData.wrapV;
  1116. babylonTexture.coordinatesIndex = textureInfo.texCoord || 0;
  1117. const image = GLTFLoader._GetProperty(`${context}/source`, this._gltf.images, texture.source);
  1118. promises.push(this._loadImageAsync(`#/images/${image._index}`, image).then(objectURL => {
  1119. babylonTexture.updateURL(objectURL);
  1120. }));
  1121. assign(babylonTexture);
  1122. this.onTextureLoadedObservable.notifyObservers(babylonTexture);
  1123. return Promise.all(promises).then(() => {});
  1124. }
  1125. private _loadSampler(context: string, sampler: ILoaderSampler): ILoaderSamplerData {
  1126. if (!sampler._data) {
  1127. sampler._data = {
  1128. noMipMaps: (sampler.minFilter === TextureMinFilter.NEAREST || sampler.minFilter === TextureMinFilter.LINEAR),
  1129. samplingMode: GLTFLoader._GetTextureSamplingMode(context, sampler.magFilter, sampler.minFilter),
  1130. wrapU: GLTFLoader._GetTextureWrapMode(context, sampler.wrapS),
  1131. wrapV: GLTFLoader._GetTextureWrapMode(context, sampler.wrapT)
  1132. };
  1133. };
  1134. return sampler._data;
  1135. }
  1136. private _loadImageAsync(context: string, image: ILoaderImage): Promise<string> {
  1137. if (image._objectURL) {
  1138. return image._objectURL;
  1139. }
  1140. let promise: Promise<ArrayBufferView>;
  1141. if (image.uri) {
  1142. promise = this._loadUriAsync(context, image.uri);
  1143. }
  1144. else {
  1145. const bufferView = GLTFLoader._GetProperty(`${context}/bufferView`, this._gltf.bufferViews, image.bufferView);
  1146. promise = this._loadBufferViewAsync(`#/bufferViews/${bufferView._index}`, bufferView);
  1147. }
  1148. image._objectURL = promise.then(data => {
  1149. return URL.createObjectURL(new Blob([data], { type: image.mimeType }));
  1150. });
  1151. return image._objectURL;
  1152. }
  1153. public _loadUriAsync(context: string, uri: string): Promise<ArrayBufferView> {
  1154. const promise = GLTFLoaderExtension._LoadUriAsync(this, context, uri);
  1155. if (promise) {
  1156. return promise;
  1157. }
  1158. if (!GLTFLoader._ValidateUri(uri)) {
  1159. throw new Error(`${context}: Uri '${uri}' is invalid`);
  1160. }
  1161. if (Tools.IsBase64(uri)) {
  1162. return Promise.resolve(new Uint8Array(Tools.DecodeBase64(uri)));
  1163. }
  1164. return new Promise((resolve, reject) => {
  1165. const request = Tools.LoadFile(this._rootUrl + uri, data => {
  1166. if (!this._disposed) {
  1167. resolve(new Uint8Array(data as ArrayBuffer));
  1168. }
  1169. }, event => {
  1170. if (!this._disposed) {
  1171. try {
  1172. if (request && this._state === GLTFLoaderState.Loading) {
  1173. request._lengthComputable = event.lengthComputable;
  1174. request._loaded = event.loaded;
  1175. request._total = event.total;
  1176. this._onProgress();
  1177. }
  1178. }
  1179. catch (e) {
  1180. reject(e);
  1181. }
  1182. }
  1183. }, this._babylonScene.database, true, (request, exception) => {
  1184. if (!this._disposed) {
  1185. reject(new LoadFileError(`${context}: Failed to load '${uri}'${request ? ": " + request.status + " " + request.statusText : ""}`, request));
  1186. }
  1187. }) as IFileRequestInfo;
  1188. this._requests.push(request);
  1189. })
  1190. }
  1191. private _onProgress(): void {
  1192. if (!this._progressCallback) {
  1193. return;
  1194. }
  1195. let lengthComputable = true;
  1196. let loaded = 0;
  1197. let total = 0;
  1198. for (let request of this._requests) {
  1199. if (request._lengthComputable === undefined || request._loaded === undefined || request._total === undefined) {
  1200. return;
  1201. }
  1202. lengthComputable = lengthComputable && request._lengthComputable;
  1203. loaded += request._loaded;
  1204. total += request._total;
  1205. }
  1206. this._progressCallback(new SceneLoaderProgressEvent(lengthComputable, loaded, lengthComputable ? total : 0));
  1207. }
  1208. public static _GetProperty<T>(context: string, array: ArrayLike<T> | undefined, index: number | undefined): T {
  1209. if (!array || index == undefined || !array[index]) {
  1210. throw new Error(`${context}: Failed to find index (${index})`);
  1211. }
  1212. return array[index];
  1213. }
  1214. private static _GetTextureWrapMode(context: string, mode: TextureWrapMode | undefined): number {
  1215. // Set defaults if undefined
  1216. mode = mode == undefined ? TextureWrapMode.REPEAT : mode;
  1217. switch (mode) {
  1218. case TextureWrapMode.CLAMP_TO_EDGE: return Texture.CLAMP_ADDRESSMODE;
  1219. case TextureWrapMode.MIRRORED_REPEAT: return Texture.MIRROR_ADDRESSMODE;
  1220. case TextureWrapMode.REPEAT: return Texture.WRAP_ADDRESSMODE;
  1221. default:
  1222. Tools.Warn(`${context}: Invalid texture wrap mode (${mode})`);
  1223. return Texture.WRAP_ADDRESSMODE;
  1224. }
  1225. }
  1226. private static _GetTextureSamplingMode(context: string, magFilter?: TextureMagFilter, minFilter?: TextureMinFilter): number {
  1227. // Set defaults if undefined
  1228. magFilter = magFilter == undefined ? TextureMagFilter.LINEAR : magFilter;
  1229. minFilter = minFilter == undefined ? TextureMinFilter.LINEAR_MIPMAP_LINEAR : minFilter;
  1230. if (magFilter === TextureMagFilter.LINEAR) {
  1231. switch (minFilter) {
  1232. case TextureMinFilter.NEAREST: return Texture.LINEAR_NEAREST;
  1233. case TextureMinFilter.LINEAR: return Texture.LINEAR_LINEAR;
  1234. case TextureMinFilter.NEAREST_MIPMAP_NEAREST: return Texture.LINEAR_NEAREST_MIPNEAREST;
  1235. case TextureMinFilter.LINEAR_MIPMAP_NEAREST: return Texture.LINEAR_LINEAR_MIPNEAREST;
  1236. case TextureMinFilter.NEAREST_MIPMAP_LINEAR: return Texture.LINEAR_NEAREST_MIPLINEAR;
  1237. case TextureMinFilter.LINEAR_MIPMAP_LINEAR: return Texture.LINEAR_LINEAR_MIPLINEAR;
  1238. default:
  1239. Tools.Warn(`${context}: Invalid texture minification filter (${minFilter})`);
  1240. return Texture.LINEAR_LINEAR_MIPLINEAR;
  1241. }
  1242. }
  1243. else {
  1244. if (magFilter !== TextureMagFilter.NEAREST) {
  1245. Tools.Warn(`${context}: Invalid texture magnification filter (${magFilter})`);
  1246. }
  1247. switch (minFilter) {
  1248. case TextureMinFilter.NEAREST: return Texture.NEAREST_NEAREST;
  1249. case TextureMinFilter.LINEAR: return Texture.NEAREST_LINEAR;
  1250. case TextureMinFilter.NEAREST_MIPMAP_NEAREST: return Texture.NEAREST_NEAREST_MIPNEAREST;
  1251. case TextureMinFilter.LINEAR_MIPMAP_NEAREST: return Texture.NEAREST_LINEAR_MIPNEAREST;
  1252. case TextureMinFilter.NEAREST_MIPMAP_LINEAR: return Texture.NEAREST_NEAREST_MIPLINEAR;
  1253. case TextureMinFilter.LINEAR_MIPMAP_LINEAR: return Texture.NEAREST_LINEAR_MIPLINEAR;
  1254. default:
  1255. Tools.Warn(`${context}: Invalid texture minification filter (${minFilter})`);
  1256. return Texture.NEAREST_NEAREST_MIPNEAREST;
  1257. }
  1258. }
  1259. }
  1260. private static _GetNumComponents(context: string, type: string): number {
  1261. switch (type) {
  1262. case "SCALAR": return 1;
  1263. case "VEC2": return 2;
  1264. case "VEC3": return 3;
  1265. case "VEC4": return 4;
  1266. case "MAT2": return 4;
  1267. case "MAT3": return 9;
  1268. case "MAT4": return 16;
  1269. }
  1270. throw new Error(`${context}: Invalid type (${type})`);
  1271. }
  1272. private static _ValidateUri(uri: string): boolean {
  1273. return (Tools.IsBase64(uri) || uri.indexOf("..") === -1);
  1274. }
  1275. private _compileMaterialsAsync(): Promise<void> {
  1276. const promises = new Array<Promise<void>>();
  1277. if (this._gltf.materials) {
  1278. for (const material of this._gltf.materials) {
  1279. const babylonMaterial = material._babylonMaterial;
  1280. const babylonMeshes = material._babylonMeshes;
  1281. if (babylonMaterial && babylonMeshes) {
  1282. for (const babylonMesh of babylonMeshes) {
  1283. // Ensure nonUniformScaling is set if necessary.
  1284. babylonMesh.computeWorldMatrix(true);
  1285. promises.push(babylonMaterial.forceCompilationAsync(babylonMesh));
  1286. if (this.useClipPlane) {
  1287. promises.push(babylonMaterial.forceCompilationAsync(babylonMesh, { clipPlane: true }));
  1288. }
  1289. }
  1290. }
  1291. }
  1292. }
  1293. return Promise.all(promises).then(() => {});
  1294. }
  1295. private _compileShadowGeneratorsAsync(): Promise<void> {
  1296. const promises = new Array<Promise<void>>();
  1297. const lights = this._babylonScene.lights;
  1298. for (let light of lights) {
  1299. let generator = light.getShadowGenerator();
  1300. if (generator) {
  1301. promises.push(generator.forceCompilationAsync());
  1302. }
  1303. }
  1304. return Promise.all(promises).then(() => {});
  1305. }
  1306. private _clear(): void {
  1307. for (const request of this._requests) {
  1308. request.abort();
  1309. }
  1310. this._requests.length = 0;
  1311. if (this._gltf && this._gltf.images) {
  1312. for (const image of this._gltf.images) {
  1313. if (image._objectURL) {
  1314. image._objectURL.then(value => {
  1315. URL.revokeObjectURL(value);
  1316. });
  1317. image._objectURL = undefined;
  1318. }
  1319. }
  1320. }
  1321. delete this._gltf;
  1322. delete this._babylonScene;
  1323. this._completePromises.length = 0;
  1324. for (const name in this._extensions) {
  1325. this._extensions[name].dispose();
  1326. }
  1327. this._extensions = {};
  1328. delete this._rootBabylonMesh;
  1329. delete this._progressCallback;
  1330. this.onMeshLoadedObservable.clear();
  1331. this.onTextureLoadedObservable.clear();
  1332. this.onMaterialLoadedObservable.clear();
  1333. }
  1334. public _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>) {
  1335. for (const name of GLTFLoader._Names) {
  1336. const extension = this._extensions[name];
  1337. if (extension.enabled) {
  1338. const promise = actionAsync(extension);
  1339. if (promise) {
  1340. return promise;
  1341. }
  1342. }
  1343. }
  1344. return null;
  1345. }
  1346. }
  1347. GLTFFileLoader.CreateGLTFLoaderV2 = () => new GLTFLoader();
  1348. }