three.js realizes panoramic exhibition hall roaming (actual project)

As we all know, there are many different ways to achieve panorama. Today we mainly introduce the use of three.js to achieve the effect. Three.js is a three-dimensional engine running based on the native WebGL package. Among all WebGL engines, Three.js is the one with the most domestic literature and the most used The most extensive 3D engine.

1: Initialization settings

All initialization operations are implemented in mounted. Why not use created here? Because we need to operate dom,

And created cannot obtain dom.

?
    //Create scene
    const scene = new THREE.Scene() //Initialize scene
    var ambient = new THREE.AmbientLight(0xfffffff, 2) //Add light source color and light intensity
    scene.add(ambient) //Add light source to the scene

First of all, for the initial scene, a light source must be added. However, there are also some special materials that can emit light without adding a light source. Of course, this is a rare situation. No light source will cause a black screen.

?
    //Create camera
    var width = 800 //Window width
    var height = 800 //Window height
    const camera = new THREE.PerspectiveCamera(90, width / height, 1, 1000) //Use perspective camera
    camera.position.set(30, 0, 10) //Set camera position
    camera.lookAt(new THREE.Vector3(30, 0, 0)) // Camera looking direction

?

Here we use a perspective camera, which is the closest to a natural view and conforms to the rules of near and far.

 // Create renderer
    width = window.innerWidth //Window width window.innerWidth browser window visual area width (excluding browser console, menu bar, toolbar) including scroll bar
    height = window.innerHeight //Window height window.innerHeight
    const renderer = new THREE.WebGLRenderer() //Create renderer
    renderer.setSize(width, height) //Set the renderer size
    renderer.setPixelRatio(window.devicePixelRatio)
    this.$refs.container.appendChild(renderer.domElement) //Pass this.$ref

The renderer is equivalent to the canvas. All display effects need to be displayed on the canvas. We need to add a box with a ref of container in the html. Of course, you can also name it yourself.

 // Create controller
    const controls = new OrbitControls(camera, renderer.domElement)
    controls.enableDamping = true
    // zoom limit
    controls.maxDistance = 12
    controls.target.set(30, 0, 0)

?

Here we need to impose a zoom limit on the controller, because the principle of panorama is to create a cube or a sphere, and then let the perspective be inside the box, so we cannot expose the outer box to the user.

2: Add model

Next is the most critical step. We need to create a sphere or cube. Different materials require different panoramas. A sphere only requires a complete panoramic photo to achieve a panoramic view. The disadvantage is that it may be possible from certain viewing angles. The effect is not very good, and the cube requires six photos in different directions. This is too difficult for beginners and often cannot achieve seamless fit. However, it avoids the shortcomings of the sphere and the display effect is very good.

 // Add a sphere
    const geometry = new THREE.SphereGeometry(130, 256, 256)
    var textureLoader = new THREE.TextureLoader() //Create texture map
    var img = textureLoader.load(require('../../../public/image/vrTest3.jpg'))
    const material = new THREE.MeshLambertMaterial({
      map: img, //Set the color map attribute value
      side: THREE.DoubleSide //Double-sided rendering
     })
    const cube = new THREE.Mesh(geometry, material)
    scene.add(cube)

Finally, the rendering scene

 // Render scene
    const animate = function () {
      requestAnimationFrame(animate)
      renderer.render(scene, camera)
    }
    animate()

You can also add animation here to make the scene move by itself.

After completing the appeal, you should have completed a most basic VR panorama.

Here I add a 3D model in it, and you can also expand it based on your own business.

3: Scene roaming

Scene roaming is divided into same scene roaming and different scene roaming

1: Roaming in different scenes

Since they are different scenes, one scene is an object. Here we need to create multiple spheres in a loop. Remember that scenes cannot overlap. The principle is mainly to change the position of the camera and the position of the control center when switching, because we are At the beginning, there were zoom restrictions so that users could not find them. During testing, the restrictions can be commented out for debugging.

<template>
  <div class="home">
    <div ref="container"></div>
    <!-- Scene switching point -->
    <div class="switch">
      <span
        class="buttons"
        v-for="(room, index) in rooms"
        :key="index"
        @click="handleSwitchButtonClick(room.key)"
        v-show="room.key !== currentRoom"
      >
        <b class="text">{<!-- -->{ room.name }}</b>
        <i class="icon"></i>
      </span>
    </div>
  </div>
</template>

Parallel to the canvas, fix the switching box to the right side of the panorama. The index of the box needs to be greater than the canvas.

For the creation and addition of multiple scenes, you can refer to the above code and create them in a loop. I will not elaborate here.

 // Click to switch scenes
    async handleSwitchButtonClick(key) {
      if (key == 'internet-hall') {
        this.cameras.position.set(280, 0, 10)
        this.cameras.lookAt(new THREE.Vector3(280, 0, 0))
        this.controles.target.set(280, 0, 0)
        this.currentRoom = 'internet-hall'
      } else if (key == 'insect-hall') {
        this.cameras.position.set(0, 0, 10)
        this.cameras.lookAt(new THREE.Vector3(0, 0, 0))
        this.controles.target.set(0, 0, 0)
        this.currentRoom = 'insect-hall'
      } else if (key == 'agriculture-hall') {
        this.cameras.position.set(580, 0, 10)
        this.cameras.lookAt(new THREE.Vector3(580, 0, 0))
        this.controles.target.set(580, 0, 0)
        this.currentRoom = 'agriculture-hall'
      }
}

You can use my method to switch scenes when there are not many scenes. Of course, you can also put the data in data and use loops to switch different scenes.

2: Roaming in the same scene

For roaming in the same scene, I used mobile to achieve

 window.addEventListener(
      'keydown',
      (e) => {
        var ev = e || window.event
        switch (ev.keyCode) {
          case 87:
            camera.position.x + = 2
            controls.target.x + = 2
            break
          case 83:
            camera.position.x -= 2
            controls.target.x -= 2
            break
          case 65:
            camera.position.z -= 2
            controls.target.z -= 2
            break
          case 68:
            camera.position.z + = 2
            controls.target.z + = 2
            break
          default:
            break
        }
      },
      false
    )

If you have any questions, please leave them in the comments.