最近有一个项目需要搭建一个在线的3D全景VR画展,经过几天的摸索走通了整个流程,完成了一个简单的DEMO原型,我会将这几天的踩过的坑总结成一个教程系列分享给大家,希望你也会从中学到东西,少走一些弯路。

全景VR画廊

技术和工具选择

首先是webGL框架的选择,threejs免费开源,有活跃的社区和大量的学习案例,自然是我们不二的选择。其次是建模工具的选择,同样是开源免费的blender,相比其他的建模工具更小巧更轻量,上手更容易,在B站和油管上都可以找到免费的视频教程,最终我们锁定threejs+blender这对最佳CP。

用Blender创建画展模型

因为建模不是我们教程的重点,这里也不会用到复杂的模型,有兴趣的同学可以在B站和油管上找免费的bleneder教程来学习,由于最终要将模型导出到threejs中使用,这里简单介绍下blender建模中需要注意的地方,有不清楚的地方可以给行歌留言。

将相同类型的元素放在各自的集合中,方便模型的管理和导出,比如我们可以将不需要导出的摄像机和灯光等元素放在一个分组中,在导出时将该分组设置为不可选。

02

元素命名上建议使用类型+数字序列的方式,比如这里的画展图片,后面我们可以在threejs中方便的遍历这些名称带数字的元素,动态地给它们加载材质图片。

03

模型导出我们选择gltf二进制模式;只导出选择的元素;不导出素材,因为我们会在threejs中动态设置材质和贴图;因为我们的模型比较简单,所以这里选择不压缩模型,如果你的模型比较复杂需要压缩,在threejs中需要使用draco插件来加载压缩后的模型。

导出的模型大概100多k,如果采用压缩模式,导出的模型会下降到30几k,大家可以根据自己的情况自行选择,我们的模型比较简单,这里就偷个懒。

在threejs中渲染模型

首先我们要用gltfLoader来加载之前导出的glb文件,然后循环遍历模型并根据元素名设置不同元素的材质和贴图。

const loader = new THREE.GLTFLoader()
  loader.load(
    'model/gallery.glb',
    gltf => {
      gltf.scene.traverse(child => {
        switch(child.name) {
          case 'walls':
            initWalls(child)
            break
          case 'stairs':
            initStairs(child)
            break
        }
        //设置展画边框贴图
        if(child.name.includes('paint')) {
          initFrames(child)
        }
        //设置展画图片贴图
        if(child.name.includes('draw')) {
          initDraws(child)
        }
      })
      scene.add(gltf.scene)
    }
  )

修正材质贴图错误

在设置展画贴图后,我发现展画的颜色不对,材质的也是颠倒的。

05

经过一番踩坑,我们要这样设置材质的encoding和flipY值才能得到正确的结果。

texture.encoding = THREE.sRGBEncoding
texture.flipY = false

第一人称摄像机跟踪

为了实现第一人称摄像机效果,我首先用一个box代表被跟踪对象,让场景中的摄像机始终同步跟踪这个box中的一个坐标,我们只需要根据键盘事件来移动旋转box就能达到第一人称摄像机的效果。

//用插值函数来过渡摄像机
camera.position.lerp(
  activeCamera.getWorldPosition(
    new THREE.Vector3()
  ), 
  0.05
)
const pos = player.position.clone()
camera.lookAt(pos)

总结

目前为止我们已经完成了搭建3D画展的第一步,我们接下来会加入简单的碰撞检测功能,并学习如何在手机等移动设备上的添加导航功能。

源码地址:https://github.com/imokya/3dvr-gallery

关注