MTLLoader.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /**
  2. * Loads a Wavefront .mtl file specifying materials
  3. *
  4. * @author angelxuanchang
  5. */
  6. THREE.MTLLoader = function( manager ) {
  7. this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
  8. };
  9. THREE.MTLLoader.prototype = {
  10. constructor: THREE.MTLLoader,
  11. load: function ( url, onLoad, onProgress, onError ) {
  12. var scope = this;
  13. var loader = new THREE.XHRLoader( this.manager );
  14. loader.setPath( this.path );
  15. loader.load( url, function ( text ) {
  16. onLoad( scope.parse( text ) );
  17. }, onProgress, onError );
  18. },
  19. setPath: function ( value ) {
  20. this.path = value;
  21. },
  22. setBaseUrl: function( value ) {
  23. // TODO: Merge with setPath()? Or rename to setTexturePath?
  24. this.baseUrl = value;
  25. },
  26. setCrossOrigin: function ( value ) {
  27. this.crossOrigin = value;
  28. },
  29. setMaterialOptions: function ( value ) {
  30. this.materialOptions = value;
  31. },
  32. /**
  33. * Parses loaded MTL file
  34. * @param text - Content of MTL file
  35. * @return {THREE.MTLLoader.MaterialCreator}
  36. */
  37. parse: function ( text ) {
  38. var lines = text.split( "\n" );
  39. var info = {};
  40. var delimiter_pattern = /\s+/;
  41. var materialsInfo = {};
  42. for ( var i = 0; i < lines.length; i ++ ) {
  43. var line = lines[ i ];
  44. line = line.trim();
  45. if ( line.length === 0 || line.charAt( 0 ) === '#' ) {
  46. // Blank line or comment ignore
  47. continue;
  48. }
  49. var pos = line.indexOf( ' ' );
  50. var key = ( pos >= 0 ) ? line.substring( 0, pos ) : line;
  51. key = key.toLowerCase();
  52. var value = ( pos >= 0 ) ? line.substring( pos + 1 ) : "";
  53. value = value.trim();
  54. if ( key === "newmtl" ) {
  55. // New material
  56. info = { name: value };
  57. materialsInfo[ value ] = info;
  58. } else if ( info ) {
  59. if ( key === "ka" || key === "kd" || key === "ks" ) {
  60. var ss = value.split( delimiter_pattern, 3 );
  61. info[ key ] = [ parseFloat( ss[ 0 ] ), parseFloat( ss[ 1 ] ), parseFloat( ss[ 2 ] ) ];
  62. } else {
  63. info[ key ] = value;
  64. }
  65. }
  66. }
  67. var materialCreator = new THREE.MTLLoader.MaterialCreator( this.baseUrl, this.materialOptions );
  68. materialCreator.setCrossOrigin( this.crossOrigin );
  69. materialCreator.setManager( this.manager );
  70. materialCreator.setMaterials( materialsInfo );
  71. return materialCreator;
  72. }
  73. };
  74. /**
  75. * Create a new THREE-MTLLoader.MaterialCreator
  76. * @param baseUrl - Url relative to which textures are loaded
  77. * @param options - Set of options on how to construct the materials
  78. * side: Which side to apply the material
  79. * THREE.FrontSide (default), THREE.BackSide, THREE.DoubleSide
  80. * wrap: What type of wrapping to apply for textures
  81. * THREE.RepeatWrapping (default), THREE.ClampToEdgeWrapping, THREE.MirroredRepeatWrapping
  82. * normalizeRGB: RGBs need to be normalized to 0-1 from 0-255
  83. * Default: false, assumed to be already normalized
  84. * ignoreZeroRGBs: Ignore values of RGBs (Ka,Kd,Ks) that are all 0's
  85. * Default: false
  86. * @constructor
  87. */
  88. THREE.MTLLoader.MaterialCreator = function( baseUrl, options ) {
  89. this.baseUrl = baseUrl;
  90. this.options = options;
  91. this.materialsInfo = {};
  92. this.materials = {};
  93. this.materialsArray = [];
  94. this.nameLookup = {};
  95. this.side = ( this.options && this.options.side ) ? this.options.side : THREE.FrontSide;
  96. this.wrap = ( this.options && this.options.wrap ) ? this.options.wrap : THREE.RepeatWrapping;
  97. };
  98. THREE.MTLLoader.MaterialCreator.prototype = {
  99. constructor: THREE.MTLLoader.MaterialCreator,
  100. setCrossOrigin: function ( value ) {
  101. this.crossOrigin = value;
  102. },
  103. setManager: function ( value ) {
  104. this.manager = value;
  105. },
  106. setMaterials: function( materialsInfo ) {
  107. this.materialsInfo = this.convert( materialsInfo );
  108. this.materials = {};
  109. this.materialsArray = [];
  110. this.nameLookup = {};
  111. },
  112. convert: function( materialsInfo ) {
  113. if ( ! this.options ) return materialsInfo;
  114. var converted = {};
  115. for ( var mn in materialsInfo ) {
  116. // Convert materials info into normalized form based on options
  117. var mat = materialsInfo[ mn ];
  118. var covmat = {};
  119. converted[ mn ] = covmat;
  120. for ( var prop in mat ) {
  121. var save = true;
  122. var value = mat[ prop ];
  123. var lprop = prop.toLowerCase();
  124. switch ( lprop ) {
  125. case 'kd':
  126. case 'ka':
  127. case 'ks':
  128. // Diffuse color (color under white light) using RGB values
  129. if ( this.options && this.options.normalizeRGB ) {
  130. value = [ value[ 0 ] / 255, value[ 1 ] / 255, value[ 2 ] / 255 ];
  131. }
  132. if ( this.options && this.options.ignoreZeroRGBs ) {
  133. if ( value[ 0 ] === 0 && value[ 1 ] === 0 && value[ 1 ] === 0 ) {
  134. // ignore
  135. save = false;
  136. }
  137. }
  138. break;
  139. default:
  140. break;
  141. }
  142. if ( save ) {
  143. covmat[ lprop ] = value;
  144. }
  145. }
  146. }
  147. return converted;
  148. },
  149. preload: function () {
  150. for ( var mn in this.materialsInfo ) {
  151. this.create( mn );
  152. }
  153. },
  154. getIndex: function( materialName ) {
  155. return this.nameLookup[ materialName ];
  156. },
  157. getAsArray: function() {
  158. var index = 0;
  159. for ( var mn in this.materialsInfo ) {
  160. this.materialsArray[ index ] = this.create( mn );
  161. this.nameLookup[ mn ] = index;
  162. index ++;
  163. }
  164. return this.materialsArray;
  165. },
  166. create: function ( materialName ) {
  167. if ( this.materials[ materialName ] === undefined ) {
  168. this.createMaterial_( materialName );
  169. }
  170. return this.materials[ materialName ];
  171. },
  172. createMaterial_: function ( materialName ) {
  173. // Create material
  174. var mat = this.materialsInfo[ materialName ];
  175. var params = {
  176. name: materialName,
  177. side: this.side
  178. };
  179. for ( var prop in mat ) {
  180. var value = mat[ prop ];
  181. if ( value === '' ) continue;
  182. switch ( prop.toLowerCase() ) {
  183. // Ns is material specular exponent
  184. case 'kd':
  185. // Diffuse color (color under white light) using RGB values
  186. params[ 'color' ] = new THREE.Color().fromArray( value );
  187. break;
  188. case 'ks':
  189. // Specular color (color when light is reflected from shiny surface) using RGB values
  190. params[ 'specular' ] = new THREE.Color().fromArray( value );
  191. break;
  192. case 'map_kd':
  193. // Diffuse texture map
  194. params[ 'map' ] = this.loadTexture( this.baseUrl + value );
  195. params[ 'map' ].wrapS = this.wrap;
  196. params[ 'map' ].wrapT = this.wrap;
  197. break;
  198. case 'ns':
  199. // The specular exponent (defines the focus of the specular highlight)
  200. // A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000.
  201. params[ 'shininess' ] = parseFloat( value );
  202. break;
  203. case 'd':
  204. if ( value < 1 ) {
  205. params[ 'opacity' ] = value;
  206. params[ 'transparent' ] = true;
  207. }
  208. break;
  209. case 'Tr':
  210. if ( value > 0 ) {
  211. params[ 'opacity' ] = 1 - value;
  212. params[ 'transparent' ] = true;
  213. }
  214. break;
  215. case 'map_bump':
  216. case 'bump':
  217. // Bump texture map
  218. if ( params[ 'bumpMap' ] ) break; // Avoid loading twice.
  219. params[ 'bumpMap' ] = this.loadTexture( this.baseUrl + value );
  220. params[ 'bumpMap' ].wrapS = this.wrap;
  221. params[ 'bumpMap' ].wrapT = this.wrap;
  222. break;
  223. default:
  224. break;
  225. }
  226. }
  227. this.materials[ materialName ] = new THREE.MeshPhongMaterial( params );
  228. return this.materials[ materialName ];
  229. },
  230. loadTexture: function ( url, mapping, onLoad, onProgress, onError ) {
  231. var texture;
  232. var loader = THREE.Loader.Handlers.get( url );
  233. var manager = ( this.manager !== undefined ) ? this.manager : THREE.DefaultLoadingManager;
  234. if ( loader === null ) {
  235. loader = new THREE.TextureLoader( manager );
  236. }
  237. if ( loader.setCrossOrigin ) loader.setCrossOrigin( this.crossOrigin );
  238. texture = loader.load( url, onLoad, onProgress, onError );
  239. if ( mapping !== undefined ) texture.mapping = mapping;
  240. return texture;
  241. }
  242. };
  243. THREE.EventDispatcher.prototype.apply( THREE.MTLLoader.prototype );