babylon.glTFLoader.ts 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084
  1. /// <reference path="../../../../dist/preview release/babylon.d.ts"/>
  2. module BABYLON.GLTF2 {
  3. export class GLTFLoader implements IGLTFLoader, IDisposable {
  4. private _parent: GLTFFileLoader;
  5. private _gltf: IGLTF;
  6. private _babylonScene: Scene;
  7. private _rootUrl: string;
  8. private _defaultMaterial: PBRMaterial;
  9. private _successCallback: () => void;
  10. private _progressCallback: (event: ProgressEvent) => void;
  11. private _errorCallback: (message: string) => void;
  12. private _renderReady: boolean = false;
  13. private _disposed: boolean = false;
  14. private _objectURLs: string[] = new Array<string>();
  15. // Observable with boolean indicating success or error.
  16. private _renderReadyObservable = new Observable<GLTFLoader>();
  17. // Count of pending work that needs to complete before the asset is rendered.
  18. private _renderPendingCount: number = 0;
  19. // Count of pending work that needs to complete before the loader is cleared.
  20. private _loaderPendingCount: number = 0;
  21. public static Extensions: { [name: string]: GLTFLoaderExtension } = {};
  22. public static RegisterExtension(extension: GLTFLoaderExtension): void {
  23. if (GLTFLoader.Extensions[extension.name]) {
  24. Tools.Error("Extension with the same name '" + extension.name + "' already exists");
  25. return;
  26. }
  27. GLTFLoader.Extensions[extension.name] = extension;
  28. // Keep the order of registration so that extensions registered first are called first.
  29. GLTFLoaderExtension._Extensions.push(extension);
  30. }
  31. public get gltf(): IGLTF {
  32. return this._gltf;
  33. }
  34. public get babylonScene(): Scene {
  35. return this._babylonScene;
  36. }
  37. public executeWhenRenderReady(func: () => void) {
  38. if (this._renderReady) {
  39. func();
  40. }
  41. else {
  42. this._renderReadyObservable.add(func);
  43. }
  44. }
  45. public constructor(parent: GLTFFileLoader) {
  46. this._parent = parent;
  47. }
  48. public dispose(): void {
  49. if (this._disposed) {
  50. return;
  51. }
  52. this._disposed = true;
  53. // Revoke object urls created during load
  54. this._objectURLs.forEach(url => URL.revokeObjectURL(url));
  55. this._objectURLs.length = 0;
  56. this._gltf = undefined;
  57. this._babylonScene = undefined;
  58. this._rootUrl = undefined;
  59. this._defaultMaterial = undefined;
  60. this._successCallback = undefined;
  61. this._errorCallback = undefined;
  62. this._renderReady = false;
  63. this._renderReadyObservable.clear();
  64. this._renderPendingCount = 0;
  65. this._loaderPendingCount = 0;
  66. }
  67. public importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void {
  68. this._loadAsync(meshesNames, scene, data, rootUrl, () => {
  69. var meshes = [];
  70. if (this._gltf.nodes) {
  71. for (var i = 0; i < this._gltf.nodes.length; i++) {
  72. var node = this._gltf.nodes[i];
  73. if (node.babylonMesh) {
  74. meshes.push(node.babylonMesh);
  75. }
  76. }
  77. }
  78. var skeletons = [];
  79. if (this._gltf.skins) {
  80. for (var i = 0; i < this._gltf.skins.length; i++) {
  81. var skin = this._gltf.skins[i];
  82. if (skin.babylonSkeleton instanceof Skeleton) {
  83. skeletons.push(skin.babylonSkeleton);
  84. }
  85. }
  86. }
  87. onSuccess(meshes, null, skeletons);
  88. }, onProgress, onError);
  89. }
  90. public loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void {
  91. this._loadAsync(null, scene, data, rootUrl, onSuccess, onProgress, onError);
  92. }
  93. private _loadAsync(nodeNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void {
  94. this._loadData(data);
  95. this._babylonScene = scene;
  96. this._rootUrl = rootUrl;
  97. this._successCallback = onSuccess;
  98. this._progressCallback = onProgress;
  99. this._errorCallback = onError;
  100. this.addPendingData(this);
  101. this._loadScene(nodeNames);
  102. this._loadAnimations();
  103. this.removePendingData(this);
  104. }
  105. private _onError(message: string): void {
  106. this._errorCallback(message);
  107. this.dispose();
  108. }
  109. private _onProgress(event: ProgressEvent): void {
  110. this._progressCallback(event);
  111. }
  112. private _onRenderReady(): void {
  113. switch (this._parent.coordinateSystemMode) {
  114. case GLTFLoaderCoordinateSystemMode.AUTO:
  115. if (!this._babylonScene.useRightHandedSystem) {
  116. this._addRightHandToLeftHandRootTransform();
  117. }
  118. break;
  119. case GLTFLoaderCoordinateSystemMode.PASS_THROUGH:
  120. // do nothing
  121. break;
  122. case GLTFLoaderCoordinateSystemMode.FORCE_RIGHT_HANDED:
  123. this._babylonScene.useRightHandedSystem = true;
  124. break;
  125. default:
  126. Tools.Error("Invalid coordinate system mode (" + this._parent.coordinateSystemMode + ")");
  127. break;
  128. }
  129. this._showMeshes();
  130. this._startAnimations();
  131. this._successCallback();
  132. this._renderReadyObservable.notifyObservers(this);
  133. }
  134. private _onLoaderComplete(): void {
  135. this.dispose();
  136. if (this._parent.onComplete) {
  137. this._parent.onComplete();
  138. }
  139. }
  140. private _loadData(data: IGLTFLoaderData): void {
  141. this._gltf = <IGLTF>data.json;
  142. var binaryBuffer: IGLTFBuffer;
  143. var buffers = this._gltf.buffers;
  144. if (buffers.length > 0 && buffers[0].uri === undefined) {
  145. binaryBuffer = buffers[0];
  146. }
  147. if (data.bin) {
  148. if (binaryBuffer) {
  149. if (binaryBuffer.byteLength != data.bin.byteLength) {
  150. Tools.Warn("Binary buffer length (" + binaryBuffer.byteLength + ") from JSON does not match chunk length (" + data.bin.byteLength + ")");
  151. }
  152. }
  153. else {
  154. Tools.Warn("Unexpected BIN chunk");
  155. }
  156. binaryBuffer.loadedData = data.bin;
  157. }
  158. }
  159. private _addRightHandToLeftHandRootTransform(): void {
  160. var rootMesh = new Mesh("root", this._babylonScene);
  161. rootMesh.scaling = new Vector3(1, 1, -1);
  162. rootMesh.rotation.y = Math.PI;
  163. var nodes = this._gltf.nodes;
  164. for (var i = 0; i < nodes.length; i++) {
  165. var mesh = nodes[i].babylonMesh;
  166. if (mesh && !mesh.parent) {
  167. mesh.parent = rootMesh;
  168. }
  169. }
  170. }
  171. private _showMeshes(): void {
  172. var nodes = this._gltf.nodes;
  173. for (var i = 0; i < nodes.length; i++) {
  174. var node = nodes[i];
  175. if (node.babylonMesh) {
  176. node.babylonMesh.isVisible = true;
  177. }
  178. }
  179. }
  180. private _startAnimations(): void {
  181. var animations = this._gltf.animations;
  182. if (!animations) {
  183. return;
  184. }
  185. for (var i = 0; i < animations.length; i++) {
  186. var animation = animations[i];
  187. for (var j = 0; j < animation.targets.length; j++) {
  188. this._babylonScene.beginAnimation(animation.targets[j], 0, Number.MAX_VALUE, true);
  189. }
  190. }
  191. }
  192. private _loadScene(nodeNames: any): void {
  193. var scene = this._gltf.scenes[this._gltf.scene || 0];
  194. var nodeIndices = scene.nodes;
  195. this._traverseNodes(nodeIndices, (node, index, parentNode) => {
  196. node.index = index;
  197. node.parent = parentNode;
  198. return true;
  199. });
  200. if (nodeNames) {
  201. if (!(nodeNames instanceof Array)) {
  202. nodeNames = [nodeNames];
  203. }
  204. var filteredNodeIndices = new Array<number>();
  205. this._traverseNodes(nodeIndices, node => {
  206. if (nodeNames.indexOf(node.name) === -1) {
  207. return true;
  208. }
  209. filteredNodeIndices.push(node.index);
  210. return false;
  211. });
  212. nodeIndices = filteredNodeIndices;
  213. }
  214. this._traverseNodes(nodeIndices, node => this._loadSkin(node));
  215. this._traverseNodes(nodeIndices, node => this._loadMesh(node));
  216. }
  217. private _loadSkin(node: IGLTFNode): boolean {
  218. if (node.skin !== undefined) {
  219. var skin = this._gltf.skins[node.skin];
  220. var skeletonId = "skeleton" + node.skin;
  221. skin.babylonSkeleton = new Skeleton(skin.name || skeletonId, skeletonId, this._babylonScene);
  222. skin.index = node.skin;
  223. for (var i = 0; i < skin.joints.length; i++) {
  224. this._createBone(this._gltf.nodes[skin.joints[i]], skin);
  225. }
  226. if (skin.skeleton === undefined) {
  227. // TODO: handle when skeleton is not defined
  228. throw new Error("Not implemented");
  229. }
  230. if (skin.inverseBindMatrices === undefined) {
  231. // TODO: handle when inverse bind matrices are not defined
  232. throw new Error("Not implemented");
  233. }
  234. var accessor = this._gltf.accessors[skin.inverseBindMatrices];
  235. this._loadAccessorAsync(accessor, data => {
  236. this._traverseNode(skin.skeleton, (node, index, parent) => this._updateBone(node, parent, skin, <Float32Array>data));
  237. });
  238. }
  239. return true;
  240. }
  241. private _updateBone(node: IGLTFNode, parentNode: IGLTFNode, skin: IGLTFSkin, inverseBindMatrixData: Float32Array): boolean {
  242. var jointIndex = skin.joints.indexOf(node.index);
  243. if (jointIndex === -1) {
  244. this._createBone(node, skin);
  245. }
  246. var babylonBone = node.babylonSkinToBones[skin.index];
  247. // TODO: explain the math
  248. var matrix = jointIndex === -1 ? Matrix.Identity() : Matrix.FromArray(inverseBindMatrixData, jointIndex * 16);
  249. matrix.invertToRef(matrix);
  250. if (parentNode) {
  251. babylonBone.setParent(parentNode.babylonSkinToBones[skin.index], false);
  252. matrix.multiplyToRef(babylonBone.getParent().getInvertedAbsoluteTransform(), matrix);
  253. }
  254. babylonBone.updateMatrix(matrix);
  255. return true;
  256. }
  257. private _createBone(node: IGLTFNode, skin: IGLTFSkin): Bone {
  258. var babylonBone = new Bone(node.name || "bone" + node.index, skin.babylonSkeleton);
  259. node.babylonSkinToBones = node.babylonSkinToBones || {};
  260. node.babylonSkinToBones[skin.index] = babylonBone;
  261. node.babylonAnimationTargets = node.babylonAnimationTargets || [];
  262. node.babylonAnimationTargets.push(babylonBone);
  263. return babylonBone;
  264. }
  265. private _loadMesh(node: IGLTFNode): boolean {
  266. var babylonMesh = new Mesh(node.name || "mesh" + node.index, this._babylonScene);
  267. babylonMesh.isVisible = false;
  268. this._loadTransform(node, babylonMesh);
  269. if (node.mesh !== undefined) {
  270. var mesh = this._gltf.meshes[node.mesh];
  271. this._loadMeshData(node, mesh, babylonMesh);
  272. }
  273. babylonMesh.parent = node.parent ? node.parent.babylonMesh : null;
  274. node.babylonMesh = babylonMesh;
  275. node.babylonAnimationTargets = node.babylonAnimationTargets || [];
  276. node.babylonAnimationTargets.push(node.babylonMesh);
  277. if (node.skin !== undefined) {
  278. var skin = this._gltf.skins[node.skin];
  279. babylonMesh.skeleton = skin.babylonSkeleton;
  280. }
  281. if (node.camera !== undefined) {
  282. // TODO: handle cameras
  283. }
  284. return true;
  285. }
  286. private _loadMeshData(node: IGLTFNode, mesh: IGLTFMesh, babylonMesh: Mesh): void {
  287. babylonMesh.name = mesh.name || babylonMesh.name;
  288. var babylonMultiMaterial = new MultiMaterial(babylonMesh.name, this._babylonScene);
  289. babylonMesh.material = babylonMultiMaterial;
  290. var geometry = new Geometry(babylonMesh.name, this._babylonScene, null, false, babylonMesh);
  291. var vertexData = new VertexData();
  292. vertexData.positions = [];
  293. vertexData.indices = [];
  294. var subMeshInfos: { materialIndex: number, verticesStart: number, verticesCount: number, indicesStart: number, indicesCount: number }[] = [];
  295. var loadedPrimitives = 0;
  296. var totalPrimitives = mesh.primitives.length;
  297. for (let i = 0; i < totalPrimitives; i++) {
  298. let primitive = mesh.primitives[i];
  299. if (primitive.mode && primitive.mode !== EMeshPrimitiveMode.TRIANGLES) {
  300. // TODO: handle other primitive modes
  301. throw new Error("Not implemented");
  302. }
  303. this._createMorphTargets(node, mesh, primitive, babylonMesh);
  304. this._loadVertexDataAsync(primitive, subVertexData => {
  305. this._loadMorphTargetsData(mesh, primitive, subVertexData, babylonMesh);
  306. subMeshInfos.push({
  307. materialIndex: i,
  308. verticesStart: vertexData.positions.length,
  309. verticesCount: subVertexData.positions.length,
  310. indicesStart: vertexData.indices.length,
  311. indicesCount: subVertexData.indices.length
  312. });
  313. vertexData.merge(subVertexData);
  314. if (primitive.material === undefined) {
  315. babylonMultiMaterial.subMaterials[i] = this._getDefaultMaterial();
  316. }
  317. else {
  318. this.loadMaterial(primitive.material, (babylonMaterial, isNew) => {
  319. if (isNew && this._parent.onMaterialLoaded) {
  320. this._parent.onMaterialLoaded(babylonMaterial);
  321. }
  322. if (this._renderReady) {
  323. babylonMaterial.forceCompilation(babylonMesh, babylonSubMaterial => {
  324. babylonMultiMaterial.subMaterials[i] = babylonSubMaterial;
  325. });
  326. }
  327. else {
  328. babylonMultiMaterial.subMaterials[i] = babylonMaterial;
  329. }
  330. });
  331. }
  332. if (++loadedPrimitives === totalPrimitives) {
  333. geometry.setAllVerticesData(vertexData, false);
  334. // TODO: optimize this so that sub meshes can be created without being overwritten after setting vertex data.
  335. // Sub meshes must be cleared and created after setting vertex data because of mesh._createGlobalSubMesh.
  336. babylonMesh.subMeshes = [];
  337. subMeshInfos.forEach(info => new SubMesh(info.materialIndex, info.verticesStart, info.verticesCount, info.indicesStart, info.indicesCount, babylonMesh));
  338. }
  339. });
  340. }
  341. }
  342. private _loadVertexDataAsync(primitive: IGLTFMeshPrimitive, onSuccess: (vertexData: VertexData) => void): void {
  343. var attributes = primitive.attributes;
  344. if (!attributes) {
  345. this._onError("Primitive has no attributes");
  346. return;
  347. }
  348. var vertexData = new VertexData();
  349. var loadedAttributes = 0;
  350. var totalAttributes = Object.keys(attributes).length;
  351. for (let semantic in attributes) {
  352. var accessor = this._gltf.accessors[attributes[semantic]];
  353. this._loadAccessorAsync(accessor, data => {
  354. switch (semantic) {
  355. case "NORMAL":
  356. vertexData.normals = <Float32Array>data;
  357. break;
  358. case "POSITION":
  359. vertexData.positions = <Float32Array>data;
  360. break;
  361. case "TANGENT":
  362. vertexData.tangents = <Float32Array>data;
  363. break;
  364. case "TEXCOORD_0":
  365. vertexData.uvs = <Float32Array>data;
  366. break;
  367. case "TEXCOORD_1":
  368. vertexData.uvs2 = <Float32Array>data;
  369. break;
  370. case "JOINTS_0":
  371. vertexData.matricesIndices = new Float32Array(Array.prototype.slice.apply(data));
  372. break;
  373. case "WEIGHTS_0":
  374. vertexData.matricesWeights = <Float32Array>data;
  375. break;
  376. case "COLOR_0":
  377. vertexData.colors = <Float32Array>data;
  378. break;
  379. default:
  380. Tools.Warn("Ignoring unrecognized semantic '" + semantic + "'");
  381. break;
  382. }
  383. if (++loadedAttributes === totalAttributes) {
  384. var indicesAccessor = this._gltf.accessors[primitive.indices];
  385. if (indicesAccessor) {
  386. this._loadAccessorAsync(indicesAccessor, data => {
  387. vertexData.indices = <IndicesArray>data;
  388. onSuccess(vertexData);
  389. });
  390. }
  391. else {
  392. vertexData.indices = new Uint32Array(vertexData.positions.length / 3);
  393. vertexData.indices.forEach((v, i) => vertexData.indices[i] = i);
  394. onSuccess(vertexData);
  395. }
  396. }
  397. });
  398. }
  399. }
  400. private _createMorphTargets(node: IGLTFNode, mesh: IGLTFMesh, primitive: IGLTFMeshPrimitive, babylonMesh: Mesh) {
  401. var targets = primitive.targets;
  402. if (!targets) {
  403. return;
  404. }
  405. if (!babylonMesh.morphTargetManager) {
  406. babylonMesh.morphTargetManager = new MorphTargetManager();
  407. }
  408. for (var index = 0; index < targets.length; index++) {
  409. var weight = node.weights ? node.weights[index] : mesh.weights ? mesh.weights[index] : 0;
  410. babylonMesh.morphTargetManager.addTarget(new MorphTarget("morphTarget" + index, weight));
  411. }
  412. }
  413. private _loadMorphTargetsData(mesh: IGLTFMesh, primitive: IGLTFMeshPrimitive, vertexData: VertexData, babylonMesh: Mesh): void {
  414. var targets = primitive.targets;
  415. if (!targets) {
  416. return;
  417. }
  418. for (var index = 0; index < targets.length; index++) {
  419. let babylonMorphTarget = babylonMesh.morphTargetManager.getTarget(index);
  420. var attributes = targets[index];
  421. for (let semantic in attributes) {
  422. var accessor = this._gltf.accessors[attributes[semantic]];
  423. this._loadAccessorAsync(accessor, data => {
  424. if (accessor.name) {
  425. babylonMorphTarget.name = accessor.name;
  426. }
  427. // glTF stores morph target information as deltas while babylon.js expects the final data.
  428. // As a result we have to add the original data to the delta to calculate the final data.
  429. var values = <Float32Array>data;
  430. switch (semantic) {
  431. case "NORMAL":
  432. GLTFUtils.ForEach(values, (v, i) => values[i] += vertexData.normals[i]);
  433. babylonMorphTarget.setNormals(values);
  434. break;
  435. case "POSITION":
  436. GLTFUtils.ForEach(values, (v, i) => values[i] += vertexData.positions[i]);
  437. babylonMorphTarget.setPositions(values);
  438. break;
  439. case "TANGENT":
  440. // Tangent data for morph targets is stored as xyz delta.
  441. // The vertexData.tangent is stored as xyzw.
  442. // So we need to skip every fourth vertexData.tangent.
  443. for (var i = 0, j = 0; i < values.length; i++, j++) {
  444. values[i] += vertexData.tangents[j];
  445. if ((i + 1) % 3 == 0) {
  446. j++;
  447. }
  448. }
  449. babylonMorphTarget.setTangents(values);
  450. break;
  451. default:
  452. Tools.Warn("Ignoring unrecognized semantic '" + semantic + "'");
  453. break;
  454. }
  455. });
  456. }
  457. }
  458. }
  459. private _loadTransform(node: IGLTFNode, babylonMesh: Mesh): void {
  460. var position: Vector3 = Vector3.Zero();
  461. var rotation: Quaternion = Quaternion.Identity();
  462. var scaling: Vector3 = Vector3.One();
  463. if (node.matrix) {
  464. var mat = Matrix.FromArray(node.matrix);
  465. mat.decompose(scaling, rotation, position);
  466. }
  467. else {
  468. if (node.translation) position = Vector3.FromArray(node.translation);
  469. if (node.rotation) rotation = Quaternion.FromArray(node.rotation);
  470. if (node.scale) scaling = Vector3.FromArray(node.scale);
  471. }
  472. babylonMesh.position = position;
  473. babylonMesh.rotationQuaternion = rotation;
  474. babylonMesh.scaling = scaling;
  475. }
  476. private _traverseNodes(indices: number[], action: (node: IGLTFNode, index: number, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode = null): void {
  477. for (var i = 0; i < indices.length; i++) {
  478. this._traverseNode(indices[i], action, parentNode);
  479. }
  480. }
  481. private _traverseNode(index: number, action: (node: IGLTFNode, index: number, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode = null): void {
  482. var node = this._gltf.nodes[index];
  483. if (!action(node, index, parentNode)) {
  484. return;
  485. }
  486. if (node.children) {
  487. for (var i = 0; i < node.children.length; i++) {
  488. this._traverseNode(node.children[i], action, node);
  489. }
  490. }
  491. }
  492. private _loadAnimations(): void {
  493. var animations = this._gltf.animations;
  494. if (!animations || animations.length === 0) {
  495. return;
  496. }
  497. for (var animationIndex = 0; animationIndex < animations.length; animationIndex++) {
  498. var animation = animations[animationIndex];
  499. for (var channelIndex = 0; channelIndex < animation.channels.length; channelIndex++) {
  500. this._loadAnimationChannel(animation, animationIndex, channelIndex);
  501. }
  502. }
  503. }
  504. private _loadAnimationChannel(animation: IGLTFAnimation, animationIndex: number, channelIndex: number): void {
  505. var channel = animation.channels[channelIndex];
  506. var samplerIndex = channel.sampler;
  507. var sampler = animation.samplers[samplerIndex];
  508. var targetNode = this._gltf.nodes[channel.target.node];
  509. if (!targetNode) {
  510. Tools.Warn("Animation channel target node (" + channel.target.node + ") does not exist");
  511. return;
  512. }
  513. var targetPath = {
  514. "translation": "position",
  515. "rotation": "rotationQuaternion",
  516. "scale": "scaling",
  517. "weights": "influence"
  518. }[channel.target.path];
  519. if (!targetPath) {
  520. Tools.Warn("Animation channel target path '" + channel.target.path + "' is not valid");
  521. return;
  522. }
  523. var animationType = {
  524. "position": Animation.ANIMATIONTYPE_VECTOR3,
  525. "rotationQuaternion": Animation.ANIMATIONTYPE_QUATERNION,
  526. "scaling": Animation.ANIMATIONTYPE_VECTOR3,
  527. "influence": Animation.ANIMATIONTYPE_FLOAT,
  528. }[targetPath];
  529. var inputData: Float32Array;
  530. var outputData: Float32Array;
  531. var checkSuccess = () => {
  532. if (!inputData || !outputData) {
  533. return;
  534. }
  535. var outputBufferOffset = 0;
  536. var getNextOutputValue: () => any = {
  537. "position": () => {
  538. var value = Vector3.FromArray(outputData, outputBufferOffset);
  539. outputBufferOffset += 3;
  540. return value;
  541. },
  542. "rotationQuaternion": () => {
  543. var value = Quaternion.FromArray(outputData, outputBufferOffset);
  544. outputBufferOffset += 4;
  545. return value;
  546. },
  547. "scaling": () => {
  548. var value = Vector3.FromArray(outputData, outputBufferOffset);
  549. outputBufferOffset += 3;
  550. return value;
  551. },
  552. "influence": () => {
  553. var numTargets = targetNode.babylonMesh.morphTargetManager.numTargets;
  554. var value = new Array(numTargets);
  555. for (var i = 0; i < numTargets; i++) {
  556. value[i] = outputData[outputBufferOffset++];
  557. }
  558. return value;
  559. },
  560. }[targetPath];
  561. var getNextKey: (frameIndex) => any = {
  562. "LINEAR": frameIndex => ({
  563. frame: inputData[frameIndex],
  564. value: getNextOutputValue()
  565. }),
  566. "CUBICSPLINE": frameIndex => ({
  567. frame: inputData[frameIndex],
  568. inTangent: getNextOutputValue(),
  569. value: getNextOutputValue(),
  570. outTangent: getNextOutputValue()
  571. }),
  572. }[sampler.interpolation];
  573. var keys = new Array(inputData.length);
  574. for (var frameIndex = 0; frameIndex < inputData.length; frameIndex++) {
  575. keys[frameIndex] = getNextKey(frameIndex);
  576. }
  577. animation.targets = animation.targets || [];
  578. if (targetPath === "influence") {
  579. var morphTargetManager = targetNode.babylonMesh.morphTargetManager;
  580. for (var targetIndex = 0; targetIndex < morphTargetManager.numTargets; targetIndex++) {
  581. var morphTarget = morphTargetManager.getTarget(targetIndex);
  582. var animationName = (animation.name || "anim" + animationIndex) + "_" + targetIndex;
  583. var babylonAnimation = new Animation(animationName, targetPath, 1, animationType);
  584. babylonAnimation.setKeys(keys.map(key => ({
  585. frame: key.frame,
  586. inTangent: key.inTangent ? key.inTangent[targetIndex] : undefined,
  587. value: key.value[targetIndex],
  588. outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
  589. })));
  590. morphTarget.animations.push(babylonAnimation);
  591. animation.targets.push(morphTarget);
  592. }
  593. }
  594. else {
  595. var animationName = animation.name || "anim" + animationIndex;
  596. var babylonAnimation = new Animation(animationName, targetPath, 1, animationType);
  597. babylonAnimation.setKeys(keys);
  598. for (var i = 0; i < targetNode.babylonAnimationTargets.length; i++) {
  599. var target = targetNode.babylonAnimationTargets[i];
  600. target.animations.push(babylonAnimation.clone());
  601. animation.targets.push(target);
  602. }
  603. }
  604. };
  605. this._loadAccessorAsync(this._gltf.accessors[sampler.input], data =>
  606. {
  607. inputData = <Float32Array>data;
  608. checkSuccess();
  609. });
  610. this._loadAccessorAsync(this._gltf.accessors[sampler.output], data =>
  611. {
  612. outputData = <Float32Array>data;
  613. checkSuccess();
  614. });
  615. }
  616. private _loadBufferAsync(index: number, onSuccess: (data: ArrayBufferView) => void): void {
  617. var buffer = this._gltf.buffers[index];
  618. this.addPendingData(buffer);
  619. if (buffer.loadedData) {
  620. setTimeout(() => {
  621. onSuccess(buffer.loadedData);
  622. this.removePendingData(buffer);
  623. });
  624. }
  625. else if (GLTFUtils.IsBase64(buffer.uri)) {
  626. var data = GLTFUtils.DecodeBase64(buffer.uri);
  627. buffer.loadedData = new Uint8Array(data);
  628. setTimeout(() => {
  629. onSuccess(buffer.loadedData);
  630. this.removePendingData(buffer);
  631. });
  632. }
  633. else if (buffer.loadedObservable) {
  634. buffer.loadedObservable.add(buffer => {
  635. onSuccess(buffer.loadedData);
  636. this.removePendingData(buffer);
  637. });
  638. }
  639. else {
  640. buffer.loadedObservable = new Observable<IGLTFBuffer>();
  641. buffer.loadedObservable.add(buffer => {
  642. onSuccess(buffer.loadedData);
  643. this.removePendingData(buffer);
  644. });
  645. Tools.LoadFile(this._rootUrl + buffer.uri, data => {
  646. buffer.loadedData = new Uint8Array(data);
  647. buffer.loadedObservable.notifyObservers(buffer);
  648. buffer.loadedObservable = null;
  649. }, event => {
  650. if (!this._disposed) {
  651. this._onProgress(event);
  652. }
  653. }, this._babylonScene.database, true, request => {
  654. if (!this._disposed) {
  655. this._onError("Failed to load file '" + buffer.uri + "': " + request.status + " " + request.statusText);
  656. this.removePendingData(buffer);
  657. }
  658. });
  659. }
  660. }
  661. private _loadBufferViewAsync(bufferView: IGLTFBufferView, byteOffset: number, byteLength: number, componentType: EComponentType, onSuccess: (data: ArrayBufferView) => void): void {
  662. byteOffset += (bufferView.byteOffset || 0);
  663. this._loadBufferAsync(bufferView.buffer, bufferData => {
  664. if (byteOffset + byteLength > bufferData.byteLength) {
  665. this._onError("Buffer access is out of range");
  666. return;
  667. }
  668. var buffer = bufferData.buffer;
  669. byteOffset += bufferData.byteOffset;
  670. var bufferViewData;
  671. switch (componentType) {
  672. case EComponentType.BYTE:
  673. bufferViewData = new Int8Array(buffer, byteOffset, byteLength);
  674. break;
  675. case EComponentType.UNSIGNED_BYTE:
  676. bufferViewData = new Uint8Array(buffer, byteOffset, byteLength);
  677. break;
  678. case EComponentType.SHORT:
  679. bufferViewData = new Int16Array(buffer, byteOffset, byteLength);
  680. break;
  681. case EComponentType.UNSIGNED_SHORT:
  682. bufferViewData = new Uint16Array(buffer, byteOffset, byteLength);
  683. break;
  684. case EComponentType.UNSIGNED_INT:
  685. bufferViewData = new Uint32Array(buffer, byteOffset, byteLength);
  686. break;
  687. case EComponentType.FLOAT:
  688. bufferViewData = new Float32Array(buffer, byteOffset, byteLength);
  689. break;
  690. default:
  691. this._onError("Invalid component type (" + componentType + ")");
  692. return;
  693. }
  694. onSuccess(bufferViewData);
  695. });
  696. }
  697. private _loadAccessorAsync(accessor: IGLTFAccessor, onSuccess: (data: ArrayBufferView) => void): void {
  698. var bufferView = this._gltf.bufferViews[accessor.bufferView];
  699. var byteOffset = accessor.byteOffset || 0;
  700. var byteLength = accessor.count * this._getByteStrideFromType(accessor);
  701. this._loadBufferViewAsync(bufferView, byteOffset, byteLength, accessor.componentType, onSuccess);
  702. }
  703. private _getByteStrideFromType(accessor: IGLTFAccessor): number {
  704. switch (accessor.type) {
  705. case "SCALAR": return 1;
  706. case "VEC2": return 2;
  707. case "VEC3": return 3;
  708. case "VEC4": return 4;
  709. case "MAT2": return 4;
  710. case "MAT3": return 9;
  711. case "MAT4": return 16;
  712. default:
  713. this._onError("Invalid accessor type (" + accessor.type + ")");
  714. return 0;
  715. }
  716. }
  717. public addPendingData(data: any) {
  718. if (!this._renderReady) {
  719. this._renderPendingCount++;
  720. }
  721. this.addLoaderPendingData(data);
  722. }
  723. public removePendingData(data: any) {
  724. if (!this._renderReady) {
  725. if (--this._renderPendingCount === 0) {
  726. this._renderReady = true;
  727. this._onRenderReady();
  728. }
  729. }
  730. this.removeLoaderPendingData(data);
  731. }
  732. public addLoaderPendingData(data: any) {
  733. this._loaderPendingCount++;
  734. }
  735. public removeLoaderPendingData(data: any) {
  736. if (--this._loaderPendingCount === 0) {
  737. this._onLoaderComplete();
  738. }
  739. }
  740. private _getDefaultMaterial(): Material {
  741. if (!this._defaultMaterial) {
  742. var id = "__gltf_default";
  743. var material = <PBRMaterial>this._babylonScene.getMaterialByName(id);
  744. if (!material) {
  745. material = new PBRMaterial(id, this._babylonScene);
  746. material.sideOrientation = Material.CounterClockWiseSideOrientation;
  747. material.metallic = 1;
  748. material.roughness = 1;
  749. }
  750. this._defaultMaterial = material;
  751. }
  752. return this._defaultMaterial;
  753. }
  754. private _loadMaterialMetallicRoughnessProperties(material: IGLTFMaterial): void {
  755. var babylonMaterial = material.babylonMaterial as PBRMaterial;
  756. // Ensure metallic workflow
  757. babylonMaterial.metallic = 1;
  758. babylonMaterial.roughness = 1;
  759. var properties = material.pbrMetallicRoughness;
  760. if (!properties) {
  761. return;
  762. }
  763. babylonMaterial.albedoColor = properties.baseColorFactor ? Color3.FromArray(properties.baseColorFactor) : new Color3(1, 1, 1);
  764. babylonMaterial.metallic = properties.metallicFactor === undefined ? 1 : properties.metallicFactor;
  765. babylonMaterial.roughness = properties.roughnessFactor === undefined ? 1 : properties.roughnessFactor;
  766. if (properties.baseColorTexture) {
  767. babylonMaterial.albedoTexture = this.loadTexture(properties.baseColorTexture);
  768. }
  769. if (properties.metallicRoughnessTexture) {
  770. babylonMaterial.metallicTexture = this.loadTexture(properties.metallicRoughnessTexture);
  771. babylonMaterial.useMetallnessFromMetallicTextureBlue = true;
  772. babylonMaterial.useRoughnessFromMetallicTextureGreen = true;
  773. babylonMaterial.useRoughnessFromMetallicTextureAlpha = false;
  774. }
  775. this.loadMaterialAlphaProperties(material, properties.baseColorFactor);
  776. }
  777. public loadMaterial(index: number, assign: (babylonMaterial: Material, isNew: boolean) => void): void {
  778. var material = this._gltf.materials[index];
  779. material.index = index;
  780. if (material.babylonMaterial) {
  781. assign(material.babylonMaterial, false);
  782. return;
  783. }
  784. if (GLTFLoaderExtension.LoadMaterial(this, material, assign)) {
  785. return;
  786. }
  787. this.createPbrMaterial(material);
  788. this.loadMaterialBaseProperties(material);
  789. this._loadMaterialMetallicRoughnessProperties(material);
  790. assign(material.babylonMaterial, true);
  791. }
  792. public createPbrMaterial(material: IGLTFMaterial): void {
  793. var babylonMaterial = new PBRMaterial(material.name || "mat" + material.index, this._babylonScene);
  794. babylonMaterial.sideOrientation = Material.CounterClockWiseSideOrientation;
  795. material.babylonMaterial = babylonMaterial;
  796. }
  797. public loadMaterialBaseProperties(material: IGLTFMaterial): void {
  798. var babylonMaterial = material.babylonMaterial as PBRMaterial;
  799. babylonMaterial.emissiveColor = material.emissiveFactor ? Color3.FromArray(material.emissiveFactor) : new Color3(0, 0, 0);
  800. if (material.doubleSided) {
  801. babylonMaterial.backFaceCulling = false;
  802. babylonMaterial.twoSidedLighting = true;
  803. }
  804. if (material.normalTexture) {
  805. babylonMaterial.bumpTexture = this.loadTexture(material.normalTexture);
  806. babylonMaterial.invertNormalMapX = true;
  807. babylonMaterial.invertNormalMapY = true;
  808. if (material.normalTexture.scale !== undefined) {
  809. babylonMaterial.bumpTexture.level = material.normalTexture.scale;
  810. }
  811. }
  812. if (material.occlusionTexture) {
  813. babylonMaterial.ambientTexture = this.loadTexture(material.occlusionTexture);
  814. babylonMaterial.useAmbientInGrayScale = true;
  815. if (material.occlusionTexture.strength !== undefined) {
  816. babylonMaterial.ambientTextureStrength = material.occlusionTexture.strength;
  817. }
  818. }
  819. if (material.emissiveTexture) {
  820. babylonMaterial.emissiveTexture = this.loadTexture(material.emissiveTexture);
  821. }
  822. }
  823. public loadMaterialAlphaProperties(material: IGLTFMaterial, colorFactor?: number[]): void {
  824. var babylonMaterial = material.babylonMaterial as PBRMaterial;
  825. var alphaMode = material.alphaMode || "OPAQUE";
  826. switch (alphaMode) {
  827. case "OPAQUE":
  828. // default is opaque
  829. break;
  830. case "MASK":
  831. case "BLEND":
  832. if (colorFactor) {
  833. babylonMaterial.alpha = colorFactor[3];
  834. }
  835. if (babylonMaterial.albedoTexture) {
  836. babylonMaterial.albedoTexture.hasAlpha = true;
  837. babylonMaterial.useAlphaFromAlbedoTexture = (alphaMode === "BLEND");
  838. }
  839. break;
  840. default:
  841. Tools.Warn("Invalid alpha mode '" + material.alphaMode + "'");
  842. break;
  843. }
  844. }
  845. public loadTexture(textureInfo: IGLTFTextureInfo): Texture {
  846. var texture = this._gltf.textures[textureInfo.index];
  847. var texCoord = textureInfo.texCoord || 0;
  848. if (!texture || texture.source === undefined) {
  849. return null;
  850. }
  851. // check the cache first
  852. var babylonTexture: Texture;
  853. if (texture.babylonTextures) {
  854. babylonTexture = texture.babylonTextures[texCoord];
  855. if (!babylonTexture) {
  856. for (var i = 0; i < texture.babylonTextures.length; i++) {
  857. babylonTexture = texture.babylonTextures[i];
  858. if (babylonTexture) {
  859. babylonTexture = babylonTexture.clone();
  860. babylonTexture.coordinatesIndex = texCoord;
  861. break;
  862. }
  863. }
  864. }
  865. return babylonTexture;
  866. }
  867. var source = this._gltf.images[texture.source];
  868. var sampler = (texture.sampler === undefined ? <IGLTFSampler>{} : this._gltf.samplers[texture.sampler]);
  869. var noMipMaps = (sampler.minFilter === ETextureMinFilter.NEAREST || sampler.minFilter === ETextureMinFilter.LINEAR);
  870. var samplingMode = GLTFUtils.GetTextureSamplingMode(sampler.magFilter, sampler.minFilter);
  871. this.addPendingData(texture);
  872. babylonTexture = new Texture(null, this._babylonScene, noMipMaps, false, samplingMode, () => {
  873. if (!this._disposed) {
  874. this.removePendingData(texture);
  875. }
  876. }, () => {
  877. if (!this._disposed) {
  878. this._onError("Failed to load texture '" + source.uri + "'");
  879. this.removePendingData(texture);
  880. }
  881. });
  882. var setTextureData = data => {
  883. var url = URL.createObjectURL(new Blob([data], { type: source.mimeType }));
  884. this._objectURLs.push(url);
  885. babylonTexture.updateURL(url);
  886. };
  887. if (!source.uri) {
  888. var bufferView = this._gltf.bufferViews[source.bufferView];
  889. this._loadBufferViewAsync(bufferView, 0, bufferView.byteLength, EComponentType.UNSIGNED_BYTE, setTextureData);
  890. }
  891. else if (GLTFUtils.IsBase64(source.uri)) {
  892. setTextureData(new Uint8Array(GLTFUtils.DecodeBase64(source.uri)));
  893. }
  894. else {
  895. Tools.LoadFile(this._rootUrl + source.uri, setTextureData, event => {
  896. if (!this._disposed) {
  897. this._onProgress(event);
  898. }
  899. }, this._babylonScene.database, true, request => {
  900. this._onError("Failed to load file '" + source.uri + "': " + request.status + " " + request.statusText);
  901. });
  902. }
  903. babylonTexture.coordinatesIndex = texCoord;
  904. babylonTexture.wrapU = GLTFUtils.GetTextureWrapMode(sampler.wrapS);
  905. babylonTexture.wrapV = GLTFUtils.GetTextureWrapMode(sampler.wrapT);
  906. babylonTexture.name = texture.name || "texture" + textureInfo.index;
  907. // Cache the texture
  908. texture.babylonTextures = texture.babylonTextures || [];
  909. texture.babylonTextures[texCoord] = babylonTexture;
  910. if (this._parent.onTextureLoaded) {
  911. this._parent.onTextureLoaded(babylonTexture);
  912. }
  913. return babylonTexture;
  914. }
  915. }
  916. BABYLON.GLTFFileLoader.CreateGLTFLoaderV2 = parent => new GLTFLoader(parent);
  917. }