前言
最近制作three.js的项目,场景可能需要大量的花草树木进行装饰,但是如果采用模型去修饰的话,工作量很大,而且加载负荷也很重,如何才能在性能和效果上面做好平衡,这就是核心问题。
Maya给我的灵感
显然用实体的模型是不现实的,一棵还算客观的树至少也要有上千个面,然而当这个面数乘以几百之后,无谓的负荷将会让场景卡到无法动弹。
因此要用面片贴图去实现树的效果,而Maya自带的Paint Effect效果就提供了很好的参考。
用paint effect的笔刷在视图中画一笔,就可以生成一堆面片。
需要注意的是paint effect并不是多边形,它不能直接导出,只能用maya 软件渲染器去渲染,因此需要将它转成多边形。
转成多边形后按6键可以在视图中看到树木面片。
奇迹般的效果出来了,当你转动视图的时候,面片会自动朝向摄像机。
遗憾的是,当你删除了转化历史之后,所有的效果就消失了,所以当然这种效果也是不可能通过模型导出来的。
重点是这里提供了操作思路。只要面片是朝向摄像机的,就可以实现不错的伪3D效果。另外也可以在这里获取Maya的树木贴图,省得网上找了。
Three.js的sprite实现
如何在Three.js实现图片永远朝向摄像机呢,我首先想到了sprite,以前做Maya的粒子效果的时候有接触过这种形式的贴图效果,印象深刻。
首先的了解sprite在Three.js怎么用 - 链接
看过之后其实很简单,链接图片,添加材质,即可生成。和生成方块的流程差不多。
1 | //核心代码 |
这个效果还是有不少遗憾
- 不够立体。
- 和Maya的不一样,Maya的效果只在水平方向指向摄像机,sprite是无时无刻都指向摄像机,看起来就很奇怪。
- 定位麻烦
进阶解决方案
既然如此,那就考虑如何实现Maya的效果吧。所以后面我摈弃了sprite的使用,还是改为使用多边形面片。
多边形面片的好处是可以实现模型定位。
后面我尝试将Maya的模型面片导出,看看实现的效果。
我在代码上实现了效果,但是透明上出了大问题。
透明遮挡问题的解决方案
在Three.js的编辑器可以更加透彻方便地看到这里的问题。
这里并不是完全看不到透明背后的部分,只是渲染顺序不同导致透明的部分渲染后看不到背后的物体,这种情况下有些透明的面片先渲染,背后的物体还没有出来,透明部分后面的模型就看不到了。(如下图)
这种问题怎么解决呢?!Three.js的新版编辑器提供了render order选项,通过调节渲染顺序可以实现正确的渲染效果
这样子的话岂不是每个物体都要去手动调整,即便是用代码智能实现也要去研究物体到摄像机的距离,进而分配render order,这个工作量得干死人的。
当时真的慌得一匹。
我记得之前在弄房产信息Demo的时候也有遇到过类似的问题,当时网上找到的信息是去调整depthwrite的材质属性。
于是我赶紧在编辑器里面测试,但是开了之后效果惊为天人,透明完全错乱了。
我算是想尽办法了,不知道该怎么解决,回到编辑器看一下吧,在材质属性上看到alphaTest属性,想着也和透明有关系,就试着调了一下。
没想到问题就解决了,加上alphaTest的数值之后,就不用考虑渲染顺序的问题了。
1 | //核心代码 |
立体效果制作
上面的实现效果,模型始终还是个面片呀,怎么才能实现立体的效果呢?
先复制几个面片看看效果吧。
这次就尝试用Three.js的面片来实现,不用考虑模型导入那么麻烦。
这个效果并不理想,一看就知道是几个面片组成的树(:з」∠)
这时我想到了depthWrite的魔性效果,可能穿插的透明感觉正好可以混淆这里的立体效果
的确开了之后,效果确实不错,只是能感觉到有一个面片在旋转,
现在要考虑怎么实现在镜头移动的时候,树可以保持望向镜头,这样看起来就不会那么奇怪。
怎么实现类似于Maya的面片效果呢?
网上搜了一下还真找到了方案两个链接的核心处理就是 mesh.lookAt( camera.position );
但是我弄上去之后的效果就和sprite实现的效果是一样的了。
为了解决这个问题,我又去查了lookAt函数的用法。
给lookat的Y轴方向传入0参数就好了.
1 | //核心代码 |
顶部贴图
现在效果已经算是比较完美了,但是移动到顶部的时候,还是会暴露物体是由面片构成的。
如此就需要有一张树顶部的贴图了,同时又要求颜色基本保持一致,那就只能在原先的树贴图上用图章进行处理了。
弄好之后将水平贴到树的中心。
并且给它加入朝向摄像机的效果。
最终效果
将顶部贴图的透明度调节为0.5,这样不会显得违和,效果非常棒。
总结
这是我搭建出来的面数压到最低的生成效果,一棵树用了7个面片,总计14个三角形,另外还用了两张贴图。
用种方法搭建树林都毫无压力,缺点就是不能支持阴影,如果需要点击处理的话也会很麻烦而已。