Bootstrap

VUE3+ThreeJs实现3D全景场景,可自由旋转视角

一、介绍 😜 😜

three.js是一个用于在Web上创建三维图形的JavaScript库。它可以用于创建各种类型的三维场景,包括游戏、虚拟现实、建筑和产品可视化等。three.js提供了许多功能和特性,包括3D渲染、光照、材质、几何形状、动画、交互和相机控制等。使用three.js,开发人员可以轻松地创建复杂的三维场景,使用户可以与这些场景进行交互,从而提供更好的用户体验。

文章中使用到的案例图片都来源于:Humus - Textures

这个网站里面有很多免费的资源。每个资源里面都提供6个不同方位的图片。我们只需要通过threejs稍微处理一下,就能实现3d场景了。

demo演示 😝 😝

二、three.js的基本使用方法 😁 😁

想要使用three.js显示内容的话,我们需要三样东西:场景、相机和渲染器,这样我们就可以使用相机渲染场景。

import * as THREE from 'three';

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

三、源码 😎 😎

安装依赖,选择其中一种安装即可。

# npm
npm install three

# yarn
yarn add three
<template>
  <div v-loading="loading" style="position: relative">
    <div style="position:absolute;left:0;top:0;opacity:0.5;height: 35px;width: 100%;z-index: 9999;display: flex;justify-content: flex-start;align-items: center;padding: 0 20px">
      <el-button size="mini" @click="changeName('indoor')">室内</el-button>
    </div>
    <div ref="environment"></div>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref, onMounted } from 'vue'
import {
  Scene,
  PerspectiveCamera,
  WebGL1Renderer,
  AmbientLight,
  CubeTextureLoader,
  Mesh,
  PlaneGeometry,
  MeshLambertMaterial,
} from 'three'
import {OrbitControls} from "three/examples/jsm/controls/OrbitControls";

export default defineComponent({
  components: {},
  setup() {

    const loading = ref(true)

    let scene: any = new Scene()

    const environment = ref<HTMLDivElement>()

    /**
     * 默认场景
     */
    const nameDefault = ref<string>('indoor')

    /**
     * 切换场景事件
     */
    const changeName = (environmentName: string) => {
      if (nameDefault.value === environmentName) {
        return
      }
      if (environmentName === '') {
        environmentName = nameDefault.value
      }
      loading.value = true
      scene.background = new CubeTextureLoader()
          .setPath(`/ambient/${environmentName}/`)
          .load(['posx.jpg', 'negx.jpg', 'posy.jpg', 'negy.jpg', 'posz.jpg', 'negz.jpg'], function () {
            loading.value = false
            nameDefault.value = environmentName
          })
    }

    /**
     * 初始化
     */
    const init = () => {
      loading.value = true
      /**
       * 相机 PerspectiveCamera(视野大小, 视图的长宽比, 近景, 远景)
       */
      const camera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000)
      camera.position.set(0, 0, 300)
      camera.lookAt(scene.position)

      /**
       * antialias消除锯齿
       */
      const renderer = new WebGL1Renderer({antialias: true})
      // 背景颜色
      renderer.setClearColor(0xffffff)
      // 设置设备像素比
      renderer.setPixelRatio(window.devicePixelRatio)
      renderer.setSize(window.innerWidth, window.innerHeight)

      /**
       * 添加环境灯光
       */
      scene.add(new AmbientLight(0xFFFFFF, 2))

      environment.value?.appendChild(renderer.domElement)

      const planeGeometry = new PlaneGeometry(60, 20)
      // 材质 MeshBasicMaterial和MeshLambertMaterial的区别 MeshLambertMaterial它不会自己发光,而是需要一个光源照射
      const planeMaterial = new MeshLambertMaterial({color: 0xcccccc})
      // 用来定位音源的网格模型
      const audioMesh = new Mesh(planeGeometry, planeMaterial);
      // 设置网格模型的位置,相当于设置音源的位置
      audioMesh.position.set(0, 0, 300);
      scene.add(audioMesh);

      window.addEventListener('resize', () => onWindowResize())

      /**
       * 轨道控制器 也就是鼠标转动等操作
       */
      let orbitControls = new OrbitControls(camera, renderer.domElement)
      orbitControls.autoRotateSpeed = 1
      orbitControls.minDistance = 50

      renderScene()
      function renderScene(){
        requestAnimationFrame(renderScene)
        renderer.render(scene, camera)
      }

      const onWindowResize = () => {
        renderer.setSize(window.innerWidth, window.innerHeight)
        camera.aspect = window.innerWidth / window.innerHeight
        camera.updateProjectionMatrix()
      }
    }

    onMounted(() => {
      init()
      changeName('')
    })

    return {
      environment,
      changeName,
      loading
    }
  },
})
</script>

安装好依赖,复制源码,下载好相对应的图片就能使用。这里只是一个简单的demo。纯属学习记录。

我是Etc.End。如果文章对你有所帮助,能否帮我点个免费的赞和收藏😍。

👇 👇 👇 👇 👇 👇 👇 👇 👇 👇 👇 👇

;