动态光照是three.js应用的主要性能瓶颈之一,尤其是模型材质比较复杂时,动态光照需要消耗更多的计算资源。

在一些不需要动态光照的场景里,我们可以将场景中的所有光照和阴影都烘焙bake到材质贴图中,在three.js中渲染时就可以节约大量的计算量,这对手机等性能相对不高的移动设备是一种常用的优化方法。

为了在three.js中得到正确的渲染效果,这次行歌介绍下在blender中烘焙材质需要注意的地方,然后我会用three.js加入简单的3D物品导航功能让场景动起来。

材质的烘焙

在UV编辑模式中,新建一张材质贴图,因为我准备将整个场景都烘焙在一张贴图中,为了保证放大后的材质质量,这里的尺寸选择4096×4096;颜色使用白色,之所以使用白色的原因是:白色更接近反光的颜色,可以帮助我们避免一些贴图显示问题;注意要勾选32位浮点选项。

为了保证输出正确的颜色输出,这里务必把图片存为HDR格式。

然后设置uv展开,这里我直接最快捷smart uv的展开方式,缺点是不方便后续的修改。

然后要将场景中的所有物体光照都烘焙在一张贴图上,这时候需要反选取消清除画布的选项,保留上次烘焙的结果。

烘焙结束后你会发现生成的材质贴图有大量的噪点,这时可以利用blender中的后期合成composite功能,使用denoise插件对烘焙好的图片进行降噪处理,将生成后的图片保存为jpeg格式即可。

在three.js中渲染模型

在three.js中使用GLTFLoader加载导出的gltf模型,为了得到正确的渲染效果,需要设置渲染器和材质的编码,并将材质的flipY值设置为false。

//设置渲染器
renderer.outputEncoding = THREE.sRGBEncoding
//设置材质
texture.flipY = false
texture.encoding = THREE.sRGBEncoding

实现简单的3D物品导航

首先我们获取需要导航物体在场景中的世界坐标,当点击导航按钮时,我们通过移动摄像机对准当前选中的物体的世界坐标,实现3D导航功能。

gsap.to(camera.position, {
  x: pos.end.x,
  y: pos.end.y,
  z: pos.end.z,
  duration: 1.5,
  ease: 'expo.inOut',
  onUpdate() {
    //平滑过渡摄像机
    const camStart = camera.quaternion.clone()
    camera.lookAt(pos.lookAt)
    const camEnd = camera.quaternion.clone()
    camera.quaternion.copy(camStart)
    camera.quaternion.slerp(camEnd, this.progress())
  },
  onComplete() {
    //重置orbitControls
    controls.target.copy(pos.lookAt)
    controls.update()
    controls.enabled = true
  }
})

总结

通过一个3D导航的小案例,我们学习了3D web优化的一种手段:材质烘焙,后面行歌会挖掘更多的有趣案例分享给大家!

演示地址:
https://www.xinapp.net/case/room/

关注