原先只是实现了用单张贴图的透明效果,但是在工作中,好多模型都是用三维建模软件制作的,导出obj后可以直接导入到我们的程序中去;
如果是使用OBJMTLLoader那么,模型中透明贴图效果要怎么实现呢?
我们已经知道,要想在程序中实现透明贴图的效果,就需要将模型的材质的透明属性设置为true;
下面我们就来寻找OBJMTLLoader中设置材质属性的关键点吧。
OBJMTLLoader.js的路径为:ThreeJS\examples\js\loaders\OBJMTLLoader.js;
设置模型材质的代码如下:
if ( object.material.name ) { var material = materialsCreator.create( object.material.name ); if ( material ) { object.material = material; } }
我们要怎么判断是否要把材质的透明属性设置为true呢?通过贴图的文件名,如果贴图文件名包含png,那么我们就把材质的属性设置为true;
添加代码如下:
if ( object.material.name ) { var material = materialsCreator.create( object.material.name ); if ( material ) { object.material = material; if((undefined == material.map) || (null == material.map)) { console.log('undefined == material.map'); } else if((undefined == material.map.image) ||((null == material.map.image))) { console.log('undefined == material.map.image'); } else if((undefined == material.map.image.src) || (null == material.map.image.src)) { console.log('undefined == material.map.image.src'); } else if(material.map.image.src.toLowerCase().contains('png')) { console.log('ObjMTLLoader:' + material.map.image.src.toLowerCase()); material.transparent = true; } } }
可是经过测试发现经常会出现“undefined == material.map.image”,这是什么原因呢,并且更奇怪的是,如果在前面加一个断点,就可以正常运行,真是让人困扰啊!经过重重困难,原因终于被发现了,原来是因为image是一个对象,可能在执行到这一句的时候该对象还没有构建完成,所以导致该问题,如何解决呢?断续跟踪;
这一次我们切入的关键代码是:
var material = materialsCreator.create( object.material.name );
这是创建材质的过程,直接杀进去应该可以解决问题,我们看代码:
create: function ( materialName ) { if ( this.materials[ materialName ] === undefined ) { this.createMaterial_( materialName ); } return this.materials[ materialName ]; }
直接返回了一个“this.materials[ materialName ]”,这是个什么?断续跟踪!
1 createMaterial_: function ( materialName ) { 2 3 // Create material 4 5 var mat = this.materialsInfo[ materialName ]; 6 var params = { 7 8 name: materialName, 9 side: this.side 10 11 }; 12 //增加一个变量,保存材质是否透明 13 //默认为false 14 var bTransparent = false; 15 for ( var prop in mat ) { 16 17 var value = mat[ prop ]; 18 19 switch ( prop.toLowerCase() ) { 20 21 // Ns is material specular exponent 22 23 case 'kd': 24 25 // Diffuse color (color under white light) using RGB values 26 27 params[ 'diffuse' ] = new THREE.Color().fromArray( value ); 28 29 break; 30 31 case 'ka': 32 33 // Ambient color (color under shadow) using RGB values 34 35 break; 36 37 case 'ks': 38 39 // Specular color (color when light is reflected from shiny surface) using RGB values 40 params[ 'specular' ] = new THREE.Color().fromArray( value ); 41 42 break; 43 44 case 'map_kd': 45 46 // Diffuse texture map 47 //哇,看,这就是我们要找的东西了 48 //贴图就是在这一步生成的 49 //我们直接在这一步做判断,应该万无一失了吧 50 params[ 'map' ] = this.loadTexture( this.baseUrl + value ); 51 params[ 'map' ].wrapS = this.wrap; 52 params[ 'map' ].wrapT = this.wrap; 53 //添加是否透明判断 54 if (value.toLowerCase().contains('png')) 55 bTransparent = true; 56 break; 57 58 case 'ns': 59 60 // The specular exponent (defines the focus of the specular highlight) 61 // A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000. 62 63 params['shininess'] = value; 64 65 break; 66 67 case 'd': 68 69 // According to MTL format (http://paulbourke.net/dataformats/mtl/): 70 // d is dissolve for current material 71 // factor of 1.0 is fully opaque, a factor of 0 is fully dissolved (completely transparent) 72 73 if ( value < 1 ) { 74 75 params['transparent'] = true; 76 params['opacity'] = value; 77 78 } 79 80 break; 81 82 case 'map_bump': 83 case 'bump': 84 85 // Bump texture map 86 87 if ( params[ 'bumpMap' ] ) break; // Avoid loading twice. 88 89 params[ 'bumpMap' ] = this.loadTexture( this.baseUrl + value ); 90 params[ 'bumpMap' ].wrapS = this.wrap; 91 params[ 'bumpMap' ].wrapT = this.wrap; 92 93 break; 94 95 default: 96 break; 97 98 } 99 100 } 101 102 if ( params[ 'diffuse' ] ) { 103 104 params[ 'color' ] = params[ 'diffuse' ]; 105 106 } 107 108 this.materials[ materialName ] = new THREE.MeshPhongMaterial( params ); 109 //设置材质的透明属性 110 this.materials[ materialName ].transparent = bTransparent; 111 return this.materials[ materialName ]; 112 113 }
这样修改以后,经测试已基本满足正常使用!