第一步:安装插件
/**
 * npm i three@0.145.0
 * npm i three-tween@1.0.0
 */
第二步:

 在项目public文件夹内引入 格式为 .glb 格式的模型和一张圆点的图片,上图示例

 第三步:创建vue组件
<template>
  <div class="three" ref="three"></div>
</template>
<script>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import TWEEN from 'three-tween'
const bufArrays = []
// 当前第几个模型
let current = 0
// 最大的模型长度
const maxLength = 10440
// 模型数量
const modelNum = 3

export default {
  mounted() {
    this._initBase()
  },
  methods: {
    _initBase() {
      // 初始化场景,设置背景色
      this.scene = new THREE.Scene()
      this.scene.background = this.backgroundTexture()

      // 初始化一个透视相机,并且设置相机位置
      this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 80)
      this.camera.position.set(0, 0, 5)

      // 初始化一个渲染器,打开抗锯齿,设置渲染器大小
      this.renderer = new THREE.WebGLRenderer({ antialias: true })
      this.renderer.setPixelRatio(window.devicePixelRatio)
      this.renderer.setSize(window.innerWidth, window.innerHeight)

      // threejs 生命钩子
      const manager = new THREE.LoadingManager()
      manager.onStart = (url, itemsLoaded, itemsTotal) => {
        console.log('onstart');
      }
      manager.onLoad = () => {
        this.transition()

        for (let i = 0; i < bufArrays.length; i++) {
          if(maxLength < bufArrays[i].length) {
            maxLength = bufArrays[i].length;
          }
        }
        console.log('onload', bufArrays[0].length);
      }
      manager.onError = (url) => {
        console.log(url)
      }

      // 添加处理建模的模型
      // child.geometry.scale(0.5, 0.5, 0.5) 可控制模型缩放大小
      // child.geometry.translate(0, 0.5, 0) 设置模型位置
      const gltfLoader = new GLTFLoader(manager)
      gltfLoader.load('/she.glb', gltf => {
        gltf.scene.traverse(child => {
          if(child.isMesh) {
            child.geometry.translate(0, 0.5, 0)
            child.geometry.scale(0.5, 0.5, 0.5)
            const { array } = child.geometry.attributes.position
            bufArrays.push(array)
          }
        })
        // this.scene.add(gltf.scene)
      })
      gltfLoader.load('/yuan2.glb', gltf => {
        gltf.scene.traverse(child => {
          if(child.isMesh) {
            // child.geometry.scale(0.5, 0.5, 0.5)
            const { array } = child.geometry.attributes.position
            bufArrays.push(array)
          }
        })
      })
      gltfLoader.load('/123.glb', gltf => {
        gltf.scene.traverse(child => {
          if(child.isMesh) {
            child.geometry.scale(0.5, 0.5, 0.5)
            const { array } = child.geometry.attributes.position
            bufArrays.push(array)
          }
        })
      })


      // 通过模型数据,处理成粒子需要的数据格式,并添加动画
      this.geometry = new THREE.BufferGeometry()
      this.geometry.tween = []
      const vertices = []
      // 10440是最大模型的二进制数组 长度
      for (let i = 0; i < maxLength; i++) {
        const position = THREE.MathUtils.randFloat(-4, 4)
        this.geometry.tween.push(new TWEEN.Tween({ position }).easing(TWEEN.Easing.Exponential.In))
        vertices.push(position)
      }
      this.geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(vertices), 3))

      // 生成粒子,并添加到场景中
      this.points = new THREE.Points(this.geometry, new THREE.PointsMaterial({
        size: 0.05,
        map: new THREE.TextureLoader().load('/gradient.png'),
        alphaTest: 0.1,
        opacity: 0.5,
        transparent: true,
        depthTest: true
      }))
      this.scene.add(this.points)

      // 设置一个材料材质, 不受关照影响的材质,生成几何体,添加到场景里
      // const geometry = new THREE.BoxGeometry(1, 1, 1)
      // const material = new THREE.MeshBasicMaterial({ color: 0xff0000 })
      // const cube = new THREE.Mesh(geometry, material)
      // this.scene.add(cube)

      this.controls = new OrbitControls(this.camera, this.renderer.domElement)

      // 监听窗口大小,变化
      window.addEventListener('resize', this.onWindowResize, false)
      this.$refs.three.appendChild(this.renderer.domElement)

      // 渲染效果
      this.render()
    },

    // 切换模型的函数
    transition() {
      const self = this
      for (let i = 0, j = 0; i < maxLength; i++, j++) {
        const item = this.geometry.tween[i]
        if(j >= bufArrays[current].length) {
          j = 0
        }
        item.to({ position: bufArrays[current][j] }, THREE.MathUtils.randFloat(1000, 3000)).onUpdate(function() {
          self.geometry.attributes.position.array[i] = this.position
          self.geometry.attributes.position.needsUpdate = true
        }).start()
      }

      // 递归调用,3是模型的数量
      setTimeout(() => this.transition(), 4000);
      current = (current + 1) % modelNum
    },

    // 设置场景背景色, 渐变色,canvas
    backgroundTexture() {
      const canvas = document.createElement('canvas')
      canvas.width = window.innerWidth
      canvas.height = window.innerHeight
      const ctx = canvas.getContext('2d')
      const gradient = ctx.createLinearGradient(0, 0, window.innerWidth, 0)
      gradient.addColorStop(0, '#4e22b7')
      gradient.addColorStop(1, '#3292ff')
      ctx.fillStyle = gradient
      ctx.fillRect(0, 0, window.innerWidth, window.innerHeight)
      const canvasTexture = new THREE.CanvasTexture(canvas)
      return canvasTexture
    },
    onWindowResize() {
      this.renderer.setSize(window.innerWidth, window.innerHeight)
      this.camera.aspect = window.innerWidth / window.innerHeight
      this.camera.updateProjectionMatrix()
    },
    render() {
      // 设置点的旋转速度
      this.points.rotation.x += 0.0005
      this.points.rotation.y += 0.0007
      this.points.rotation.z += 0.0003
      // 更新动画
      TWEEN.update()
      this.renderer.render(this.scene, this.camera)
      requestAnimationFrame(this.render)
    }
  }
}
</script>
<style lang="scss" scoped>
.three {
  pointer-events: none;
}
</style>

以上完成即可运行,

 

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐