babylon.glTF2Serializer.js 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099
  1. /// <reference path="../../../../dist/preview release/babylon.d.ts"/>
  2. var BABYLON;
  3. (function (BABYLON) {
  4. ;
  5. /**
  6. * Class for generating glTF data from a Babylon scene.
  7. */
  8. var GLTF2Export = /** @class */ (function () {
  9. function GLTF2Export() {
  10. }
  11. /**
  12. * Exports the geometry of the scene to .gltf file format.
  13. * @param scene - Babylon scene with scene hierarchy information.
  14. * @param filePrefix - File prefix to use when generating the glTF file.
  15. * @param options - Exporter options.
  16. * @returns - Returns an object with a .gltf file and associates texture names
  17. * as keys and their data and paths as values.
  18. */
  19. GLTF2Export.GLTF = function (scene, filePrefix, options) {
  20. var glTFPrefix = filePrefix.replace(/\.[^/.]+$/, "");
  21. var gltfGenerator = new BABYLON.GLTF2._Exporter(scene, options);
  22. if (scene.isReady) {
  23. return gltfGenerator._generateGLTF(glTFPrefix);
  24. }
  25. else {
  26. throw new Error("glTF Serializer: Scene is not ready!");
  27. }
  28. };
  29. /**
  30. * Exports the geometry of the scene to .glb file format.
  31. * @param scene - Babylon scene with scene hierarchy information.
  32. * @param filePrefix - File prefix to use when generating glb file.
  33. * @param options - Exporter options.
  34. * @returns - Returns an object with a .glb filename as key and data as value
  35. */
  36. GLTF2Export.GLB = function (scene, filePrefix, options) {
  37. var glTFPrefix = filePrefix.replace(/\.[^/.]+$/, "");
  38. var gltfGenerator = new BABYLON.GLTF2._Exporter(scene, options);
  39. if (scene.isReady) {
  40. return gltfGenerator._generateGLB(glTFPrefix);
  41. }
  42. else {
  43. throw new Error("glTF Serializer: Scene is not ready!");
  44. }
  45. };
  46. return GLTF2Export;
  47. }());
  48. BABYLON.GLTF2Export = GLTF2Export;
  49. })(BABYLON || (BABYLON = {}));
  50. //# sourceMappingURL=babylon.glTFSerializer.js.map
  51. /// <reference path="../../../../dist/babylon.glTF2Interface.d.ts"/>
  52. /**
  53. * Module for the Babylon glTF 2.0 exporter. Should ONLY be used internally.
  54. * @ignore - capitalization of GLTF2 module.
  55. */
  56. var BABYLON;
  57. (function (BABYLON) {
  58. var GLTF2;
  59. (function (GLTF2) {
  60. /**
  61. * Converts Babylon Scene into glTF 2.0.
  62. */
  63. var _Exporter = /** @class */ (function () {
  64. /**
  65. * Creates a glTF Exporter instance, which can accept optional exporter options.
  66. * @param babylonScene - Babylon scene object
  67. * @param options - Options to modify the behavior of the exporter.
  68. */
  69. function _Exporter(babylonScene, options) {
  70. this.asset = { generator: "BabylonJS", version: "2.0" };
  71. this.babylonScene = babylonScene;
  72. this.bufferViews = new Array();
  73. this.accessors = new Array();
  74. this.meshes = new Array();
  75. this.scenes = new Array();
  76. this.nodes = new Array();
  77. this.images = new Array();
  78. this.materials = new Array();
  79. this.imageData = {};
  80. if (options !== undefined) {
  81. this.options = options;
  82. }
  83. var totalByteLength = 0;
  84. totalByteLength = this.createScene(this.babylonScene, totalByteLength);
  85. this.totalByteLength = totalByteLength;
  86. }
  87. /**
  88. * Creates a buffer view based on teh supplied arguments
  89. * @param {number} bufferIndex - index value of the specified buffer
  90. * @param {number} byteOffset - byte offset value
  91. * @param {number} byteLength - byte length of the bufferView
  92. * @returns - bufferView for glTF
  93. */
  94. _Exporter.prototype.createBufferView = function (bufferIndex, byteOffset, byteLength, name) {
  95. var bufferview = { buffer: bufferIndex, byteLength: byteLength };
  96. if (byteOffset > 0) {
  97. bufferview.byteOffset = byteOffset;
  98. }
  99. if (name) {
  100. bufferview.name = name;
  101. }
  102. return bufferview;
  103. };
  104. /**
  105. * Creates an accessor based on the supplied arguments
  106. * @param bufferviewIndex
  107. * @param name
  108. * @param type
  109. * @param componentType
  110. * @param count
  111. * @param min
  112. * @param max
  113. * @returns - accessor for glTF
  114. */
  115. _Exporter.prototype.createAccessor = function (bufferviewIndex, name, type, componentType, count, min, max) {
  116. var accessor = { name: name, bufferView: bufferviewIndex, componentType: componentType, count: count, type: type };
  117. if (min) {
  118. accessor.min = min;
  119. }
  120. if (max) {
  121. accessor.max = max;
  122. }
  123. return accessor;
  124. };
  125. /**
  126. * Calculates the minimum and maximum values of an array of floats, based on stride
  127. * @param buff
  128. * @param vertexStart
  129. * @param vertexCount
  130. * @param arrayOffset
  131. * @param stride
  132. * @returns - min number array and max number array
  133. */
  134. _Exporter.prototype.calculateMinMax = function (buff, vertexStart, vertexCount, arrayOffset, stride) {
  135. var min = [Infinity, Infinity, Infinity];
  136. var max = [-Infinity, -Infinity, -Infinity];
  137. var end = vertexStart + vertexCount;
  138. if (vertexCount > 0) {
  139. for (var i = vertexStart; i < end; ++i) {
  140. var index = stride * i;
  141. for (var j = 0; j < stride; ++j) {
  142. if (buff[index] < min[j]) {
  143. min[j] = buff[index];
  144. }
  145. if (buff[index] > max[j]) {
  146. max[j] = buff[index];
  147. }
  148. ++index;
  149. }
  150. }
  151. }
  152. return { min: min, max: max };
  153. };
  154. /**
  155. * Write mesh attribute data to buffer.
  156. * Returns the bytelength of the data.
  157. * @param vertexBufferType
  158. * @param submesh
  159. * @param meshAttributeArray
  160. * @param strideSize
  161. * @param byteOffset
  162. * @param dataBuffer
  163. * @param useRightHandedSystem
  164. * @returns - byte length
  165. */
  166. _Exporter.prototype.writeAttributeData = function (vertexBufferType, submesh, meshAttributeArray, strideSize, byteOffset, dataBuffer, useRightHandedSystem) {
  167. var byteOff = byteOffset;
  168. var end = submesh.verticesStart + submesh.verticesCount;
  169. var byteLength = 0;
  170. switch (vertexBufferType) {
  171. case BABYLON.VertexBuffer.PositionKind: {
  172. for (var k = submesh.verticesStart; k < end; ++k) {
  173. var index = k * strideSize;
  174. dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
  175. byteOff += 4;
  176. dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
  177. byteOff += 4;
  178. if (useRightHandedSystem) {
  179. dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
  180. }
  181. else {
  182. dataBuffer.setFloat32(byteOff, -meshAttributeArray[index + 2], true);
  183. }
  184. byteOff += 4;
  185. }
  186. byteLength = submesh.verticesCount * 12;
  187. break;
  188. }
  189. case BABYLON.VertexBuffer.NormalKind: {
  190. for (var k = submesh.verticesStart; k < end; ++k) {
  191. var index = k * strideSize;
  192. dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
  193. byteOff += 4;
  194. dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
  195. byteOff += 4;
  196. if (useRightHandedSystem) {
  197. dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
  198. }
  199. else {
  200. dataBuffer.setFloat32(byteOff, -meshAttributeArray[index + 2], true);
  201. }
  202. byteOff += 4;
  203. }
  204. byteLength = submesh.verticesCount * 12;
  205. break;
  206. }
  207. case BABYLON.VertexBuffer.TangentKind: {
  208. for (var k = submesh.indexStart; k < end; ++k) {
  209. var index = k * strideSize;
  210. dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
  211. byteOff += 4;
  212. dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
  213. byteOff += 4;
  214. if (useRightHandedSystem) {
  215. dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
  216. }
  217. else {
  218. dataBuffer.setFloat32(byteOff, -meshAttributeArray[index + 2], true);
  219. }
  220. byteOff += 4;
  221. dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 3], true);
  222. byteOff += 4;
  223. }
  224. byteLength = submesh.verticesCount * 16;
  225. break;
  226. }
  227. case BABYLON.VertexBuffer.ColorKind: {
  228. for (var k = submesh.verticesStart; k < end; ++k) {
  229. var index = k * strideSize;
  230. dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
  231. byteOff += 4;
  232. dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
  233. byteOff += 4;
  234. dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
  235. byteOff += 4;
  236. dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 3], true);
  237. byteOff += 4;
  238. }
  239. byteLength = submesh.verticesCount * 16;
  240. break;
  241. }
  242. case BABYLON.VertexBuffer.UVKind: {
  243. for (var k = submesh.verticesStart; k < end; ++k) {
  244. var index = k * strideSize;
  245. dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
  246. byteOff += 4;
  247. dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
  248. byteOff += 4;
  249. }
  250. byteLength = submesh.verticesCount * 8;
  251. break;
  252. }
  253. case BABYLON.VertexBuffer.UV2Kind: {
  254. for (var k = submesh.verticesStart; k < end; ++k) {
  255. var index = k * strideSize;
  256. dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
  257. byteOff += 4;
  258. dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
  259. byteOff += 4;
  260. }
  261. byteLength = submesh.verticesCount * 8;
  262. break;
  263. }
  264. default: {
  265. throw new Error("Unsupported vertex buffer type: " + vertexBufferType);
  266. }
  267. }
  268. return byteLength;
  269. };
  270. /**
  271. * Generates glTF json data
  272. * @param glb
  273. * @param glTFPrefix
  274. * @param prettyPrint
  275. * @returns - json data as string
  276. */
  277. _Exporter.prototype.generateJSON = function (glb, glTFPrefix, prettyPrint) {
  278. var buffer = { byteLength: this.totalByteLength };
  279. var glTF = {
  280. asset: this.asset
  281. };
  282. if (buffer.byteLength > 0) {
  283. glTF.buffers = [buffer];
  284. }
  285. if (this.nodes && this.nodes.length !== 0) {
  286. glTF.nodes = this.nodes;
  287. }
  288. if (this.meshes && this.meshes.length !== 0) {
  289. glTF.meshes = this.meshes;
  290. }
  291. if (this.scenes && this.scenes.length !== 0) {
  292. glTF.scenes = this.scenes;
  293. glTF.scene = 0;
  294. }
  295. if (this.bufferViews && this.bufferViews.length !== 0) {
  296. glTF.bufferViews = this.bufferViews;
  297. }
  298. if (this.accessors && this.accessors.length !== 0) {
  299. glTF.accessors = this.accessors;
  300. }
  301. if (this.materials && this.materials.length !== 0) {
  302. glTF.materials = this.materials;
  303. }
  304. if (this.textures && this.textures.length !== 0) {
  305. glTF.textures = this.textures;
  306. }
  307. if (this.images && this.images.length !== 0) {
  308. if (!glb) {
  309. glTF.images = this.images;
  310. }
  311. else {
  312. glTF.images = [];
  313. // Replace uri with bufferview and mime type for glb
  314. var imageLength = this.images.length;
  315. var byteOffset = this.totalByteLength;
  316. for (var i = 0; i < imageLength; ++i) {
  317. var image = this.images[i];
  318. if (image.uri !== undefined) {
  319. var imageData = this.imageData[image.uri];
  320. var imageName = image.uri.split('.')[0] + " image";
  321. var bufferView = this.createBufferView(0, byteOffset, imageData.data.length, imageName);
  322. byteOffset += imageData.data.buffer.byteLength;
  323. this.bufferViews.push(bufferView);
  324. image.bufferView = this.bufferViews.length - 1;
  325. image.name = imageName;
  326. image.mimeType = imageData.mimeType;
  327. image.uri = undefined;
  328. glTF.images.push(image);
  329. }
  330. }
  331. buffer.byteLength = byteOffset;
  332. }
  333. }
  334. if (!glb) {
  335. buffer.uri = glTFPrefix + ".bin";
  336. }
  337. var jsonText = prettyPrint ? JSON.stringify(glTF, null, 2) : JSON.stringify(glTF);
  338. return jsonText;
  339. };
  340. /**
  341. * Generates data for .gltf and .bin files based on the glTF prefix string
  342. * @param glTFPrefix
  343. * @returns - object with glTF json tex filename
  344. * and binary file name as keys and their data as values
  345. */
  346. _Exporter.prototype._generateGLTF = function (glTFPrefix) {
  347. var jsonText = this.generateJSON(false, glTFPrefix, true);
  348. var binaryBuffer = this.generateBinary();
  349. var bin = new Blob([binaryBuffer], { type: 'application/octet-stream' });
  350. var glTFFileName = glTFPrefix + '.gltf';
  351. var glTFBinFile = glTFPrefix + '.bin';
  352. var container = new BABYLON._GLTFData();
  353. container.glTFFiles[glTFFileName] = jsonText;
  354. container.glTFFiles[glTFBinFile] = bin;
  355. if (this.imageData !== null) {
  356. for (var image in this.imageData) {
  357. container.glTFFiles[image] = new Blob([this.imageData[image].data], { type: this.imageData[image].mimeType });
  358. }
  359. }
  360. return container;
  361. };
  362. /**
  363. * Creates a binary buffer for glTF
  364. * @returns - array buffer for binary data
  365. */
  366. _Exporter.prototype.generateBinary = function () {
  367. var byteOffset = 0;
  368. var binaryBuffer = new ArrayBuffer(this.totalByteLength);
  369. var dataBuffer = new DataView(binaryBuffer);
  370. byteOffset = this.createScene(this.babylonScene, byteOffset, dataBuffer);
  371. return binaryBuffer;
  372. };
  373. /**
  374. * Pads the number to a power of 4
  375. * @param num - number to pad
  376. * @returns - padded number
  377. */
  378. _Exporter.prototype._getPadding = function (num) {
  379. var remainder = num % 4;
  380. var padding = remainder === 0 ? remainder : 4 - remainder;
  381. return padding;
  382. };
  383. /**
  384. * Generates a glb file from the json and binary data.
  385. * Returns an object with the glb file name as the key and data as the value.
  386. * @param jsonText
  387. * @param binaryBuffer
  388. * @param glTFPrefix
  389. * @returns - object with glb filename as key and data as value
  390. */
  391. _Exporter.prototype._generateGLB = function (glTFPrefix) {
  392. var jsonText = this.generateJSON(true);
  393. var binaryBuffer = this.generateBinary();
  394. var glbFileName = glTFPrefix + '.glb';
  395. var headerLength = 12;
  396. var chunkLengthPrefix = 8;
  397. var jsonLength = jsonText.length;
  398. var imageByteLength = 0;
  399. for (var key in this.imageData) {
  400. imageByteLength += this.imageData[key].data.byteLength;
  401. }
  402. var jsonPadding = this._getPadding(jsonLength);
  403. var binPadding = this._getPadding(binaryBuffer.byteLength);
  404. var byteLength = headerLength + (2 * chunkLengthPrefix) + jsonLength + jsonPadding + binaryBuffer.byteLength + binPadding + imageByteLength;
  405. //header
  406. var headerBuffer = new ArrayBuffer(headerLength);
  407. var headerBufferView = new DataView(headerBuffer);
  408. headerBufferView.setUint32(0, 0x46546C67, true); //glTF
  409. headerBufferView.setUint32(4, 2, true); // version
  410. headerBufferView.setUint32(8, byteLength, true); // total bytes in file
  411. //json chunk
  412. var jsonChunkBuffer = new ArrayBuffer(chunkLengthPrefix + jsonLength + jsonPadding);
  413. var jsonChunkBufferView = new DataView(jsonChunkBuffer);
  414. jsonChunkBufferView.setUint32(0, jsonLength + jsonPadding, true);
  415. jsonChunkBufferView.setUint32(4, 0x4E4F534A, true);
  416. //json chunk bytes
  417. var jsonData = new Uint8Array(jsonChunkBuffer, chunkLengthPrefix);
  418. for (var i = 0; i < jsonLength; ++i) {
  419. jsonData[i] = jsonText.charCodeAt(i);
  420. }
  421. //json padding
  422. var jsonPaddingView = new Uint8Array(jsonChunkBuffer, chunkLengthPrefix + jsonLength);
  423. for (var i = 0; i < jsonPadding; ++i) {
  424. jsonPaddingView[i] = 0x20;
  425. }
  426. //binary chunk
  427. var binaryChunkBuffer = new ArrayBuffer(chunkLengthPrefix);
  428. var binaryChunkBufferView = new DataView(binaryChunkBuffer);
  429. binaryChunkBufferView.setUint32(0, binaryBuffer.byteLength + imageByteLength, true);
  430. binaryChunkBufferView.setUint32(4, 0x004E4942, true);
  431. // binary padding
  432. var binPaddingBuffer = new ArrayBuffer(binPadding);
  433. var binPaddingView = new Uint8Array(binPaddingBuffer);
  434. for (var i = 0; i < binPadding; ++i) {
  435. binPaddingView[i] = 0;
  436. }
  437. var glbData = [headerBuffer, jsonChunkBuffer, binaryChunkBuffer, binaryBuffer];
  438. // binary data
  439. for (var key in this.imageData) {
  440. glbData.push(this.imageData[key].data.buffer);
  441. }
  442. glbData.push(binPaddingBuffer);
  443. var glbFile = new Blob(glbData, { type: 'application/octet-stream' });
  444. var container = new BABYLON._GLTFData();
  445. container.glTFFiles[glbFileName] = glbFile;
  446. return container;
  447. };
  448. /**
  449. * Sets the TRS for each node
  450. * @param node
  451. * @param babylonMesh
  452. * @param useRightHandedSystem
  453. */
  454. _Exporter.prototype.setNodeTransformation = function (node, babylonMesh, useRightHandedSystem) {
  455. if (!(babylonMesh.position.x === 0 && babylonMesh.position.y === 0 && babylonMesh.position.z === 0)) {
  456. if (useRightHandedSystem) {
  457. node.translation = babylonMesh.position.asArray();
  458. }
  459. else {
  460. node.translation = [babylonMesh.position.x, babylonMesh.position.y, -babylonMesh.position.z];
  461. }
  462. }
  463. if (!(babylonMesh.scaling.x === 1 && babylonMesh.scaling.y === 1 && babylonMesh.scaling.z === 1)) {
  464. if (useRightHandedSystem) {
  465. node.scale = babylonMesh.scaling.asArray();
  466. }
  467. else {
  468. node.scale = [babylonMesh.scaling.x, babylonMesh.scaling.y, -babylonMesh.scaling.z];
  469. }
  470. }
  471. var rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(babylonMesh.rotation.y, babylonMesh.rotation.x, babylonMesh.rotation.z);
  472. if (babylonMesh.rotationQuaternion) {
  473. rotationQuaternion = rotationQuaternion.multiply(babylonMesh.rotationQuaternion);
  474. }
  475. if (!(rotationQuaternion.x === 0 && rotationQuaternion.y === 0 && rotationQuaternion.z === 0 && rotationQuaternion.w === 1)) {
  476. if (useRightHandedSystem) {
  477. node.rotation = rotationQuaternion.asArray();
  478. }
  479. else {
  480. node.rotation = [-rotationQuaternion.x, -rotationQuaternion.y, rotationQuaternion.z, rotationQuaternion.w];
  481. }
  482. }
  483. };
  484. /**
  485. *
  486. * @param babylonTexture
  487. * @return - glTF texture, or null if the texture format is not supported
  488. */
  489. _Exporter.prototype.exportTexture = function (babylonTexture, mimeType) {
  490. if (mimeType === void 0) { mimeType = "image/jpeg" /* JPEG */; }
  491. var textureInfo = null;
  492. var glTFTexture;
  493. glTFTexture = {
  494. source: this.images.length
  495. };
  496. var textureName = babylonTexture.getInternalTexture().url;
  497. if (textureName.search('/') !== -1) {
  498. var splitFilename = textureName.split('/');
  499. textureName = splitFilename[splitFilename.length - 1];
  500. var basefile = textureName.split('.')[0];
  501. var extension = textureName.split('.')[1];
  502. if (mimeType === "image/jpeg" /* JPEG */) {
  503. extension = ".jpg";
  504. }
  505. else if (mimeType === "image/png" /* PNG */) {
  506. extension = ".png";
  507. }
  508. else {
  509. throw new Error("Unsupported mime type " + mimeType);
  510. }
  511. textureName = basefile + extension;
  512. }
  513. var pixels = babylonTexture.readPixels();
  514. var imageCanvas = document.createElement('canvas');
  515. imageCanvas.id = "ImageCanvas";
  516. var ctx = imageCanvas.getContext('2d');
  517. var size = babylonTexture.getSize();
  518. imageCanvas.width = size.width;
  519. imageCanvas.height = size.height;
  520. var imgData = ctx.createImageData(size.width, size.height);
  521. imgData.data.set(pixels);
  522. ctx.putImageData(imgData, 0, 0);
  523. var base64Data = imageCanvas.toDataURL(mimeType);
  524. var binStr = atob(base64Data.split(',')[1]);
  525. var arr = new Uint8Array(binStr.length);
  526. for (var i = 0; i < binStr.length; ++i) {
  527. arr[i] = binStr.charCodeAt(i);
  528. }
  529. var imageValues = { data: arr, mimeType: mimeType };
  530. this.imageData[textureName] = imageValues;
  531. if (mimeType === "image/jpeg" /* JPEG */) {
  532. var glTFImage = {
  533. uri: textureName
  534. };
  535. var foundIndex = -1;
  536. for (var i = 0; i < this.images.length; ++i) {
  537. if (this.images[i].uri === textureName) {
  538. foundIndex = i;
  539. break;
  540. }
  541. }
  542. if (foundIndex === -1) {
  543. this.images.push(glTFImage);
  544. glTFTexture.source = this.images.length - 1;
  545. this.textures.push({
  546. source: this.images.length - 1
  547. });
  548. textureInfo = {
  549. index: this.images.length - 1
  550. };
  551. }
  552. else {
  553. glTFTexture.source = foundIndex;
  554. textureInfo = {
  555. index: foundIndex
  556. };
  557. }
  558. }
  559. return textureInfo;
  560. };
  561. /**
  562. * Sets data for the primitive attributes of each submesh
  563. * @param mesh
  564. * @param babylonMesh
  565. * @param byteOffset
  566. * @param useRightHandedSystem
  567. * @param dataBuffer
  568. * @returns - bytelength of the primitive attributes plus the passed in byteOffset
  569. */
  570. _Exporter.prototype.setPrimitiveAttributes = function (mesh, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer) {
  571. // go through all mesh primitives (submeshes)
  572. for (var j = 0; j < babylonMesh.subMeshes.length; ++j) {
  573. var bufferMesh = null;
  574. var submesh = babylonMesh.subMeshes[j];
  575. var meshPrimitive = { attributes: {} };
  576. if (babylonMesh instanceof BABYLON.Mesh) {
  577. bufferMesh = babylonMesh;
  578. }
  579. else if (babylonMesh instanceof BABYLON.InstancedMesh) {
  580. bufferMesh = babylonMesh.sourceMesh;
  581. }
  582. // Loop through each attribute of the submesh (mesh primitive)
  583. if (bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
  584. var positionVertexBuffer = bufferMesh.getVertexBuffer(BABYLON.VertexBuffer.PositionKind);
  585. var positionVertexBufferOffset = positionVertexBuffer.getOffset();
  586. var positions = positionVertexBuffer.getData();
  587. var positionStrideSize = positionVertexBuffer.getStrideSize();
  588. if (dataBuffer) {
  589. byteOffset += this.writeAttributeData(BABYLON.VertexBuffer.PositionKind, submesh, positions, positionStrideSize, byteOffset, dataBuffer, useRightHandedSystem);
  590. }
  591. else {
  592. // Create bufferview
  593. var byteLength = submesh.verticesCount * 12;
  594. var bufferview = this.createBufferView(0, byteOffset, byteLength, "Positions");
  595. byteOffset += byteLength;
  596. this.bufferViews.push(bufferview);
  597. // Create accessor
  598. var result = this.calculateMinMax(positions, submesh.verticesStart, submesh.verticesCount, positionVertexBufferOffset, positionStrideSize);
  599. var accessor = this.createAccessor(this.bufferViews.length - 1, "Position", "VEC3" /* VEC3 */, 5126 /* FLOAT */, submesh.verticesCount, result.min, result.max);
  600. this.accessors.push(accessor);
  601. meshPrimitive.attributes.POSITION = this.accessors.length - 1;
  602. }
  603. }
  604. if (bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
  605. var normalVertexBuffer = bufferMesh.getVertexBuffer(BABYLON.VertexBuffer.NormalKind);
  606. var normals = normalVertexBuffer.getData();
  607. var normalStrideSize = normalVertexBuffer.getStrideSize();
  608. if (dataBuffer) {
  609. byteOffset += this.writeAttributeData(BABYLON.VertexBuffer.NormalKind, submesh, normals, normalStrideSize, byteOffset, dataBuffer, useRightHandedSystem);
  610. }
  611. else {
  612. // Create bufferview
  613. var byteLength = submesh.verticesCount * 12;
  614. var bufferview = this.createBufferView(0, byteOffset, byteLength, "Normals");
  615. byteOffset += byteLength;
  616. this.bufferViews.push(bufferview);
  617. // Create accessor
  618. var accessor = this.createAccessor(this.bufferViews.length - 1, "Normal", "VEC3" /* VEC3 */, 5126 /* FLOAT */, submesh.verticesCount);
  619. this.accessors.push(accessor);
  620. meshPrimitive.attributes.NORMAL = this.accessors.length - 1;
  621. }
  622. }
  623. if (bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.TangentKind)) {
  624. var tangentVertexBuffer = bufferMesh.getVertexBuffer(BABYLON.VertexBuffer.TangentKind);
  625. var tangents = tangentVertexBuffer.getData();
  626. var tangentStrideSize = tangentVertexBuffer.getStrideSize();
  627. if (dataBuffer) {
  628. byteOffset += this.writeAttributeData(BABYLON.VertexBuffer.TangentKind, submesh, tangents, tangentStrideSize, byteOffset, dataBuffer, useRightHandedSystem);
  629. }
  630. else {
  631. // Create bufferview
  632. var byteLength = submesh.verticesCount * 16;
  633. var bufferview = this.createBufferView(0, byteOffset, byteLength, "Tangents");
  634. byteOffset += byteLength;
  635. this.bufferViews.push(bufferview);
  636. // Create accessor
  637. var accessor = this.createAccessor(this.bufferViews.length - 1, "Tangent", "VEC4" /* VEC4 */, 5126 /* FLOAT */, submesh.verticesCount);
  638. this.accessors.push(accessor);
  639. meshPrimitive.attributes.TANGENT = this.accessors.length - 1;
  640. }
  641. }
  642. if (bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
  643. var colorVertexBuffer = bufferMesh.getVertexBuffer(BABYLON.VertexBuffer.ColorKind);
  644. var colors = colorVertexBuffer.getData();
  645. var colorStrideSize = colorVertexBuffer.getStrideSize();
  646. if (dataBuffer) {
  647. byteOffset += this.writeAttributeData(BABYLON.VertexBuffer.ColorKind, submesh, colors, colorStrideSize, byteOffset, dataBuffer, useRightHandedSystem);
  648. }
  649. else {
  650. // Create bufferview
  651. var byteLength = submesh.verticesCount * 16;
  652. var bufferview = this.createBufferView(0, byteOffset, byteLength, "Colors");
  653. byteOffset += byteLength;
  654. this.bufferViews.push(bufferview);
  655. // Create accessor
  656. var accessor = this.createAccessor(this.bufferViews.length - 1, "Color", "VEC4" /* VEC4 */, 5126 /* FLOAT */, submesh.verticesCount);
  657. this.accessors.push(accessor);
  658. meshPrimitive.attributes.COLOR_0 = this.accessors.length - 1;
  659. }
  660. }
  661. if (bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
  662. var texCoord0VertexBuffer = bufferMesh.getVertexBuffer(BABYLON.VertexBuffer.UVKind);
  663. var texCoords0 = texCoord0VertexBuffer.getData();
  664. var texCoord0StrideSize = texCoord0VertexBuffer.getStrideSize();
  665. if (dataBuffer) {
  666. byteOffset += this.writeAttributeData(BABYLON.VertexBuffer.UVKind, submesh, texCoords0, texCoord0StrideSize, byteOffset, dataBuffer, useRightHandedSystem);
  667. }
  668. else {
  669. // Create bufferview
  670. var byteLength = submesh.verticesCount * 8;
  671. var bufferview = this.createBufferView(0, byteOffset, byteLength, "Texture Coords0");
  672. byteOffset += byteLength;
  673. this.bufferViews.push(bufferview);
  674. // Create accessor
  675. var accessor = this.createAccessor(this.bufferViews.length - 1, "Texture Coords", "VEC2" /* VEC2 */, 5126 /* FLOAT */, submesh.verticesCount);
  676. this.accessors.push(accessor);
  677. meshPrimitive.attributes.TEXCOORD_0 = this.accessors.length - 1;
  678. }
  679. }
  680. if (bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
  681. var texCoord1VertexBuffer = bufferMesh.getVertexBuffer(BABYLON.VertexBuffer.UV2Kind);
  682. var texCoords1 = texCoord1VertexBuffer.getData();
  683. var texCoord1StrideSize = texCoord1VertexBuffer.getStrideSize();
  684. if (dataBuffer) {
  685. byteOffset += this.writeAttributeData(BABYLON.VertexBuffer.UV2Kind, submesh, texCoords1, texCoord1StrideSize, byteOffset, dataBuffer, useRightHandedSystem);
  686. }
  687. else {
  688. // Create bufferview
  689. var byteLength = submesh.verticesCount * 8;
  690. var bufferview = this.createBufferView(0, byteOffset, byteLength, "Texture Coords 1");
  691. byteOffset += byteLength;
  692. this.bufferViews.push(bufferview);
  693. // Create accessor
  694. var accessor = this.createAccessor(this.bufferViews.length - 1, "Texture Coords", "VEC2" /* VEC2 */, 5126 /* FLOAT */, submesh.verticesCount);
  695. this.accessors.push(accessor);
  696. meshPrimitive.attributes.TEXCOORD_1 = this.accessors.length - 1;
  697. }
  698. }
  699. if (bufferMesh.getTotalIndices() > 0) {
  700. if (dataBuffer) {
  701. var indices = bufferMesh.getIndices();
  702. var start = submesh.indexStart;
  703. var end = submesh.indexCount + start;
  704. var byteOff = byteOffset;
  705. for (var k = start; k < end; k = k + 3) {
  706. dataBuffer.setUint32(byteOff, indices[k], true);
  707. byteOff += 4;
  708. dataBuffer.setUint32(byteOff, indices[k + 1], true);
  709. byteOff += 4;
  710. dataBuffer.setUint32(byteOff, indices[k + 2], true);
  711. byteOff += 4;
  712. }
  713. var byteLength = submesh.indexCount * 4;
  714. byteOffset += byteLength;
  715. }
  716. else {
  717. // Create bufferview
  718. var indicesCount = submesh.indexCount;
  719. var byteLength = indicesCount * 4;
  720. var bufferview = this.createBufferView(0, byteOffset, byteLength, "Indices");
  721. byteOffset += byteLength;
  722. this.bufferViews.push(bufferview);
  723. // Create accessor
  724. var accessor = this.createAccessor(this.bufferViews.length - 1, "Indices", "SCALAR" /* SCALAR */, 5125 /* UNSIGNED_INT */, indicesCount);
  725. this.accessors.push(accessor);
  726. meshPrimitive.indices = this.accessors.length - 1;
  727. }
  728. }
  729. if (bufferMesh.material) {
  730. if (bufferMesh.material instanceof BABYLON.StandardMaterial) {
  731. var babylonStandardMaterial = bufferMesh.material;
  732. var glTFMaterial = { name: babylonStandardMaterial.name };
  733. if (!babylonStandardMaterial.backFaceCulling) {
  734. glTFMaterial.doubleSided = true;
  735. }
  736. if (babylonStandardMaterial.bumpTexture) {
  737. var glTFTexture = this.exportTexture(babylonStandardMaterial.bumpTexture);
  738. if (glTFTexture) {
  739. glTFMaterial.normalTexture = glTFTexture;
  740. }
  741. }
  742. if (babylonStandardMaterial.emissiveTexture) {
  743. var glTFEmissiveTexture = this.exportTexture(babylonStandardMaterial.emissiveTexture);
  744. if (glTFEmissiveTexture) {
  745. glTFMaterial.emissiveTexture = glTFEmissiveTexture;
  746. }
  747. glTFMaterial.emissiveFactor = [1.0, 1.0, 1.0];
  748. }
  749. if (babylonStandardMaterial.ambientTexture) {
  750. var glTFOcclusionTexture = this.exportTexture(babylonStandardMaterial.ambientTexture);
  751. if (glTFOcclusionTexture) {
  752. glTFMaterial.occlusionTexture = glTFOcclusionTexture;
  753. }
  754. }
  755. // Spec Gloss
  756. var glTFPbrMetallicRoughness = GLTF2._GLTFMaterial.ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial);
  757. glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
  758. // TODO: Handle Textures
  759. this.materials.push(glTFMaterial);
  760. meshPrimitive.material = this.materials.length - 1;
  761. }
  762. else if (bufferMesh.material instanceof BABYLON.PBRMetallicRoughnessMaterial) {
  763. if (!this.textures) {
  764. this.textures = new Array();
  765. }
  766. var babylonPBRMaterial = bufferMesh.material;
  767. var glTFPbrMetallicRoughness = {};
  768. if (babylonPBRMaterial.baseColor) {
  769. glTFPbrMetallicRoughness.baseColorFactor = [
  770. babylonPBRMaterial.baseColor.r,
  771. babylonPBRMaterial.baseColor.g,
  772. babylonPBRMaterial.baseColor.b,
  773. babylonPBRMaterial.alpha
  774. ];
  775. }
  776. if (babylonPBRMaterial.baseTexture !== undefined) {
  777. var glTFTexture = this.exportTexture(babylonPBRMaterial.baseTexture);
  778. if (glTFTexture !== null) {
  779. glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
  780. }
  781. glTFPbrMetallicRoughness.baseColorTexture;
  782. }
  783. if (babylonPBRMaterial.metallic !== undefined) {
  784. glTFPbrMetallicRoughness.metallicFactor = babylonPBRMaterial.metallic;
  785. }
  786. if (babylonPBRMaterial.roughness !== undefined) {
  787. glTFPbrMetallicRoughness.roughnessFactor = babylonPBRMaterial.roughness;
  788. }
  789. var glTFMaterial = {
  790. name: babylonPBRMaterial.name
  791. };
  792. if (babylonPBRMaterial.doubleSided) {
  793. glTFMaterial.doubleSided = babylonPBRMaterial.doubleSided;
  794. }
  795. if (babylonPBRMaterial.normalTexture) {
  796. var glTFTexture = this.exportTexture(babylonPBRMaterial.normalTexture);
  797. if (glTFTexture) {
  798. glTFMaterial.normalTexture = glTFTexture;
  799. }
  800. }
  801. if (babylonPBRMaterial.occlusionTexture) {
  802. var glTFTexture = this.exportTexture(babylonPBRMaterial.occlusionTexture);
  803. if (glTFTexture) {
  804. glTFMaterial.occlusionTexture = glTFTexture;
  805. if (babylonPBRMaterial.occlusionStrength !== undefined) {
  806. glTFMaterial.occlusionTexture.strength = babylonPBRMaterial.occlusionStrength;
  807. }
  808. }
  809. }
  810. if (babylonPBRMaterial.emissiveTexture) {
  811. var glTFTexture = this.exportTexture(babylonPBRMaterial.emissiveTexture);
  812. if (glTFTexture !== null) {
  813. glTFMaterial.emissiveTexture = glTFTexture;
  814. }
  815. }
  816. if (!babylonPBRMaterial.emissiveColor.equals(new BABYLON.Color3(0.0, 0.0, 0.0))) {
  817. glTFMaterial.emissiveFactor = babylonPBRMaterial.emissiveColor.asArray();
  818. }
  819. if (babylonPBRMaterial.transparencyMode) {
  820. var alphaMode = GLTF2._GLTFMaterial.GetAlphaMode(babylonPBRMaterial);
  821. if (alphaMode !== "OPAQUE" /* OPAQUE */) {
  822. glTFMaterial.alphaMode = alphaMode;
  823. if (alphaMode === "BLEND" /* BLEND */) {
  824. glTFMaterial.alphaCutoff = babylonPBRMaterial.alphaCutOff;
  825. }
  826. }
  827. }
  828. glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
  829. // TODO: Handle Textures
  830. this.materials.push(glTFMaterial);
  831. meshPrimitive.material = this.materials.length - 1;
  832. }
  833. }
  834. mesh.primitives.push(meshPrimitive);
  835. }
  836. return byteOffset;
  837. };
  838. /**
  839. * Creates a glTF scene based on the array of meshes.
  840. * Returns the the total byte offset.
  841. * @param gltf
  842. * @param byteOffset
  843. * @param buffer
  844. * @param dataBuffer
  845. * @returns bytelength + byteoffset
  846. */
  847. _Exporter.prototype.createScene = function (babylonScene, byteOffset, dataBuffer) {
  848. if (babylonScene.meshes.length > 0) {
  849. var babylonMeshes = babylonScene.meshes;
  850. var scene = { nodes: new Array() };
  851. for (var i = 0; i < babylonMeshes.length; ++i) {
  852. if (this.options &&
  853. this.options.shouldExportMesh !== undefined &&
  854. !this.options.shouldExportMesh(babylonMeshes[i])) {
  855. continue;
  856. }
  857. else {
  858. // create node to hold translation/rotation/scale and the mesh
  859. var node = { mesh: -1 };
  860. var babylonMesh = babylonMeshes[i];
  861. var useRightHandedSystem = babylonMesh.getScene().useRightHandedSystem;
  862. // Set transformation
  863. this.setNodeTransformation(node, babylonMesh, useRightHandedSystem);
  864. // create mesh
  865. var mesh = { primitives: new Array() };
  866. mesh.primitives = [];
  867. byteOffset = this.setPrimitiveAttributes(mesh, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
  868. // go through all mesh primitives (submeshes)
  869. this.meshes.push(mesh);
  870. node.mesh = this.meshes.length - 1;
  871. if (babylonMesh.name) {
  872. node.name = babylonMesh.name;
  873. }
  874. this.nodes.push(node);
  875. scene.nodes.push(this.nodes.length - 1);
  876. }
  877. }
  878. this.scenes.push(scene);
  879. }
  880. return byteOffset;
  881. };
  882. return _Exporter;
  883. }());
  884. GLTF2._Exporter = _Exporter;
  885. })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
  886. })(BABYLON || (BABYLON = {}));
  887. //# sourceMappingURL=babylon.glTFExporter.js.map
  888. /// <reference path="../../../../dist/babylon.glTF2Interface.d.ts"/>
  889. var BABYLON;
  890. (function (BABYLON) {
  891. /**
  892. * Class for holding and downloading glTF file data
  893. */
  894. var _GLTFData = /** @class */ (function () {
  895. /**
  896. * Initializes the glTF file object.
  897. */
  898. function _GLTFData() {
  899. this.glTFFiles = {};
  900. }
  901. /**
  902. * Downloads the glTF data as files based on their names and data.
  903. */
  904. _GLTFData.prototype.downloadFiles = function () {
  905. /**
  906. * Checks for a matching suffix at the end of a string (for ES5 and lower).
  907. * @param str - Source string.
  908. * @param suffix - Suffix to search for in the source string.
  909. * @returns - Boolean indicating whether the suffix was found (true) or not (false).
  910. */
  911. function endsWith(str, suffix) {
  912. return str.indexOf(suffix, str.length - suffix.length) !== -1;
  913. }
  914. for (var key in this.glTFFiles) {
  915. var link = document.createElement('a');
  916. document.body.appendChild(link);
  917. link.setAttribute("type", "hidden");
  918. link.download = key;
  919. var blob = this.glTFFiles[key];
  920. var mimeType = void 0;
  921. if (endsWith(key, ".glb")) {
  922. mimeType = { type: "model/gltf-binary" };
  923. }
  924. else if (endsWith(key, ".bin")) {
  925. mimeType = { type: "application/octet-stream" };
  926. }
  927. else if (endsWith(key, ".gltf")) {
  928. mimeType = { type: "model/gltf+json" };
  929. }
  930. else if (endsWith(key, ".jpeg" || ".jpg")) {
  931. mimeType = { type: "image/jpeg" /* JPEG */ };
  932. }
  933. else if (endsWith(key, ".png")) {
  934. mimeType = { type: "image/png" /* PNG */ };
  935. }
  936. link.href = window.URL.createObjectURL(new Blob([blob], mimeType));
  937. link.click();
  938. }
  939. };
  940. return _GLTFData;
  941. }());
  942. BABYLON._GLTFData = _GLTFData;
  943. })(BABYLON || (BABYLON = {}));
  944. //# sourceMappingURL=babylon.glTFData.js.map
  945. /// <reference path="../../../../dist/babylon.glTF2Interface.d.ts"/>
  946. var BABYLON;
  947. (function (BABYLON) {
  948. var GLTF2;
  949. (function (GLTF2) {
  950. /**
  951. * Utility methods for working with glTF material conversion properties. This class should only be used internally.
  952. */
  953. var _GLTFMaterial = /** @class */ (function () {
  954. function _GLTFMaterial() {
  955. }
  956. /**
  957. * Converts a Babylon StandardMaterial to a glTF Metallic Roughness Material.
  958. * @param babylonStandardMaterial
  959. * @returns - glTF Metallic Roughness Material representation
  960. */
  961. _GLTFMaterial.ConvertToGLTFPBRMetallicRoughness = function (babylonStandardMaterial) {
  962. var babylonSpecularGlossiness = {
  963. diffuse: babylonStandardMaterial.diffuseColor,
  964. opacity: babylonStandardMaterial.alpha,
  965. specular: babylonStandardMaterial.specularColor || BABYLON.Color3.Black(),
  966. glossiness: babylonStandardMaterial.specularPower / 256
  967. };
  968. if (babylonStandardMaterial.specularTexture) {
  969. }
  970. var babylonMetallicRoughness = _GLTFMaterial._ConvertToMetallicRoughness(babylonSpecularGlossiness);
  971. var glTFPbrMetallicRoughness = {
  972. baseColorFactor: [
  973. babylonMetallicRoughness.baseColor.r,
  974. babylonMetallicRoughness.baseColor.g,
  975. babylonMetallicRoughness.baseColor.b,
  976. babylonMetallicRoughness.opacity
  977. ],
  978. metallicFactor: babylonMetallicRoughness.metallic,
  979. roughnessFactor: babylonMetallicRoughness.roughness
  980. };
  981. return glTFPbrMetallicRoughness;
  982. };
  983. /**
  984. * Converts Specular Glossiness to Metallic Roughness. This is based on the algorithm used in the Babylon glTF 3ds Max Exporter.
  985. * {@link https://github.com/BabylonJS/Exporters/blob/master/3ds%20Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Material.cs}
  986. * @param babylonSpecularGlossiness - Babylon specular glossiness parameters
  987. * @returns - Babylon metallic roughness values
  988. */
  989. _GLTFMaterial._ConvertToMetallicRoughness = function (babylonSpecularGlossiness) {
  990. var diffuse = babylonSpecularGlossiness.diffuse;
  991. var opacity = babylonSpecularGlossiness.opacity;
  992. var specular = babylonSpecularGlossiness.specular;
  993. var glossiness = babylonSpecularGlossiness.glossiness;
  994. var oneMinusSpecularStrength = 1 - Math.max(specular.r, Math.max(specular.g, specular.b));
  995. var diffusePerceivedBrightness = _GLTFMaterial.PerceivedBrightness(diffuse);
  996. var specularPerceivedBrightness = _GLTFMaterial.PerceivedBrightness(specular);
  997. var metallic = _GLTFMaterial.SolveMetallic(diffusePerceivedBrightness, specularPerceivedBrightness, oneMinusSpecularStrength);
  998. var diffuseScaleFactor = oneMinusSpecularStrength / (1 - this.dielectricSpecular.r) / Math.max(1 - metallic, this.epsilon);
  999. var baseColorFromDiffuse = diffuse.scale(diffuseScaleFactor);
  1000. var baseColorFromSpecular = specular.subtract(this.dielectricSpecular.scale(1 - metallic)).scale(1 / Math.max(metallic, this.epsilon));
  1001. var lerpColor = BABYLON.Color3.Lerp(baseColorFromDiffuse, baseColorFromSpecular, metallic * metallic);
  1002. var baseColor = new BABYLON.Color3();
  1003. lerpColor.clampToRef(0, 1, baseColor);
  1004. var babylonMetallicRoughness = {
  1005. baseColor: baseColor,
  1006. opacity: opacity,
  1007. metallic: metallic,
  1008. roughness: 1.0 - glossiness
  1009. };
  1010. return babylonMetallicRoughness;
  1011. };
  1012. /**
  1013. * Returns the perceived brightness value based on the provided color
  1014. * @param color - color used in calculating the perceived brightness
  1015. * @returns - perceived brightness value
  1016. */
  1017. _GLTFMaterial.PerceivedBrightness = function (color) {
  1018. return Math.sqrt(0.299 * color.r * color.r + 0.587 * color.g * color.g + 0.114 * color.b * color.b);
  1019. };
  1020. /**
  1021. * Computes the metallic factor
  1022. * @param diffuse - diffused value
  1023. * @param specular - specular value
  1024. * @param oneMinusSpecularStrength - one minus the specular strength
  1025. * @returns - metallic value
  1026. */
  1027. _GLTFMaterial.SolveMetallic = function (diffuse, specular, oneMinusSpecularStrength) {
  1028. if (specular < this.dielectricSpecular.r) {
  1029. return 0;
  1030. }
  1031. var a = this.dielectricSpecular.r;
  1032. var b = diffuse * oneMinusSpecularStrength / (1.0 - this.dielectricSpecular.r) + specular - 2.0 * this.dielectricSpecular.r;
  1033. var c = this.dielectricSpecular.r - specular;
  1034. var D = b * b - 4.0 * a * c;
  1035. return BABYLON.Scalar.Clamp((-b + Math.sqrt(D)) / (2.0 * a));
  1036. };
  1037. /**
  1038. * Gets the glTF alpha mode from the Babylon Material
  1039. * @param babylonMaterial - Babylon Material
  1040. * @returns - The Babylon alpha mode value
  1041. */
  1042. _GLTFMaterial.GetAlphaMode = function (babylonMaterial) {
  1043. if (babylonMaterial instanceof BABYLON.StandardMaterial) {
  1044. var babylonStandardMaterial = babylonMaterial;
  1045. if ((babylonStandardMaterial.alpha != 1.0) ||
  1046. (babylonStandardMaterial.diffuseTexture != null && babylonStandardMaterial.diffuseTexture.hasAlpha) ||
  1047. (babylonStandardMaterial.opacityTexture != null)) {
  1048. return "BLEND" /* BLEND */;
  1049. }
  1050. else {
  1051. return "OPAQUE" /* OPAQUE */;
  1052. }
  1053. }
  1054. else if (babylonMaterial instanceof BABYLON.PBRMetallicRoughnessMaterial) {
  1055. var babylonPBRMetallicRoughness = babylonMaterial;
  1056. switch (babylonPBRMetallicRoughness.transparencyMode) {
  1057. case BABYLON.PBRMaterial.PBRMATERIAL_OPAQUE: {
  1058. return "OPAQUE" /* OPAQUE */;
  1059. }
  1060. case BABYLON.PBRMaterial.PBRMATERIAL_ALPHABLEND: {
  1061. return "BLEND" /* BLEND */;
  1062. }
  1063. case BABYLON.PBRMaterial.PBRMATERIAL_ALPHATEST: {
  1064. return "MASK" /* MASK */;
  1065. }
  1066. case BABYLON.PBRMaterial.PBRMATERIAL_ALPHATESTANDBLEND: {
  1067. console.warn("GLTF Exporter | Alpha test and blend mode not supported in glTF. Alpha blend used instead.");
  1068. return "BLEND" /* BLEND */;
  1069. }
  1070. default: {
  1071. throw new Error("Unsupported alpha mode " + babylonPBRMetallicRoughness.transparencyMode);
  1072. }
  1073. }
  1074. }
  1075. else {
  1076. throw new Error("Unsupported Babylon material type");
  1077. }
  1078. };
  1079. /**
  1080. * Represents the dielectric specular values for R, G and B.
  1081. */
  1082. _GLTFMaterial.dielectricSpecular = new BABYLON.Color3(0.04, 0.04, 0.04);
  1083. /**
  1084. * Epsilon value, used as a small tolerance value for a numeric value.
  1085. */
  1086. _GLTFMaterial.epsilon = 1e-6;
  1087. return _GLTFMaterial;
  1088. }());
  1089. GLTF2._GLTFMaterial = _GLTFMaterial;
  1090. })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
  1091. })(BABYLON || (BABYLON = {}));
  1092. //# sourceMappingURL=babylon.glTFMaterial.js.map