Three.js - 添加天空盒(十八)

4,691 阅读1分钟

「这是我参与2022首次更文挑战的第18天,活动详情查看:2022首次更文挑战

天空盒

  • 在3D场景中,为了增强场景表现力,我们通常会为场景添加天空盒。就是在整个场景的上方绘制天空这一类图片。
  • 最简单的做法是,制作一个很大的立方体为6个面添加纹理,这里要注意我们渲染的是内部。纹理是特殊处理了的能组合成一个整体。当然还有其他的方式比如创建球体或半圆的穹顶等。

创建

  • 基础代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>学习</title>
  </head>
  <body>
    <canvas id="c2d" class="c2d" width="1000" height="500"></canvas>
    <script type="module">
      import * as THREE from './file/three.js-dev/build/three.module.js'
      import { OrbitControls } from './file/three.js-dev/examples/jsm/controls/OrbitControls.js'

      const canvas = document.querySelector('#c2d')
      // 渲染器
      const renderer = new THREE.WebGLRenderer({ canvas })

      const fov = 40 // 视野范围
      const aspect = 2 // 相机默认值 画布的宽高比
      const near = 0.1 // 近平面
      const far = 10000 // 远平面
      // 透视投影相机
      const camera = new THREE.PerspectiveCamera(fov, aspect, near, far)
      camera.position.set(10, 3, 0)
      camera.lookAt(0, 0, 0)
      // 控制相机
      const controls = new OrbitControls(camera, canvas)
      controls.update()

      // 场景
      const scene = new THREE.Scene()

      // 渲染
      function render() {
        renderer.render(scene, camera)
        requestAnimationFrame(render)
      }
      requestAnimationFrame(render)
    </script>
  </body>
</html>
  • 添加几何体,给每个面设置纹理。
  • 需要注意材质要设置THREE.BackSide渲染内部,相机的远平面必须大于盒子的长度。directions[]数组中的图片也是有序的。
      {
        var directions = [
          './file/18/pos-x.jpg',
          './file/18/neg-x.jpg',
          './file/18/pos-y.jpg',
          './file/18/neg-y.jpg',
          './file/18/pos-z.jpg',
          './file/18/neg-z.jpg'
        ] // 获取对象

        const loader = new THREE.TextureLoader()
        // 创建盒子,并设置盒子的大小为( 5000, 5000, 5000 )
        const skyGeometry = new THREE.BoxGeometry(5000, 5000, 5000)
        // 设置盒子材质
        const materialArray = []
        for (let i = 0; i < 6; i++)
          materialArray.push(
            new THREE.MeshBasicMaterial({
              map: loader.load(directions[i]), // 将图片纹理贴上
              side: THREE.BackSide // 镜像翻转
            })
          )
        // 创建一个完整的天空盒,填入几何模型和材质的参数
        const skyBox = new THREE.Mesh(skyGeometry, materialArray) 
        scene.add(skyBox) // 在场景中加入天空盒
      }

1.gif

  • three.js提供了一种特殊的纹理CubeTextureLoader,可以模拟正方形的6个边。只需要很少的代码就能实现上面的效果。
      {
        const loader = new THREE.CubeTextureLoader()
        const texture = loader.load([
          './file/18/pos-x.jpg',
          './file/18//neg-x.jpg',
          './file/18//pos-y.jpg',
          './file/18//neg-y.jpg',
          './file/18//pos-z.jpg',
          './file/18//neg-z.jpg'
        ])
        scene.background = texture
      }

1.gif

  • three.js中除几张图组合的方式,还可以使用360度的全景图来设置天空。
  • 使用WebGLCubeRenderTarget渲染器的.fromEquirectangularTexture,把全景图转换为立方体贴图格式。
 {
    const loader = new THREE.TextureLoader()
    const texture = loader.load('./file/18/2.webp', () => {
      const rt = new THREE.WebGLCubeRenderTarget(texture.image.height)
      rt.fromEquirectangularTexture(renderer, texture)
      scene.background = rt.texture
    })
  }

1.gif

  • 天空盒子在3D场景中,是最常见的一种增强效果的方式。使用那种方式去实现,就需要根据需求来判断什么方式最简单了。