babylon.glTFFileLoaderUtils.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. module BABYLON {
  2. /**
  3. * Utils functions for GLTF
  4. */
  5. export class GLTFUtils {
  6. /**
  7. * Sets the given "parameter" matrix
  8. * @param scene: the {BABYLON.Scene} object
  9. * @param source: the source node where to pick the matrix
  10. * @param parameter: the GLTF technique parameter
  11. * @param uniformName: the name of the shader's uniform
  12. * @param shaderMaterial: the shader material
  13. */
  14. public static SetMatrix(scene: Scene, source: Node, parameter: IGLTFTechniqueParameter, uniformName: string, shaderMaterial: ShaderMaterial | Effect): void {
  15. var mat: Matrix = null;
  16. if (parameter.semantic === "MODEL") {
  17. mat = source.getWorldMatrix();
  18. }
  19. else if (parameter.semantic === "PROJECTION") {
  20. mat = scene.getProjectionMatrix();
  21. }
  22. else if (parameter.semantic === "VIEW") {
  23. mat = scene.getViewMatrix();
  24. }
  25. else if (parameter.semantic === "MODELVIEWINVERSETRANSPOSE") {
  26. mat = Matrix.Transpose(source.getWorldMatrix().multiply(scene.getViewMatrix()).invert());
  27. }
  28. else if (parameter.semantic === "MODELVIEW") {
  29. mat = source.getWorldMatrix().multiply(scene.getViewMatrix());
  30. }
  31. else if (parameter.semantic === "MODELVIEWPROJECTION") {
  32. mat = source.getWorldMatrix().multiply(scene.getTransformMatrix());
  33. }
  34. else if (parameter.semantic === "MODELINVERSE") {
  35. mat = source.getWorldMatrix().invert();
  36. }
  37. else if (parameter.semantic === "VIEWINVERSE") {
  38. mat = scene.getViewMatrix().invert();
  39. }
  40. else if (parameter.semantic === "PROJECTIONINVERSE") {
  41. mat = scene.getProjectionMatrix().invert();
  42. }
  43. else if (parameter.semantic === "MODELVIEWINVERSE") {
  44. mat = source.getWorldMatrix().multiply(scene.getViewMatrix()).invert();
  45. }
  46. else if (parameter.semantic === "MODELVIEWPROJECTIONINVERSE") {
  47. mat = source.getWorldMatrix().multiply(scene.getTransformMatrix()).invert();
  48. }
  49. else if (parameter.semantic === "MODELINVERSETRANSPOSE") {
  50. mat = Matrix.Transpose(source.getWorldMatrix().invert());
  51. }
  52. else {
  53. debugger;
  54. }
  55. switch (parameter.type) {
  56. case EParameterType.FLOAT_MAT2: shaderMaterial.setMatrix2x2(uniformName, Matrix.GetAsMatrix2x2(mat)); break;
  57. case EParameterType.FLOAT_MAT3: shaderMaterial.setMatrix3x3(uniformName, Matrix.GetAsMatrix3x3(mat)); break;
  58. case EParameterType.FLOAT_MAT4: shaderMaterial.setMatrix(uniformName, mat); break;
  59. default: break;
  60. }
  61. }
  62. /**
  63. * Sets the given "parameter" matrix
  64. * @param shaderMaterial: the shader material
  65. * @param uniform: the name of the shader's uniform
  66. * @param value: the value of the uniform
  67. * @param type: the uniform's type (EParameterType FLOAT, VEC2, VEC3 or VEC4)
  68. */
  69. public static SetUniform(shaderMaterial: ShaderMaterial | Effect, uniform: string, value: any, type: number): boolean {
  70. switch (type) {
  71. case EParameterType.FLOAT: shaderMaterial.setFloat(uniform, value); return true;
  72. case EParameterType.FLOAT_VEC2: shaderMaterial.setVector2(uniform, Vector2.FromArray(value)); return true;
  73. case EParameterType.FLOAT_VEC3: shaderMaterial.setVector3(uniform, Vector3.FromArray(value)); return true;
  74. case EParameterType.FLOAT_VEC4: shaderMaterial.setVector4(uniform, Vector4.FromArray(value)); return true;
  75. default: return false;
  76. }
  77. }
  78. /**
  79. * If the uri is a base64 string
  80. * @param uri: the uri to test
  81. */
  82. public static IsBase64(uri: string): boolean {
  83. return uri.length < 5 ? false : uri.substr(0, 5) === "data:";
  84. }
  85. /**
  86. * Returns the wrap mode of the texture
  87. * @param mode: the mode value
  88. */
  89. public static GetWrapMode(mode: number): number {
  90. switch (mode) {
  91. case ETextureWrapMode.CLAMP_TO_EDGE: return Texture.CLAMP_ADDRESSMODE;
  92. case ETextureWrapMode.MIRRORED_REPEAT: return Texture.MIRROR_ADDRESSMODE;
  93. case ETextureWrapMode.REPEAT: return Texture.WRAP_ADDRESSMODE;
  94. default: return Texture.WRAP_ADDRESSMODE;
  95. }
  96. }
  97. /**
  98. * Returns the byte stride giving an accessor
  99. * @param accessor: the GLTF accessor objet
  100. */
  101. public static GetByteStrideFromType(accessor: IGLTFAccessor): number {
  102. // Needs this function since "byteStride" isn't requiered in glTF format
  103. var type = accessor.type;
  104. switch (type) {
  105. case "VEC2": return 2;
  106. case "VEC3": return 3;
  107. case "VEC4": return 4;
  108. case "MAT2": return 4;
  109. case "MAT3": return 9;
  110. case "MAT4": return 16;
  111. default: return 1;
  112. }
  113. }
  114. /**
  115. * Returns the texture filter mode giving a mode value
  116. * @param mode: the filter mode value
  117. */
  118. public static GetTextureFilterMode(mode: number): ETextureFilterType {
  119. switch (mode) {
  120. case ETextureFilterType.LINEAR:
  121. case ETextureFilterType.LINEAR_MIPMAP_NEAREST:
  122. case ETextureFilterType.LINEAR_MIPMAP_LINEAR: return Texture.TRILINEAR_SAMPLINGMODE;
  123. case ETextureFilterType.NEAREST:
  124. case ETextureFilterType.NEAREST_MIPMAP_NEAREST: return Texture.NEAREST_SAMPLINGMODE;
  125. default: return Texture.BILINEAR_SAMPLINGMODE;
  126. }
  127. }
  128. public static GetBufferFromBufferView(gltfRuntime: IGLTFRuntime, bufferView: IGLTFBufferView, byteOffset: number, byteLength: number, componentType: EComponentType): any {
  129. var byteOffset = bufferView.byteOffset + byteOffset;
  130. var loadedBufferView = gltfRuntime.loadedBufferViews[bufferView.buffer];
  131. if (byteOffset + byteLength > loadedBufferView.byteLength) {
  132. throw new Error("Buffer access is out of range");
  133. }
  134. var buffer = loadedBufferView.buffer;
  135. byteOffset += loadedBufferView.byteOffset;
  136. switch (componentType) {
  137. case EComponentType.BYTE: return new Int8Array(buffer, byteOffset, byteLength);
  138. case EComponentType.UNSIGNED_BYTE: return new Uint8Array(buffer, byteOffset, byteLength);
  139. case EComponentType.SHORT: return new Int16Array(buffer, byteOffset, byteLength);
  140. case EComponentType.UNSIGNED_SHORT: return new Uint16Array(buffer, byteOffset, byteLength);
  141. default: return new Float32Array(buffer, byteOffset, byteLength);
  142. }
  143. }
  144. /**
  145. * Returns a buffer from its accessor
  146. * @param gltfRuntime: the GLTF runtime
  147. * @param accessor: the GLTF accessor
  148. */
  149. public static GetBufferFromAccessor(gltfRuntime: IGLTFRuntime, accessor: IGLTFAccessor): any {
  150. var bufferView: IGLTFBufferView = gltfRuntime.bufferViews[accessor.bufferView];
  151. var byteLength = accessor.count * GLTFUtils.GetByteStrideFromType(accessor);
  152. return GLTFUtils.GetBufferFromBufferView(gltfRuntime, bufferView, accessor.byteOffset, byteLength, accessor.componentType);
  153. }
  154. /**
  155. * Decodes a buffer view into a string
  156. * @param view: the buffer view
  157. */
  158. public static DecodeBufferToText(view: ArrayBufferView): string {
  159. var result = "";
  160. var length = view.byteLength;
  161. for (var i = 0; i < length; ++i) {
  162. result += String.fromCharCode(view[i]);
  163. }
  164. return result;
  165. }
  166. /**
  167. * Loads a texture from its name
  168. * @param gltfRuntime: the gltf runtime
  169. * @param name: the name of the texture
  170. */
  171. public static LoadTextureAsync(gltfRuntime: IGLTFRuntime, texture: IGLTFTexture, onSuccess: (texture: Texture) => void, onError: () => void): void {
  172. if (!texture || !texture.source) {
  173. onError();
  174. return;
  175. }
  176. if (texture.babylonTexture) {
  177. onSuccess(texture.babylonTexture);
  178. return;
  179. }
  180. var sampler: IGLTFSampler = gltfRuntime.samplers[texture.sampler];
  181. var source: IGLTFImage = gltfRuntime.images[texture.source];
  182. var newTexture: Texture;
  183. var createMipMaps =
  184. (sampler.minFilter === ETextureFilterType.NEAREST_MIPMAP_NEAREST) ||
  185. (sampler.minFilter === ETextureFilterType.NEAREST_MIPMAP_LINEAR) ||
  186. (sampler.minFilter === ETextureFilterType.LINEAR_MIPMAP_NEAREST) ||
  187. (sampler.minFilter === ETextureFilterType.LINEAR_MIPMAP_LINEAR);
  188. var samplingMode = Texture.BILINEAR_SAMPLINGMODE;
  189. if (GLTFUtils.IsBase64(source.uri)) {
  190. newTexture = new Texture(source.uri, gltfRuntime.scene, !createMipMaps, true, samplingMode, () => onSuccess(newTexture), onError, source.uri, true);
  191. }
  192. else {
  193. newTexture = new Texture(gltfRuntime.rootUrl + source.uri, gltfRuntime.scene, !createMipMaps, true, samplingMode, () => onSuccess(newTexture), onError);
  194. }
  195. newTexture.wrapU = GLTFUtils.GetWrapMode(sampler.wrapS);
  196. newTexture.wrapV = GLTFUtils.GetWrapMode(sampler.wrapT);
  197. newTexture.name = name;
  198. texture.babylonTexture = newTexture;
  199. }
  200. public static LoadShaderAsync(gltfRuntime: IGLTFRuntime, shader: IGLTFShader, onSuccess: (shaderString: string) => void, onError: () => void): void {
  201. if (GLTFUtils.IsBase64(shader.uri)) {
  202. var shaderString = atob(shader.uri.split(",")[1]);
  203. onSuccess(shaderString);
  204. }
  205. else {
  206. Tools.LoadFile(gltfRuntime.rootUrl + shader.uri, onSuccess, null, null, false, onError);
  207. }
  208. }
  209. /**
  210. * Decode array buffer from base64
  211. */
  212. public static DecodeArrayBuffer(base64: string): ArrayBuffer {
  213. var decodedString = atob(base64);
  214. var bufferLength = decodedString.length;
  215. var arraybuffer = new Uint8Array(new ArrayBuffer(bufferLength));
  216. for (var i = 0; i < bufferLength; i++) {
  217. arraybuffer[i] = decodedString.charCodeAt(i);
  218. }
  219. return arraybuffer.buffer;
  220. };
  221. public static LoadBufferAsync(gltfRuntime: IGLTFRuntime, buffer: IGLTFBuffer, onSuccess: (bufferView: ArrayBufferView) => void, onError: () => void): void {
  222. if (GLTFUtils.IsBase64(buffer.uri)) {
  223. var decodedBuffer = GLTFUtils.DecodeArrayBuffer(buffer.uri.split(",")[1]);
  224. onSuccess(new Uint8Array(decodedBuffer));
  225. }
  226. else {
  227. Tools.LoadFile(gltfRuntime.rootUrl + buffer.uri, data => onSuccess(new Uint8Array(data)), null, null, true, onError);
  228. }
  229. }
  230. public static ParseObject(parsedObjects: any, runtimeProperty: string, gltfRuntime: IGLTFRuntime): void {
  231. for (var object in parsedObjects) {
  232. var parsedObject = parsedObjects[object];
  233. gltfRuntime[runtimeProperty][object] = parsedObject;
  234. }
  235. }
  236. public static ParseBuffers(parsedBuffers: any, gltfRuntime: IGLTFRuntime): void {
  237. for (var buf in parsedBuffers) {
  238. var parsedBuffer = parsedBuffers[buf];
  239. gltfRuntime.buffers[buf] = parsedBuffer;
  240. gltfRuntime.buffersCount++;
  241. }
  242. }
  243. public static ParseShaders(parsedShaders: any, gltfRuntime: IGLTFRuntime): void {
  244. for (var sha in parsedShaders) {
  245. var parsedShader = parsedShaders[sha];
  246. gltfRuntime.shaders[sha] = parsedShader;
  247. gltfRuntime.shaderscount++;
  248. }
  249. }
  250. public static CreateGlTFRuntime(parsedData: any, scene: Scene, rootUrl: string): IGLTFRuntime {
  251. var gltfRuntime: IGLTFRuntime = {
  252. accessors: {},
  253. buffers: {},
  254. bufferViews: {},
  255. meshes: {},
  256. lights: {},
  257. cameras: {},
  258. nodes: {},
  259. images: {},
  260. textures: {},
  261. shaders: {},
  262. programs: {},
  263. samplers: {},
  264. techniques: {},
  265. materials: {},
  266. animations: {},
  267. skins: {},
  268. currentScene: {},
  269. extensionsUsed: [],
  270. buffersCount: 0,
  271. shaderscount: 0,
  272. scene: scene,
  273. rootUrl: rootUrl,
  274. loadedBufferCount: 0,
  275. loadedBufferViews: {},
  276. loadedShaderCount: 0,
  277. importOnlyMeshes: false,
  278. dummyNodes: []
  279. }
  280. // Parse
  281. if (parsedData.extensionsUsed) {
  282. GLTFUtils.ParseObject(parsedData.extensionsUsed, "extensionsUsed", gltfRuntime);
  283. }
  284. if (parsedData.buffers) {
  285. GLTFUtils.ParseBuffers(parsedData.buffers, gltfRuntime);
  286. }
  287. if (parsedData.bufferViews) {
  288. GLTFUtils.ParseObject(parsedData.bufferViews, "bufferViews", gltfRuntime);
  289. }
  290. if (parsedData.accessors) {
  291. GLTFUtils.ParseObject(parsedData.accessors, "accessors", gltfRuntime);
  292. }
  293. if (parsedData.meshes) {
  294. GLTFUtils.ParseObject(parsedData.meshes, "meshes", gltfRuntime);
  295. }
  296. if (parsedData.lights) {
  297. GLTFUtils.ParseObject(parsedData.lights, "lights", gltfRuntime);
  298. }
  299. if (parsedData.cameras) {
  300. GLTFUtils.ParseObject(parsedData.cameras, "cameras", gltfRuntime);
  301. }
  302. if (parsedData.nodes) {
  303. GLTFUtils.ParseObject(parsedData.nodes, "nodes", gltfRuntime);
  304. }
  305. if (parsedData.images) {
  306. GLTFUtils.ParseObject(parsedData.images, "images", gltfRuntime);
  307. }
  308. if (parsedData.textures) {
  309. GLTFUtils.ParseObject(parsedData.textures, "textures", gltfRuntime);
  310. }
  311. if (parsedData.shaders) {
  312. GLTFUtils.ParseShaders(parsedData.shaders, gltfRuntime);
  313. }
  314. if (parsedData.programs) {
  315. GLTFUtils.ParseObject(parsedData.programs, "programs", gltfRuntime);
  316. }
  317. if (parsedData.samplers) {
  318. GLTFUtils.ParseObject(parsedData.samplers, "samplers", gltfRuntime);
  319. }
  320. if (parsedData.techniques) {
  321. GLTFUtils.ParseObject(parsedData.techniques, "techniques", gltfRuntime);
  322. }
  323. if (parsedData.materials) {
  324. GLTFUtils.ParseObject(parsedData.materials, "materials", gltfRuntime);
  325. }
  326. if (parsedData.animations) {
  327. GLTFUtils.ParseObject(parsedData.animations, "animations", gltfRuntime);
  328. }
  329. if (parsedData.skins) {
  330. GLTFUtils.ParseObject(parsedData.skins, "skins", gltfRuntime);
  331. }
  332. if (parsedData.scene && parsedData.scenes) {
  333. gltfRuntime.currentScene = parsedData.scenes[parsedData.scene];
  334. }
  335. return gltfRuntime;
  336. }
  337. }
  338. }