mtlFileLoader.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. import { Color3 } from "@babylonjs/core/Maths/math.color.js";
  2. import { Texture } from "@babylonjs/core/Materials/Textures/texture.js";
  3. import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial.js";
  4. /**
  5. * Class reading and parsing the MTL file bundled with the obj file.
  6. */
  7. export class MTLFileLoader {
  8. constructor() {
  9. /**
  10. * All material loaded from the mtl will be set here
  11. */
  12. this.materials = [];
  13. }
  14. /**
  15. * This function will read the mtl file and create each material described inside
  16. * This function could be improve by adding :
  17. * -some component missing (Ni, Tf...)
  18. * -including the specific options available
  19. *
  20. * @param scene defines the scene the material will be created in
  21. * @param data defines the mtl data to parse
  22. * @param rootUrl defines the rooturl to use in order to load relative dependencies
  23. * @param assetContainer defines the asset container to store the material in (can be null)
  24. */
  25. parseMTL(scene, data, rootUrl, assetContainer) {
  26. if (data instanceof ArrayBuffer) {
  27. return;
  28. }
  29. //Split the lines from the file
  30. const lines = data.split("\n");
  31. // whitespace char ie: [ \t\r\n\f]
  32. const delimiter_pattern = /\s+/;
  33. //Array with RGB colors
  34. let color;
  35. //New material
  36. let material = null;
  37. //Look at each line
  38. for (let i = 0; i < lines.length; i++) {
  39. const line = lines[i].trim();
  40. // Blank line or comment
  41. if (line.length === 0 || line.charAt(0) === "#") {
  42. continue;
  43. }
  44. //Get the first parameter (keyword)
  45. const pos = line.indexOf(" ");
  46. let key = pos >= 0 ? line.substring(0, pos) : line;
  47. key = key.toLowerCase();
  48. //Get the data following the key
  49. const value = pos >= 0 ? line.substring(pos + 1).trim() : "";
  50. //This mtl keyword will create the new material
  51. if (key === "newmtl") {
  52. //Check if it is the first material.
  53. // Materials specifications are described after this keyword.
  54. if (material) {
  55. //Add the previous material in the material array.
  56. this.materials.push(material);
  57. }
  58. //Create a new material.
  59. // value is the name of the material read in the mtl file
  60. scene._blockEntityCollection = !!assetContainer;
  61. material = new StandardMaterial(value, scene);
  62. material._parentContainer = assetContainer;
  63. scene._blockEntityCollection = false;
  64. }
  65. else if (key === "kd" && material) {
  66. // Diffuse color (color under white light) using RGB values
  67. //value = "r g b"
  68. color = value.split(delimiter_pattern, 3).map(parseFloat);
  69. //color = [r,g,b]
  70. //Set tghe color into the material
  71. material.diffuseColor = Color3.FromArray(color);
  72. }
  73. else if (key === "ka" && material) {
  74. // Ambient color (color under shadow) using RGB values
  75. //value = "r g b"
  76. color = value.split(delimiter_pattern, 3).map(parseFloat);
  77. //color = [r,g,b]
  78. //Set tghe color into the material
  79. material.ambientColor = Color3.FromArray(color);
  80. }
  81. else if (key === "ks" && material) {
  82. // Specular color (color when light is reflected from shiny surface) using RGB values
  83. //value = "r g b"
  84. color = value.split(delimiter_pattern, 3).map(parseFloat);
  85. //color = [r,g,b]
  86. //Set the color into the material
  87. material.specularColor = Color3.FromArray(color);
  88. }
  89. else if (key === "ke" && material) {
  90. // Emissive color using RGB values
  91. color = value.split(delimiter_pattern, 3).map(parseFloat);
  92. material.emissiveColor = Color3.FromArray(color);
  93. }
  94. else if (key === "ns" && material) {
  95. //value = "Integer"
  96. material.specularPower = parseFloat(value);
  97. }
  98. else if (key === "d" && material) {
  99. //d is dissolve for current material. It mean alpha for BABYLON
  100. material.alpha = parseFloat(value);
  101. //Texture
  102. //This part can be improved by adding the possible options of texture
  103. }
  104. else if (key === "map_ka" && material) {
  105. // ambient texture map with a loaded image
  106. //We must first get the folder of the image
  107. material.ambientTexture = MTLFileLoader._GetTexture(rootUrl, value, scene);
  108. }
  109. else if (key === "map_kd" && material) {
  110. // Diffuse texture map with a loaded image
  111. material.diffuseTexture = MTLFileLoader._GetTexture(rootUrl, value, scene);
  112. }
  113. else if (key === "map_ks" && material) {
  114. // Specular texture map with a loaded image
  115. //We must first get the folder of the image
  116. material.specularTexture = MTLFileLoader._GetTexture(rootUrl, value, scene);
  117. }
  118. else if (key === "map_ns") {
  119. //Specular
  120. //Specular highlight component
  121. //We must first get the folder of the image
  122. //
  123. //Not supported by BABYLON
  124. //
  125. // continue;
  126. }
  127. else if (key === "map_bump" && material) {
  128. //The bump texture
  129. const values = value.split(delimiter_pattern);
  130. const bumpMultiplierIndex = values.indexOf("-bm");
  131. let bumpMultiplier = null;
  132. if (bumpMultiplierIndex >= 0) {
  133. bumpMultiplier = values[bumpMultiplierIndex + 1];
  134. values.splice(bumpMultiplierIndex, 2); // remove
  135. }
  136. material.bumpTexture = MTLFileLoader._GetTexture(rootUrl, values.join(" "), scene);
  137. if (material.bumpTexture && bumpMultiplier !== null) {
  138. material.bumpTexture.level = parseFloat(bumpMultiplier);
  139. }
  140. }
  141. else if (key === "map_d" && material) {
  142. // The dissolve of the material
  143. material.opacityTexture = MTLFileLoader._GetTexture(rootUrl, value, scene);
  144. //Options for illumination
  145. }
  146. else if (key === "illum") {
  147. //Illumination
  148. if (value === "0") {
  149. //That mean Kd == Kd
  150. }
  151. else if (value === "1") {
  152. //Color on and Ambient on
  153. }
  154. else if (value === "2") {
  155. //Highlight on
  156. }
  157. else if (value === "3") {
  158. //Reflection on and Ray trace on
  159. }
  160. else if (value === "4") {
  161. //Transparency: Glass on, Reflection: Ray trace on
  162. }
  163. else if (value === "5") {
  164. //Reflection: Fresnel on and Ray trace on
  165. }
  166. else if (value === "6") {
  167. //Transparency: Refraction on, Reflection: Fresnel off and Ray trace on
  168. }
  169. else if (value === "7") {
  170. //Transparency: Refraction on, Reflection: Fresnel on and Ray trace on
  171. }
  172. else if (value === "8") {
  173. //Reflection on and Ray trace off
  174. }
  175. else if (value === "9") {
  176. //Transparency: Glass on, Reflection: Ray trace off
  177. }
  178. else if (value === "10") {
  179. //Casts shadows onto invisible surfaces
  180. }
  181. }
  182. else {
  183. // console.log("Unhandled expression at line : " + i +'\n' + "with value : " + line);
  184. }
  185. }
  186. //At the end of the file, add the last material
  187. if (material) {
  188. this.materials.push(material);
  189. }
  190. }
  191. /**
  192. * Gets the texture for the material.
  193. *
  194. * If the material is imported from input file,
  195. * We sanitize the url to ensure it takes the texture from aside the material.
  196. *
  197. * @param rootUrl The root url to load from
  198. * @param value The value stored in the mtl
  199. * @param scene
  200. * @returns The Texture
  201. */
  202. static _GetTexture(rootUrl, value, scene) {
  203. if (!value) {
  204. return null;
  205. }
  206. let url = rootUrl;
  207. // Load from input file.
  208. if (rootUrl === "file:") {
  209. let lastDelimiter = value.lastIndexOf("\\");
  210. if (lastDelimiter === -1) {
  211. lastDelimiter = value.lastIndexOf("/");
  212. }
  213. if (lastDelimiter > -1) {
  214. url += value.substr(lastDelimiter + 1);
  215. }
  216. else {
  217. url += value;
  218. }
  219. }
  220. // Not from input file.
  221. else {
  222. url += value;
  223. }
  224. return new Texture(url, scene, false, MTLFileLoader.INVERT_TEXTURE_Y);
  225. }
  226. }
  227. /**
  228. * Invert Y-Axis of referenced textures on load
  229. */
  230. MTLFileLoader.INVERT_TEXTURE_Y = true;
  231. //# sourceMappingURL=mtlFileLoader.js.map