babylon.glTFLoader.ts 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200
  1. /// <reference path="../../../../dist/preview release/babylon.d.ts"/>
  2. /// <reference path="../../../../dist/preview release/loaders/babylon.glTFFileLoader.d.ts"/>
  3. module BABYLON.GLTF2 {
  4. /**
  5. * Values
  6. */
  7. var glTFAnimationPaths = ["translation", "rotation", "scale"];
  8. var babylonAnimationPaths = ["position", "rotationQuaternion", "scaling"];
  9. /**
  10. * Utils
  11. */
  12. var normalizeUVs = (buffer: any): void => {
  13. if (!buffer) {
  14. return;
  15. }
  16. for (var i = 0; i < buffer.length / 2; i++) {
  17. buffer[i * 2 + 1] = 1.0 - buffer[i * 2 + 1];
  18. }
  19. };
  20. var createStringId = (index: number): string => {
  21. return "node" + index;
  22. };
  23. /**
  24. * Returns the animation path (glTF -> Babylon)
  25. */
  26. var getAnimationPath = (path: string): string => {
  27. var index = glTFAnimationPaths.indexOf(path);
  28. if (index !== -1) {
  29. return babylonAnimationPaths[index];
  30. }
  31. return path;
  32. };
  33. /**
  34. * Loads and creates animations
  35. */
  36. var loadAnimations = (runtime: IGLTFRuntime): void => {
  37. var animations = runtime.gltf.animations;
  38. if (!animations) {
  39. return;
  40. }
  41. for (var animationIndex = 0; animationIndex < animations.length; animationIndex++) {
  42. var animation = animations[animationIndex];
  43. if (!animation || !animation.channels || !animation.samplers) {
  44. continue;
  45. }
  46. var lastAnimation: Animation = null;
  47. for (var channelIndex = 0; channelIndex < animation.channels.length; channelIndex++) {
  48. var channel = animation.channels[channelIndex];
  49. if (!channel) {
  50. continue;
  51. }
  52. var sampler = animation.samplers[channel.sampler];
  53. if (!sampler) {
  54. continue;
  55. }
  56. var inputData = sampler.input;
  57. var outputData = sampler.output;
  58. var bufferInput = GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[inputData]);
  59. var bufferOutput = GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[outputData]);
  60. var targetID = channel.target.node;
  61. var targetNode: any = runtime.babylonScene.getNodeByID(createStringId(targetID));
  62. if (targetNode === null) {
  63. Tools.Warn("Creating animation index " + animationIndex + " but cannot find node index " + targetID + " to attach to");
  64. continue;
  65. }
  66. var isBone = targetNode instanceof Bone;
  67. // Get target path (position, rotation or scaling)
  68. var targetPath = channel.target.path;
  69. var targetPathIndex = glTFAnimationPaths.indexOf(targetPath);
  70. if (targetPathIndex !== -1) {
  71. targetPath = babylonAnimationPaths[targetPathIndex];
  72. }
  73. // Determine animation type
  74. var animationType = Animation.ANIMATIONTYPE_MATRIX;
  75. if (!isBone) {
  76. if (targetPath === "rotationQuaternion") {
  77. animationType = Animation.ANIMATIONTYPE_QUATERNION;
  78. targetNode.rotationQuaternion = new Quaternion();
  79. }
  80. else {
  81. animationType = Animation.ANIMATIONTYPE_VECTOR3;
  82. }
  83. }
  84. // Create animation and key frames
  85. var babylonAnimation: Animation = null;
  86. var keys = [];
  87. var arrayOffset = 0;
  88. var modifyKey = false;
  89. if (isBone && lastAnimation && lastAnimation.getKeys().length === bufferInput.length) {
  90. babylonAnimation = lastAnimation;
  91. modifyKey = true;
  92. }
  93. if (!modifyKey) {
  94. var animationName = animation.name || "anim" + animationIndex;
  95. babylonAnimation = new Animation(animationName, isBone ? "_matrix" : targetPath, 1, animationType, Animation.ANIMATIONLOOPMODE_CYCLE);
  96. }
  97. // For each frame
  98. for (var j = 0; j < bufferInput.length; j++) {
  99. var value: any = null;
  100. if (targetPath === "rotationQuaternion") { // VEC4
  101. value = Quaternion.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2], bufferOutput[arrayOffset + 3]]);
  102. arrayOffset += 4;
  103. }
  104. else { // Position and scaling are VEC3
  105. value = Vector3.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2]]);
  106. arrayOffset += 3;
  107. }
  108. if (isBone) {
  109. var bone = <Bone>targetNode;
  110. var translation = Vector3.Zero();
  111. var rotationQuaternion = new Quaternion();
  112. var scaling = Vector3.Zero();
  113. // Warning on decompose
  114. var mat = bone.getBaseMatrix();
  115. if (modifyKey) {
  116. mat = lastAnimation.getKeys()[j].value;
  117. }
  118. mat.decompose(scaling, rotationQuaternion, translation);
  119. if (targetPath === "position") {
  120. translation = value;
  121. }
  122. else if (targetPath === "rotationQuaternion") {
  123. rotationQuaternion = value;
  124. }
  125. else {
  126. scaling = value;
  127. }
  128. value = Matrix.Compose(scaling, rotationQuaternion, translation);
  129. }
  130. if (!modifyKey) {
  131. keys.push({
  132. frame: bufferInput[j],
  133. value: value
  134. });
  135. }
  136. else {
  137. lastAnimation.getKeys()[j].value = value;
  138. }
  139. }
  140. // Finish
  141. if (!modifyKey) {
  142. babylonAnimation.setKeys(keys);
  143. targetNode.animations.push(babylonAnimation);
  144. }
  145. lastAnimation = babylonAnimation;
  146. runtime.babylonScene.stopAnimation(targetNode);
  147. runtime.babylonScene.beginAnimation(targetNode, 0, bufferInput[bufferInput.length - 1], true, 1.0);
  148. }
  149. }
  150. };
  151. /**
  152. * Returns the bones transformation matrix
  153. */
  154. var configureBoneTransformation = (node: IGLTFNode): Matrix => {
  155. var mat: Matrix = null;
  156. if (node.translation || node.rotation || node.scale) {
  157. var scale = Vector3.FromArray(node.scale || [1, 1, 1]);
  158. var rotation = Quaternion.FromArray(node.rotation || [0, 0, 0, 1]);
  159. var position = Vector3.FromArray(node.translation || [0, 0, 0]);
  160. mat = Matrix.Compose(scale, rotation, position);
  161. }
  162. else {
  163. mat = node.matrix ? Matrix.FromArray(node.matrix) : Matrix.Identity();
  164. }
  165. return mat;
  166. };
  167. /**
  168. * Returns the parent bone
  169. */
  170. var getParentBone = (runtime: IGLTFRuntime, skin: IGLTFSkin, index: number, newSkeleton: Skeleton): Bone => {
  171. // Try to find
  172. var nodeStringID = createStringId(index);
  173. for (var i = 0; i < newSkeleton.bones.length; i++) {
  174. if (newSkeleton.bones[i].id === nodeStringID) {
  175. return newSkeleton.bones[i].getParent();
  176. }
  177. }
  178. // Not found, search in gltf nodes
  179. var joints = skin.joints;
  180. for (var j = 0; j < joints.length; j++) {
  181. var parentID = joints[j];
  182. var parent = runtime.gltf.nodes[parentID];
  183. var children = parent.children;
  184. for (var i = 0; i < children.length; i++) {
  185. var childID = children[i];
  186. var child = runtime.gltf.nodes[childID];
  187. if (!nodeIsInJoints(skin, childID)) {
  188. continue;
  189. }
  190. if (childID === index)
  191. {
  192. var mat = configureBoneTransformation(parent);
  193. var bone = new Bone(parent.name || createStringId(parentID), newSkeleton, getParentBone(runtime, skin, parentID, newSkeleton), mat);
  194. bone.id = createStringId(parentID);
  195. return bone;
  196. }
  197. }
  198. }
  199. return null;
  200. }
  201. /**
  202. * Returns the appropriate root node
  203. */
  204. var getNodeToRoot = (nodesToRoot: INodeToRoot[], index: number): Bone => {
  205. for (var i = 0; i < nodesToRoot.length; i++) {
  206. var nodeToRoot = nodesToRoot[i];
  207. if (nodeToRoot.node.children) {
  208. for (var j = 0; j < nodeToRoot.node.children.length; j++) {
  209. var child = nodeToRoot.node.children[j];
  210. if (child === index) {
  211. return nodeToRoot.bone;
  212. }
  213. }
  214. }
  215. }
  216. return null;
  217. };
  218. /**
  219. * Returns the node with the node index
  220. */
  221. var getJointNode = (runtime: IGLTFRuntime, index: number): IJointNode => {
  222. var node = runtime.gltf.nodes[index];
  223. if (node) {
  224. return {
  225. node: node,
  226. index: index
  227. };
  228. }
  229. return null;
  230. }
  231. /**
  232. * Checks if a nodes is in joints
  233. */
  234. var nodeIsInJoints = (skin: IGLTFSkin, index: number): boolean => {
  235. for (var i = 0; i < skin.joints.length; i++) {
  236. if (skin.joints[i] === index) {
  237. return true;
  238. }
  239. }
  240. return false;
  241. }
  242. /**
  243. * Fills the nodes to root for bones and builds hierarchy
  244. */
  245. var getNodesToRoot = (runtime: IGLTFRuntime, newSkeleton: Skeleton, skin: IGLTFSkin, nodesToRoot: INodeToRoot[]): void => {
  246. // Creates nodes for root
  247. for (var i = 0; i < runtime.gltf.nodes.length; i++) {
  248. var node = runtime.gltf.nodes[i];
  249. if (nodeIsInJoints(skin, i)) {
  250. continue;
  251. }
  252. // Create node to root bone
  253. var mat = configureBoneTransformation(node);
  254. var bone = new Bone(node.name || createStringId(i), newSkeleton, null, mat);
  255. bone.id = createStringId(i);
  256. nodesToRoot.push({ bone: bone, node: node, index: i });
  257. }
  258. // Parenting
  259. for (var i = 0; i < nodesToRoot.length; i++) {
  260. var nodeToRoot = nodesToRoot[i];
  261. var children = nodeToRoot.node.children;
  262. if (children) {
  263. for (var j = 0; j < children.length; j++) {
  264. var child: INodeToRoot = null;
  265. for (var k = 0; k < nodesToRoot.length; k++) {
  266. if (nodesToRoot[k].index === children[j]) {
  267. child = nodesToRoot[k];
  268. break;
  269. }
  270. }
  271. if (child) {
  272. (<any>child.bone)._parent = nodeToRoot.bone;
  273. nodeToRoot.bone.children.push(child.bone);
  274. }
  275. }
  276. }
  277. }
  278. };
  279. /**
  280. * Imports a skeleton
  281. */
  282. var importSkeleton = (runtime: IGLTFRuntime, skinNode: IGLTFNode, skin: IGLTFSkin): Skeleton => {
  283. var name = skin.name || "skin" + skinNode.skin;
  284. var babylonSkeleton = <Skeleton>skin.babylonSkeleton;
  285. if (!babylonSkeleton) {
  286. babylonSkeleton = new Skeleton(name, "skin" + skinNode.skin, runtime.babylonScene);
  287. }
  288. if (!skin.babylonSkeleton) {
  289. return babylonSkeleton;
  290. }
  291. // Matrices
  292. var accessor = runtime.gltf.accessors[skin.inverseBindMatrices];
  293. var buffer = GLTFUtils.GetBufferFromAccessor(runtime, accessor);
  294. // Find the root bones
  295. var nodesToRoot: INodeToRoot[] = [];
  296. var nodesToRootToAdd: Bone[] = [];
  297. getNodesToRoot(runtime, babylonSkeleton, skin, nodesToRoot);
  298. babylonSkeleton.bones = [];
  299. // Joints
  300. for (var i = 0; i < skin.joints.length; i++) {
  301. var jointNode = getJointNode(runtime, skin.joints[i]);
  302. var node = jointNode.node;
  303. if (!node) {
  304. Tools.Warn("Joint index " + skin.joints[i] + " does not exist");
  305. continue;
  306. }
  307. var index = jointNode.index;
  308. var stringID = createStringId(index);
  309. // Optimize, if the bone already exists...
  310. var existingBone = runtime.babylonScene.getBoneByID(stringID);
  311. if (existingBone) {
  312. babylonSkeleton.bones.push(existingBone);
  313. continue;
  314. }
  315. // Search for parent bone
  316. var foundBone = false;
  317. var parentBone: Bone = null;
  318. for (var j = 0; j < i; j++) {
  319. var joint: IGLTFNode = getJointNode(runtime, skin.joints[j]).node;
  320. if (!joint) {
  321. Tools.Warn("Joint index " + skin.joints[j] + " does not exist when looking for parent");
  322. continue;
  323. }
  324. var children = joint.children;
  325. foundBone = false;
  326. for (var k = 0; k < children.length; k++) {
  327. if (children[k] === index) {
  328. parentBone = getParentBone(runtime, skin, skin.joints[j], babylonSkeleton);
  329. foundBone = true;
  330. break;
  331. }
  332. }
  333. if (foundBone) {
  334. break;
  335. }
  336. }
  337. // Create bone
  338. var mat = configureBoneTransformation(node);
  339. if (!parentBone && nodesToRoot.length > 0) {
  340. parentBone = getNodeToRoot(nodesToRoot, index);
  341. if (parentBone) {
  342. if (nodesToRootToAdd.indexOf(parentBone) === -1) {
  343. nodesToRootToAdd.push(parentBone);
  344. }
  345. }
  346. }
  347. var bone = new Bone(node.name || stringID, babylonSkeleton, parentBone, mat);
  348. bone.id = stringID;
  349. }
  350. // Polish
  351. var bones = babylonSkeleton.bones;
  352. babylonSkeleton.bones = [];
  353. for (var i = 0; i < skin.joints.length; i++) {
  354. var jointNode = getJointNode(runtime, skin.joints[i]);
  355. if (!jointNode) {
  356. continue;
  357. }
  358. var jointNodeStringId = createStringId(jointNode.index);
  359. for (var j = 0; j < bones.length; j++) {
  360. if (bones[j].id === jointNodeStringId) {
  361. babylonSkeleton.bones.push(bones[j]);
  362. break;
  363. }
  364. }
  365. }
  366. babylonSkeleton.prepare();
  367. // Finish
  368. for (var i = 0; i < nodesToRootToAdd.length; i++) {
  369. babylonSkeleton.bones.push(nodesToRootToAdd[i]);
  370. }
  371. return babylonSkeleton;
  372. };
  373. /**
  374. * Gets a material
  375. */
  376. var getMaterial = (runtime: IGLTFRuntime, index?: number): PBRMaterial => {
  377. if (index === undefined) {
  378. return GLTFUtils.GetDefaultMaterial(runtime);
  379. }
  380. var materials = runtime.gltf.materials;
  381. if (!materials || index < 0 || index >= materials.length) {
  382. Tools.Error("Invalid material index");
  383. return GLTFUtils.GetDefaultMaterial(runtime);
  384. }
  385. var material = runtime.gltf.materials[index].babylonMaterial;
  386. if (!material)
  387. {
  388. return GLTFUtils.GetDefaultMaterial(runtime);
  389. }
  390. return material;
  391. }
  392. /**
  393. * Imports a mesh and its geometries
  394. */
  395. var importMesh = (runtime: IGLTFRuntime, node: IGLTFNode, mesh: IGLTFMesh): Mesh => {
  396. var name = mesh.name || node.name || "mesh" + node.mesh;
  397. var babylonMesh = <Mesh>node.babylonNode;
  398. if (!babylonMesh) {
  399. babylonMesh = new Mesh(name, runtime.babylonScene);
  400. }
  401. if (!node.babylonNode) {
  402. return babylonMesh;
  403. }
  404. var multiMat = new MultiMaterial(name, runtime.babylonScene);
  405. if (!babylonMesh.material) {
  406. babylonMesh.material = multiMat;
  407. }
  408. var vertexData = new VertexData();
  409. var geometry = new Geometry(name, runtime.babylonScene, vertexData, false, babylonMesh);
  410. var verticesStarts = [];
  411. var verticesCounts = [];
  412. var indexStarts = [];
  413. var indexCounts = [];
  414. // Positions, normals and UVs
  415. for (var index = 0; index < mesh.primitives.length; index++) {
  416. // Temporary vertex data
  417. var tempVertexData = new VertexData();
  418. var primitive = mesh.primitives[index];
  419. if (primitive.mode !== EMeshPrimitiveMode.TRIANGLES) {
  420. // continue;
  421. }
  422. var attributes = primitive.attributes;
  423. var accessor: IGLTFAccessor = null;
  424. var buffer: any = null;
  425. // Set positions, normal and uvs
  426. for (var semantic in attributes) {
  427. // Link accessor and buffer view
  428. accessor = runtime.gltf.accessors[attributes[semantic]];
  429. buffer = GLTFUtils.GetBufferFromAccessor(runtime, accessor);
  430. if (semantic === "NORMAL") {
  431. tempVertexData.normals = new Float32Array(buffer.length);
  432. (<Float32Array>tempVertexData.normals).set(buffer);
  433. }
  434. else if (semantic === "POSITION") {
  435. tempVertexData.positions = new Float32Array(buffer.length);
  436. (<Float32Array>tempVertexData.positions).set(buffer);
  437. verticesCounts.push(tempVertexData.positions.length);
  438. }
  439. else if (semantic === "TANGENT") {
  440. tempVertexData.tangents = new Float32Array(buffer.length);
  441. (<Float32Array>tempVertexData.tangents).set(buffer);
  442. }
  443. else if (semantic.indexOf("TEXCOORD_") !== -1) {
  444. var channel = Number(semantic.split("_")[1]);
  445. var uvKind = VertexBuffer.UVKind + (channel === 0 ? "" : (channel + 1));
  446. var uvs = new Float32Array(buffer.length);
  447. (<Float32Array>uvs).set(buffer);
  448. normalizeUVs(uvs);
  449. tempVertexData.set(uvs, uvKind);
  450. }
  451. else if (semantic === "JOINT") {
  452. tempVertexData.matricesIndices = new Float32Array(buffer.length);
  453. (<Float32Array>tempVertexData.matricesIndices).set(buffer);
  454. }
  455. else if (semantic === "WEIGHT") {
  456. tempVertexData.matricesWeights = new Float32Array(buffer.length);
  457. (<Float32Array>tempVertexData.matricesWeights).set(buffer);
  458. }
  459. else if (semantic === "COLOR_0") {
  460. tempVertexData.colors = new Float32Array(buffer.length);
  461. (<Float32Array>tempVertexData.colors).set(buffer);
  462. }
  463. else {
  464. Tools.Warn("Ignoring unrecognized semantic '" + semantic + "'");
  465. }
  466. }
  467. // Indices
  468. accessor = runtime.gltf.accessors[primitive.indices];
  469. if (accessor) {
  470. buffer = GLTFUtils.GetBufferFromAccessor(runtime, accessor);
  471. tempVertexData.indices = new Int32Array(buffer.length);
  472. (<Float32Array>tempVertexData.indices).set(buffer);
  473. indexCounts.push(tempVertexData.indices.length);
  474. }
  475. else {
  476. // Set indices on the fly
  477. var indices: number[] = [];
  478. for (var j = 0; j < tempVertexData.positions.length / 3; j++) {
  479. indices.push(j);
  480. }
  481. tempVertexData.indices = new Int32Array(indices);
  482. indexCounts.push(tempVertexData.indices.length);
  483. }
  484. vertexData.merge(tempVertexData);
  485. tempVertexData = undefined;
  486. // Sub material
  487. var material = getMaterial(runtime, primitive.material);
  488. multiMat.subMaterials.push(material);
  489. // Update vertices start and index start
  490. verticesStarts.push(verticesStarts.length === 0 ? 0 : verticesStarts[verticesStarts.length - 1] + verticesCounts[verticesCounts.length - 2]);
  491. indexStarts.push(indexStarts.length === 0 ? 0 : indexStarts[indexStarts.length - 1] + indexCounts[indexCounts.length - 2]);
  492. }
  493. // Apply geometry
  494. geometry.setAllVerticesData(vertexData, false);
  495. babylonMesh.computeWorldMatrix(true);
  496. // Apply submeshes
  497. babylonMesh.subMeshes = [];
  498. for (var index = 0; index < mesh.primitives.length; index++) {
  499. if (mesh.primitives[index].mode !== EMeshPrimitiveMode.TRIANGLES) {
  500. //continue;
  501. }
  502. var subMesh = new SubMesh(index, verticesStarts[index], verticesCounts[index], indexStarts[index], indexCounts[index], babylonMesh, babylonMesh, true);
  503. }
  504. // Finish
  505. return babylonMesh;
  506. };
  507. /**
  508. * Configures node transformation
  509. */
  510. var configureNode = (babylonNode: Mesh | TargetCamera, node: IGLTFNode): void => {
  511. var position = Vector3.Zero();
  512. var rotation = Quaternion.Identity();
  513. var scaling = new Vector3(1, 1, 1);
  514. if (node.matrix) {
  515. var mat = Matrix.FromArray(node.matrix);
  516. mat.decompose(scaling, rotation, position);
  517. }
  518. else {
  519. if (node.translation) {
  520. position = Vector3.FromArray(node.translation);
  521. }
  522. if (node.rotation) {
  523. rotation = Quaternion.FromArray(node.rotation);
  524. }
  525. if (node.scale) {
  526. scaling = Vector3.FromArray(node.scale);
  527. }
  528. }
  529. babylonNode.position = position;
  530. babylonNode.rotationQuaternion = rotation;
  531. if (babylonNode instanceof Mesh) {
  532. var mesh = <Mesh>babylonNode;
  533. mesh.scaling = scaling;
  534. }
  535. };
  536. /**
  537. * Imports a node
  538. */
  539. var importNode = (runtime: IGLTFRuntime, node: IGLTFNode): Node => {
  540. var babylonNode: Mesh | TargetCamera = null;
  541. if (runtime.importOnlyMeshes && (node.skin !== undefined || node.mesh !== undefined)) {
  542. if (runtime.importMeshesNames.length > 0 && runtime.importMeshesNames.indexOf(node.name) === -1) {
  543. return null;
  544. }
  545. }
  546. // Meshes
  547. if (node.skin !== undefined) {
  548. if (node.mesh !== undefined) {
  549. var skin = runtime.gltf.skins[node.skin];
  550. var newMesh = importMesh(runtime, node, runtime.gltf.meshes[node.mesh]);
  551. var newSkeleton = importSkeleton(runtime, node, skin);
  552. if (newSkeleton)
  553. {
  554. newMesh.skeleton = newSkeleton;
  555. skin.babylonSkeleton = newSkeleton;
  556. }
  557. babylonNode = newMesh;
  558. }
  559. }
  560. else if (node.mesh !== undefined) {
  561. babylonNode = importMesh(runtime, node, runtime.gltf.meshes[node.mesh]);
  562. }
  563. // Cameras
  564. else if (node.camera !== undefined && !node.babylonNode && !runtime.importOnlyMeshes) {
  565. var camera = runtime.gltf.cameras[node.camera];
  566. if (camera !== undefined) {
  567. if (camera.type === "orthographic") {
  568. var orthographicCamera = camera.orthographic;
  569. var orthoCamera = new FreeCamera(node.name || "camera" + node.camera, Vector3.Zero(), runtime.babylonScene);
  570. orthoCamera.mode = Camera.ORTHOGRAPHIC_CAMERA;
  571. orthoCamera.attachControl(runtime.babylonScene.getEngine().getRenderingCanvas());
  572. babylonNode = orthoCamera;
  573. }
  574. else if (camera.type === "perspective") {
  575. var perspectiveCamera = camera.perspective;
  576. var persCamera = new FreeCamera(node.name || "camera" + node.camera, Vector3.Zero(), runtime.babylonScene);
  577. persCamera.attachControl(runtime.babylonScene.getEngine().getRenderingCanvas());
  578. if (!perspectiveCamera.aspectRatio) {
  579. perspectiveCamera.aspectRatio = runtime.babylonScene.getEngine().getRenderWidth() / runtime.babylonScene.getEngine().getRenderHeight();
  580. }
  581. if (perspectiveCamera.znear && perspectiveCamera.zfar) {
  582. persCamera.maxZ = perspectiveCamera.zfar;
  583. persCamera.minZ = perspectiveCamera.znear;
  584. }
  585. babylonNode = persCamera;
  586. }
  587. }
  588. }
  589. // Empty node
  590. if (node.babylonNode) {
  591. return node.babylonNode;
  592. }
  593. else if (babylonNode === null) {
  594. var dummy = new Mesh(node.name || "mesh" + node.mesh, runtime.babylonScene);
  595. node.babylonNode = dummy;
  596. babylonNode = dummy;
  597. }
  598. if (babylonNode !== null) {
  599. configureNode(babylonNode, node);
  600. babylonNode.updateCache(true);
  601. node.babylonNode = babylonNode;
  602. }
  603. return babylonNode;
  604. };
  605. /**
  606. * Traverses nodes and creates them
  607. */
  608. var traverseNodes = (runtime: IGLTFRuntime, index: number, parent: Node, meshIncluded?: boolean): void => {
  609. var node = runtime.gltf.nodes[index];
  610. var newNode: Node = null;
  611. if (runtime.importOnlyMeshes && !meshIncluded) {
  612. if (runtime.importMeshesNames.indexOf(node.name) !== -1 || runtime.importMeshesNames.length === 0) {
  613. meshIncluded = true;
  614. }
  615. else {
  616. meshIncluded = false;
  617. }
  618. }
  619. else {
  620. meshIncluded = true;
  621. }
  622. if (meshIncluded) {
  623. newNode = importNode(runtime, node);
  624. if (newNode !== null) {
  625. newNode.id = createStringId(index);
  626. newNode.parent = parent;
  627. }
  628. }
  629. if (node.children) {
  630. for (var i = 0; i < node.children.length; i++) {
  631. traverseNodes(runtime, node.children[i], newNode, meshIncluded);
  632. }
  633. }
  634. };
  635. var importScene = (runtime: IGLTFRuntime): void => {
  636. var scene = runtime.gltf.scene || 0;
  637. var scenes = runtime.gltf.scenes;
  638. if (scenes) {
  639. var nodes = scenes[scene].nodes;
  640. for (var i = 0; i < nodes.length; i++) {
  641. traverseNodes(runtime, nodes[i], null);
  642. }
  643. }
  644. else {
  645. for (var i = 0; i < runtime.gltf.nodes.length; i++) {
  646. traverseNodes(runtime, i, null);
  647. }
  648. }
  649. }
  650. /**
  651. * do stuff after buffers are loaded (e.g. hook up materials, load animations, etc.)
  652. */
  653. var postLoad = (runtime: IGLTFRuntime): void => {
  654. importScene(runtime);
  655. // Set animations
  656. loadAnimations(runtime);
  657. for (var i = 0; i < runtime.babylonScene.skeletons.length; i++) {
  658. var skeleton = runtime.babylonScene.skeletons[i];
  659. runtime.babylonScene.beginAnimation(skeleton, 0, Number.MAX_VALUE, true, 1.0);
  660. }
  661. };
  662. var importMaterials = (runtime: IGLTFRuntime): void => {
  663. if (runtime.gltf.materials) {
  664. for (var i = 0; i < runtime.gltf.materials.length; i++) {
  665. GLTFLoaderExtension.LoadMaterial(runtime, i);
  666. }
  667. }
  668. };
  669. class BinaryReader {
  670. private _arrayBuffer: ArrayBuffer;
  671. private _dataView: DataView;
  672. private _byteOffset: number;
  673. constructor(arrayBuffer: ArrayBuffer) {
  674. this._arrayBuffer = arrayBuffer;
  675. this._dataView = new DataView(arrayBuffer);
  676. this._byteOffset = 0;
  677. }
  678. public getPosition(): number {
  679. return this._byteOffset;
  680. }
  681. public getLength(): number {
  682. return this._arrayBuffer.byteLength;
  683. }
  684. public readUint32(): number {
  685. var value = this._dataView.getUint32(this._byteOffset, true);
  686. this._byteOffset += 4;
  687. return value;
  688. }
  689. public readUint8Array(length: number): Uint8Array {
  690. var value = new Uint8Array(this._arrayBuffer, this._byteOffset, length);
  691. this._byteOffset += length;
  692. return value;
  693. }
  694. public skipBytes(length: number): void {
  695. this._byteOffset += length;
  696. }
  697. }
  698. /**
  699. * glTF File Loader Plugin
  700. */
  701. export class GLTFLoader implements IGLTFLoader {
  702. public static Extensions: { [name: string]: GLTFLoaderExtension } = {};
  703. public static RegisterExtension(extension: GLTFLoaderExtension): void {
  704. if (GLTFLoader.Extensions[extension.name]) {
  705. Tools.Error("Tool with the same name \"" + extension.name + "\" already exists");
  706. return;
  707. }
  708. GLTFLoader.Extensions[extension.name] = extension;
  709. }
  710. public static LoadMaterial(runtime: IGLTFRuntime, index: number): IGLTFMaterial {
  711. var material = runtime.gltf.materials[index];
  712. if (!material) return null;
  713. material.babylonMaterial = new PBRMaterial(material.name || "mat" + index, runtime.babylonScene);
  714. material.babylonMaterial.sideOrientation = Material.CounterClockWiseSideOrientation;
  715. material.babylonMaterial.useScalarInLinearSpace = true;
  716. return material;
  717. }
  718. public static LoadMetallicRoughnessMaterialProperties = (runtime: IGLTFRuntime, material: IGLTFMaterial): void => {
  719. var properties = material.pbrMetallicRoughness;
  720. if (!properties) return;
  721. material.babylonMaterial.albedoColor = properties.baseColorFactor ? Color3.FromArray(properties.baseColorFactor) : new Color3(1, 1, 1);
  722. material.babylonMaterial.metallic = properties.metallicFactor === undefined ? 1 : properties.metallicFactor;
  723. material.babylonMaterial.roughness = properties.roughnessFactor === undefined ? 1 : properties.roughnessFactor;
  724. if (properties.baseColorTexture) {
  725. GLTFLoader.LoadTextureAsync(runtime, properties.baseColorTexture,
  726. texture => {
  727. material.babylonMaterial.albedoTexture = texture;
  728. GLTFLoader.LoadAlphaProperties(runtime, material);
  729. },
  730. () => {
  731. Tools.Warn("Failed to load base color texture");
  732. });
  733. }
  734. if (properties.metallicRoughnessTexture) {
  735. GLTFLoader.LoadTextureAsync(runtime, properties.metallicRoughnessTexture,
  736. texture => {
  737. material.babylonMaterial.metallicTexture = texture;
  738. material.babylonMaterial.useMetallnessFromMetallicTextureBlue = true;
  739. material.babylonMaterial.useRoughnessFromMetallicTextureGreen = true;
  740. material.babylonMaterial.useRoughnessFromMetallicTextureAlpha = false;
  741. },
  742. () => {
  743. Tools.Warn("Failed to load metallic roughness texture");
  744. });
  745. }
  746. }
  747. public static LoadCommonMaterialProperties(runtime: IGLTFRuntime, material: IGLTFMaterial): void {
  748. if (material.normalTexture) {
  749. GLTFLoader.LoadTextureAsync(runtime, material.normalTexture, babylonTexture => {
  750. material.babylonMaterial.bumpTexture = babylonTexture;
  751. if (material.normalTexture.scale !== undefined) {
  752. material.babylonMaterial.bumpTexture.level = material.normalTexture.scale;
  753. }
  754. }, () => Tools.Warn("Failed to load normal texture"));
  755. }
  756. if (material.occlusionTexture) {
  757. GLTFLoader.LoadTextureAsync(runtime, material.occlusionTexture, babylonTexture => {
  758. material.babylonMaterial.ambientTexture = babylonTexture;
  759. material.babylonMaterial.useAmbientInGrayScale = true;
  760. if (material.occlusionTexture.strength !== undefined) {
  761. material.babylonMaterial.ambientTextureStrength = material.occlusionTexture.strength;
  762. }
  763. }, () => Tools.Warn("Failed to load occlusion texture"));
  764. }
  765. material.babylonMaterial.useEmissiveAsIllumination = (material.emissiveFactor || material.emissiveTexture) ? true : false;
  766. material.babylonMaterial.emissiveColor = material.emissiveFactor ? Color3.FromArray(material.emissiveFactor) : new Color3(0, 0, 0);
  767. if (material.emissiveTexture) {
  768. GLTFLoader.LoadTextureAsync(runtime, material.emissiveTexture, babylonTexture => {
  769. material.babylonMaterial.emissiveTexture = babylonTexture;
  770. }, () => Tools.Warn("Failed to load emissive texture"));
  771. }
  772. if (material.doubleSided) {
  773. material.babylonMaterial.backFaceCulling = false;
  774. material.babylonMaterial.twoSidedLighting = true;
  775. }
  776. }
  777. public static LoadAlphaProperties(runtime: IGLTFRuntime, material: IGLTFMaterial): void {
  778. var alphaMode = material.alphaMode || "OPAQUE";
  779. switch (alphaMode) {
  780. case "OPAQUE":
  781. // default is opaque
  782. break;
  783. case "MASK":
  784. material.babylonMaterial.albedoTexture.hasAlpha = true;
  785. material.babylonMaterial.useAlphaFromAlbedoTexture = false;
  786. material.babylonMaterial.alphaMode = Engine.ALPHA_DISABLE;
  787. break;
  788. case "BLEND":
  789. material.babylonMaterial.albedoTexture.hasAlpha = true;
  790. material.babylonMaterial.useAlphaFromAlbedoTexture = true;
  791. material.babylonMaterial.alphaMode = Engine.ALPHA_COMBINE;
  792. break;
  793. default:
  794. Tools.Error("Invalid alpha mode '" + material.alphaMode + "'");
  795. }
  796. }
  797. public static LoadTextureAsync(runtime: IGLTFRuntime, textureInfo: IGLTFTextureInfo, onSuccess: (babylonTexture: Texture) => void, onError: () => void): void {
  798. var texture = runtime.gltf.textures[textureInfo.index];
  799. if (!texture || texture.source === undefined) {
  800. onError();
  801. return;
  802. }
  803. if (texture.babylonTexture) {
  804. onSuccess(texture.babylonTexture);
  805. return;
  806. }
  807. var source = runtime.gltf.images[texture.source];
  808. if (source.uri === undefined) {
  809. var bufferView: IGLTFBufferView = runtime.gltf.bufferViews[source.bufferView];
  810. var buffer = GLTFUtils.GetBufferFromBufferView(runtime, bufferView, 0, bufferView.byteLength, EComponentType.UNSIGNED_BYTE);
  811. GLTFLoader.CreateTextureAsync(runtime, textureInfo, buffer, source.mimeType, onSuccess, onError);
  812. }
  813. else if (GLTFUtils.IsBase64(source.uri)) {
  814. GLTFLoader.CreateTextureAsync(runtime, textureInfo, new Uint8Array(GLTFUtils.DecodeBase64(source.uri)), source.mimeType, onSuccess, onError);
  815. }
  816. else {
  817. Tools.LoadFile(runtime.rootUrl + source.uri, data => {
  818. GLTFLoader.CreateTextureAsync(runtime, textureInfo, new Uint8Array(data), source.mimeType, onSuccess, onError);
  819. }, null, null, true, onError);
  820. }
  821. }
  822. public static CreateTextureAsync(runtime: IGLTFRuntime, textureInfo: IGLTFTextureInfo, buffer: ArrayBufferView, mimeType: string, onSuccess: (babylonTexture: Texture) => void, onError: () => void): void {
  823. var texture = runtime.gltf.textures[textureInfo.index];
  824. if (!texture || texture.source === undefined) {
  825. onError();
  826. return;
  827. }
  828. if (texture.babylonTexture) {
  829. onSuccess(texture.babylonTexture);
  830. return;
  831. }
  832. var sampler: IGLTFSampler = texture.sampler ? runtime.gltf.samplers[texture.sampler] : {};
  833. var createMipMaps =
  834. (sampler.minFilter === ETextureMinFilter.NEAREST_MIPMAP_NEAREST) ||
  835. (sampler.minFilter === ETextureMinFilter.NEAREST_MIPMAP_LINEAR) ||
  836. (sampler.minFilter === ETextureMinFilter.LINEAR_MIPMAP_NEAREST) ||
  837. (sampler.minFilter === ETextureMinFilter.LINEAR_MIPMAP_LINEAR);
  838. var samplingMode = Texture.BILINEAR_SAMPLINGMODE;
  839. var blob = new Blob([buffer], { type: mimeType });
  840. var blobURL = URL.createObjectURL(blob);
  841. var revokeBlobURL = () => URL.revokeObjectURL(blobURL);
  842. texture.babylonTexture = new Texture(blobURL, runtime.babylonScene, !createMipMaps, true, samplingMode, revokeBlobURL, revokeBlobURL);
  843. texture.babylonTexture.coordinatesIndex = textureInfo.texCoord === undefined ? 0 : textureInfo.texCoord;
  844. texture.babylonTexture.wrapU = GLTFUtils.GetWrapMode(sampler.wrapS);
  845. texture.babylonTexture.wrapV = GLTFUtils.GetWrapMode(sampler.wrapT);
  846. texture.babylonTexture.name = texture.name;
  847. onSuccess(texture.babylonTexture);
  848. }
  849. /**
  850. * Import meshes
  851. */
  852. public importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError?: () => void): boolean {
  853. scene.useRightHandedSystem = true;
  854. var runtime = this._createRuntime(scene, data, rootUrl, true);
  855. if (!runtime) {
  856. if (onError) onError();
  857. return;
  858. }
  859. if (meshesNames === "") {
  860. runtime.importMeshesNames = [];
  861. }
  862. else if (typeof meshesNames === "string") {
  863. runtime.importMeshesNames = [meshesNames];
  864. }
  865. else if (meshesNames && !(meshesNames instanceof Array)) {
  866. runtime.importMeshesNames = [meshesNames];
  867. }
  868. else {
  869. runtime.importMeshesNames = [];
  870. Tools.Warn("Argument meshesNames must be of type string or string[]");
  871. }
  872. // Load scene
  873. importScene(runtime);
  874. var meshes = [];
  875. var skeletons = [];
  876. // Fill arrays of meshes and skeletons
  877. for (var i = 0; i < runtime.gltf.nodes.length; i++) {
  878. var node = runtime.gltf.nodes[i];
  879. if (node.babylonNode instanceof AbstractMesh) {
  880. meshes.push(<AbstractMesh>node.babylonNode);
  881. }
  882. }
  883. for (var i = 0; i < runtime.gltf.skins.length; i++) {
  884. var skin = runtime.gltf.skins[i];
  885. if (skin.babylonSkeleton instanceof Skeleton) {
  886. skeletons.push(skin.babylonSkeleton);
  887. }
  888. }
  889. // Load buffers, materials, etc.
  890. this._loadBuffersAsync(runtime, () => {
  891. importMaterials(runtime);
  892. postLoad(runtime);
  893. if (!BABYLON.GLTFFileLoader.IncrementalLoading && onSuccess) {
  894. onSuccess(meshes, null, skeletons);
  895. }
  896. }, onError);
  897. if (BABYLON.GLTFFileLoader.IncrementalLoading && onSuccess) {
  898. onSuccess(meshes, null, skeletons);
  899. }
  900. return true;
  901. }
  902. /**
  903. * Load scene
  904. */
  905. public loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void): boolean {
  906. scene.useRightHandedSystem = true;
  907. var runtime = this._createRuntime(scene, data, rootUrl, false);
  908. if (!runtime) {
  909. if (onError) onError();
  910. return false;
  911. }
  912. importScene(runtime);
  913. this._loadBuffersAsync(runtime, () => {
  914. importMaterials(runtime);
  915. postLoad(runtime);
  916. if (!BABYLON.GLTFFileLoader.IncrementalLoading) {
  917. onSuccess();
  918. }
  919. }, onError);
  920. if (BABYLON.GLTFFileLoader.IncrementalLoading) {
  921. onSuccess();
  922. }
  923. return true;
  924. }
  925. private _loadBuffersAsync(runtime: IGLTFRuntime, onSuccess: () => void, onError: () => void): void {
  926. if (runtime.gltf.buffers.length == 0) {
  927. onSuccess();
  928. return;
  929. }
  930. var loadedCount = 0;
  931. runtime.gltf.buffers.forEach((buffer, index) => {
  932. this._loadBufferAsync(runtime, index, () => {
  933. if (++loadedCount >= runtime.gltf.buffers.length) {
  934. onSuccess();
  935. }
  936. }, onError);
  937. });
  938. }
  939. private _loadBufferAsync(runtime: IGLTFRuntime, index: number, onSuccess: () => void, onError: () => void): void {
  940. var buffer = runtime.gltf.buffers[index];
  941. if (buffer.uri === undefined) {
  942. // buffer.loadedBufferView should already be set
  943. onSuccess();
  944. }
  945. else if (GLTFUtils.IsBase64(buffer.uri)) {
  946. var data = GLTFUtils.DecodeBase64(buffer.uri);
  947. setTimeout(() => {
  948. buffer.loadedBufferView = new Uint8Array(data);
  949. onSuccess();
  950. });
  951. }
  952. else {
  953. Tools.LoadFile(runtime.rootUrl + buffer.uri, data => {
  954. buffer.loadedBufferView = new Uint8Array(data);
  955. onSuccess();
  956. }, null, null, true, onError);
  957. }
  958. }
  959. private _createRuntime(scene: Scene, data: IGLTFLoaderData, rootUrl: string, importOnlyMeshes: boolean): IGLTFRuntime {
  960. var runtime: IGLTFRuntime = {
  961. gltf: <IGLTF>data.json,
  962. babylonScene: scene,
  963. rootUrl: rootUrl,
  964. importOnlyMeshes: importOnlyMeshes,
  965. }
  966. var binaryBuffer: IGLTFBuffer;
  967. var buffers = runtime.gltf.buffers;
  968. if (buffers.length > 0 && buffers[0].uri === undefined) {
  969. binaryBuffer = buffers[0];
  970. }
  971. if (data.bin) {
  972. if (!binaryBuffer) {
  973. Tools.Error("Unexpected BIN chunk");
  974. return null;
  975. }
  976. if (binaryBuffer.byteLength != data.bin.byteLength) {
  977. Tools.Error("Binary buffer length from JSON does not match chunk length");
  978. return null;
  979. }
  980. binaryBuffer.loadedBufferView = data.bin;
  981. }
  982. GLTFLoaderExtension.PostCreateRuntime(runtime);
  983. return runtime;
  984. }
  985. }
  986. BABYLON.GLTFFileLoader.GLTFLoaderV2 = new GLTFLoader();
  987. }