threejs:3D模型导入问题
想想复杂的模型就交给3d设计师进行创作,而我们开发时只需引入模型文件,是不是很美滋滋?
当然,如果你时间充裕,又对模型创作感兴趣,那你确实可以花时间好好学习3d建模软件的使用,这样以后就可以自己创建所需模型,由自己导出与导入模型文件。因为从建模软件导出模型的过程中,其实有特别多的坑,一个不小心,导出的模型可能就大相径庭。所以依赖于别人导出的模型文件,有时你都不知道到底问题出在哪里。
一、threejs支持的常见导出模型的文件格式有哪些?
json(*.js/ *.json):专门为three.js自己设计的json格式,你可以使用它以声明的方式定义模型,及模型材质和动画。
obj和mtl(*.obj/ *.mtl):obj是一种简单的三维文件格式,只用来定义对象的几何体。mtl文件通常和obj文件一起使用,在一个mtl文件中,定义对象的材质。
collada (*.dae):用来定义xml类文件中数字内容的格式。差不多所有的三维软件和渲染引擎都支持这个格式。
stl (*.stl):立体成型术 。 广泛用于快速成型。例如,三维打印机的模型文件通常是stl文件。three.js有一个可定制的stl导出工具,stlexporter.js。可以将three.js中的模型导出到一个stl文件。
fbx (*.fbx):是filmbox这套软件所使用的格式,其最大的用途是用在诸如在max、maya、softimage等软件间进行模型、材质、动作和摄影机信息的互导,因此在创建三维内容的应用软件之间具有无与伦比的互用性。
ctm (*.ctm):由openctm创建的格式。可以用来压缩存储表示三维网格的三角形面片。
vtk(*.vtk):visualization tookit 定义的文件格式,用来指定顶点和面。vtk有两种格式,three.js支持旧的格式,即asscii格式。
pdb(*.pdb):特别的数据格式,由 蛋白质数据银行 场景,用来定义蛋白质的形状。three.js可以加载并显示这种描述格式的蛋白质。
ply (*.ply):多边形文件格式。通常保存三维扫描仪的数据。
二、threejs中导入以上外部模型文件所需的辅助函数是哪些?
threejs中导入外部文件所需的辅助函数都在https://github.com/mrdoob/three.js/tree/dev/examples/js/loaders下可以找到。这里除了json模型文件的导入外,其余模型文件都需要引用其对应名称的辅助函数。例如:导入obj格式的模型,除了导入必要的three.js文件外,还需要在界面中引用objloader.js文件。而jsonloader函数集成在three.js中,所以无需再导入其他辅助文件!
三、3d软件导出的模型文件可以解析哪些东西呢?
可解析出网格(模型)的有:json, stl, obj
可解析出模型材质的有:json, mtl
可解析出模型动画的有:fbx, dae, json
理解就是,如:导出的json文件既可以存物体的模型,也可以存其材质及动画信息。
四、threejs中几个常用模型文件导入示例
4.1 json格式文件导入——使用jsonloader函数
// 实例化一个jsonloader类 var loader = new three.jsonloader(); // 导入资源 loader.load( // 导入的模型文件所在 url 'models/animated/monster/monster.js', // 资源加载成功后执行的函数 //@params geometry 传入的模型,只能是单个模型,不能是一个场景 // @params materials 传入的材质,是个数组 function ( geometry, materials ) { var material = materials[ 0 ]; var object = new three.mesh( geometry, material ); scene.add( object ); } );
4.2 obj格式文件导入——使用objloader函数
敲黑板!!!!!前面已经讲过,obj格式文件都是和mtl格式文件搭配使用,因为obj格式的文件只能存模型,不能存模型材质和动画,而材质都存于mtl文件中。
4.2.1 当只导入模型,不导入材质,模型的材质由导入后用代码定义
//图片加载loader var texture = new three.texture(); var loader = new three.imageloader( ); //导入资源 loader.load( //材质图片所在url 'textures/uv_grid_sm.jpg', function ( image ) { texture.image = image; texture.needsupdate = true; } ); //obj文件加载loader var loader = new three.objloader( ); //导入资源 loader.load( //obj模型所在url 'obj/male02/male02.obj', // 资源加载成功后执行的函数 //@params object 传入的模型,只能是单个模型,也可能是一个group,视构建的model而定 function ( object ) { //taverse函数为遍历object的每个子mesh,传入的child为每个mesh //该示例中的object为一个group,有多个mesh组成 object.traverse( function ( child ) { if ( child instanceof three.mesh ) { child.material.map = texture; } } ); object.position.y = - 95; scene.add( object ); });4.2.2 当既导入模型,又导入材质时
//当mtl中引用了dds类型的图片时,还需导入ddsloader文件。 //这里的src路径视实际开发而定 <script src="js/loaders/ddsloader.js"></script> <script src="js/loaders/mtlloader.js"></script> <script src="js/loaders/objloader.js"></script> three.loader.handlers.add( /\.dds$/i, new three.ddsloader() ); var mtlloader = new three.mtlloader(); //设置路径,也可不是设置,在load中加载完整路径也可 mtlloader.setpath( 'obj/male02/' ); mtlloader.load( 'male02_dds.mtl', // 资源加载成功后执行的函数 //@params materials three.mtlloader.materialcreator function( materials ) { materials.preload(); var objloader = new three.objloader(); objloader.setmaterials( materials ); objloader.setpath( 'obj/male02/' ); objloader.load( 'male02.obj', function ( object ) { object.position.y = - 95; scene.add( object ); }); });
4.3 其他模型文件导入类似,具体可参考官网examples
https://threejs.org/examples/ 中的loader/*部分
五、常见问题
模型导出为obj格式后,文件太大,想将其转化为json格式以减少文件大小。那么该怎样操作呢?threejs r86版本中,有convert-to-threejs.py这样一个python文件,该文件的作用是将模型文件(.fbx,.dae, .obj, .3ds)转换成json格式。详细地转换操作可参考以下链接文章:
convert_to_threejs.py 使用配置
注意事项:
对以上链接文章做个小补充,这里箭头所引入的python版本最好一致,反正我当时不一致好像最后转化出bug了。
虽然threejs r86仍然保留convert-to-threejs.py,但是该文件作者已很久没维护,处于已过时的文件。所以即便成功将obj转换成json文件,仍有存在json文件不可用的情况(就问你绝不绝望??)。笔者在开发的过程中,就遇到该问题:成功转换成json文件后,用jsonloader导入该文件后报错,因为转换后的json文件中“type“类型为”scene“,因此既不符合jsonloader,也不符合objectloader的导入格式要求。查询相关资料,发现有许多小伙伴也遇到过这种bug,暂时没找到解决方法。如果有大大发现,请务必分享下解决方案,万分感谢!2. 如何用threejs导入基于json格式的场景文件?
所谓场景文件,也就是文件中列出了各个物体和变换层级,以及所有的材质,纹理,相机和光源信息。讲道理,如果成功导入一个场景文件后,进行基本渲染就可以查看整个3d场景了。之前threejs的版本中进行场景渲染调用three.sceneloader即可,不过现在threejs r86版本已用three.objectloader替代。
给个简单示例:
//@params url 场景文件所在路径 new three.objectloader().load( url, function ( loadedscene ) { scene = loadedscene; // if the loaded file contains a perspective camera, use it with adjusted aspect ratio... scene.traverse( function ( scenechild ) { if ( scenechild.type === 'perspectivecamera' ) { camera = scenechild; camera.aspect = screen_width / screen_height; camera.updateprojectionmatrix(); } } );
下一篇: Ai简单绘制一个圆形仪表图标