文章数量
36
访客量
4952
访问量
9817

threejs使用Tweenjs结合SpotLight实现动画聚光灯效果

阅读量:877
更新时间:2023-02-12 10:38:15

效果预览:效果预览
源码下载:关注公众号【RMRF】,回复【three6】可获取源码

一、安装

npm install three

二、App.vue

<template>
  <div class="index">
    <div id="container"></div>
  </div>
</template>

<script>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import TWEEN from '@tweenjs/tween.js'
export default {
  data() {
    return {
      scene: null,
      camera: null,
      renderer: null,
      composer: null,
      light: null,
      lightHelper: null,
      light1: null,
      lightHelper1: null,
      light2: null,
      lightHelper2: null
    }
  },
  mounted() {
    this.init()
  },
  methods: {
    init() {
      const el = document.getElementById('container')
      this.initScene()
      this.initCamera()
      this.initRenderer(el)
      this.initCube()
      this.initPlane()
      this.initOrbitControls()
      this.initSpotLight()
      this.render()
      this.animate()
      window.addEventListener('resize', this.onWindowResize)
    },
    initScene() {
      this.scene = new THREE.Scene()
    },
    initCamera() {
      this.camera = new THREE.PerspectiveCamera(
        35,
        window.innerWidth / window.innerHeight,
        1,
        2000
      )
      this.camera.position.set(46, 22, -21)
    },
    initRenderer(el) {
      this.renderer = new THREE.WebGLRenderer({
        antialias: true
      })
      this.renderer.setPixelRatio(window.devicePixelRatio)
      this.renderer.setSize(window.innerWidth, window.innerHeight)
      this.renderer.shadowMap.enabled = true
      el.appendChild(this.renderer.domElement)
    },
    initOrbitControls() {
      let controls = new OrbitControls(this.camera, this.renderer.domElement)
      controls.target.set(0, 7, 0)
      controls.maxPolarAngle = Math.PI / 2
      controls.update()
    },
    render() {
      TWEEN.update()
      this.renderer.render(this.scene, this.camera)
      if (this.lightHelper) {
        this.lightHelper.update()
      }
      if (this.lightHelper1) {
        this.lightHelper1.update()
      }
      if (this.lightHelper2) {
        this.lightHelper2.update()
      }
      requestAnimationFrame(this.render)
    },
    onWindowResize() {
      this.camera.aspect = window.innerWidth / window.innerHeight
      this.camera.updateProjectionMatrix()
      this.renderer.setSize(window.innerWidth, window.innerHeight)
    },
    initCube() {
      const geometry = new THREE.BoxGeometry(3, 3, 3)
      const material = new THREE.MeshPhongMaterial()
      let cube = new THREE.Mesh(geometry, material)
      cube.castShadow = true
      cube.receiveShadow = true
      this.scene.add(cube)
    },
    initPlane() {
      let geometry = new THREE.PlaneGeometry(50, 50)
      let material = new THREE.MeshPhongMaterial({
        color: 0xffffff,
        dithering: true
      })
      let planeMesh = new THREE.Mesh(geometry, material)
      planeMesh.position.set(0, -3, 0)
      planeMesh.receiveShadow = true
      planeMesh.rotation.x = -Math.PI * 0.5
      this.scene.add(planeMesh)
    },
    initSpotLight() {
      const light1 = this.getSpotLight(0xffffff)
      this.scene.add(light1)
      this.light1 = light1
      this.lightHelper1 = new THREE.SpotLightHelper(light1)
      this.scene.add(this.lightHelper1)

      const light2 = this.getSpotLight(0xffff00)
      this.scene.add(light2)
      this.light2 = light2
      this.lightHelper2 = new THREE.SpotLightHelper(light2)
      this.scene.add(this.lightHelper2)
      const anbientLight = new THREE.AmbientLight(0x404040)
      this.scene.add(anbientLight)
    },
    getSpotLight(color) {
      const light = new THREE.SpotLight(color, 1)
      light.castShadow = true
      light.angle = 0.4
      light.penumbra = 0.2
      light.decay = 2
      light.distance = 50
      light.position.set(0, 20, 13)
      return light
    },
    lightTween(light) {
      new TWEEN.Tween(light).to({
        angle: (Math.random() * 0.7) + 0.1,
        penumbra: Math.random() + 1
      }, Math.random() * 3000 + 2000)
        .easing(TWEEN.Easing.Quadratic.Out).start()

      new TWEEN.Tween(light.position).to({
        x: (Math.random() * 30) - 15,
        y: (Math.random() * 10) + 15,
        z: (Math.random() * 30) - 15
      }, Math.random() * 3000 + 2000)
        .easing(TWEEN.Easing.Quadratic.Out).start()
    },
    animate() {
      this.lightTween(this.light1)
      this.lightTween(this.light2)
      setTimeout(this.animate, 5000)
    }
  }
}
</script>

<style>

</style>