THREE.js 下雪效果
阿新 • • 發佈:2022-05-11
snow.js
import * as THREE from "three"; class Snow { #time = 0 #textureLoader = new THREE.TextureLoader() constructor(num = 0, range = 0, texture = '') { this.num = num this.range = range this.particle = null this.texture = texture this.texturesMaps = [] this.position = null this.gen() } gen() { const {num, range, texture,} = this const geometry = new THREE.BufferGeometry() const material = new THREE.PointsMaterial({ size: 6, transparent: true, opacity: .6, depthWrite: false, vertexColors: true, map: this.#textureLoader.load(texture), blending: THREE.AdditiveBlending // 將黑色雪花與背景色融合 }) const position = [] // 每個粒子的位置 const colors = [] for (let x = 0; x < num; x++) { // 採用HSL顏色模式使得雪花明暗度變化 const color = new THREE.Color() const asHSL = {h: 0, s: 0, l: 0} color.getHSL(asHSL) color.setHSL(asHSL.h, asHSL.s, asHSL.l * Math.random()) colors.push(color.r, color.g, color.b) // 生成隨機點座標 position.push( THREE.MathUtils.randFloatSpread(range * 2), THREE.MathUtils.randFloatSpread(range * 2), THREE.MathUtils.randFloatSpread(range * 2) ) } this.position = new THREE.Float32BufferAttribute(position, 3) geometry.setAttribute('position', this.position) geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)) this.particle = new THREE.Points(geometry, material) } snowing(speed = 0, fps = 0) { this.#time += 1 if (fps > 0) { if (this.#time < fps * 60) return this.#time = 0 } const {position, range} = this for (let i = 0; i < position.count; i++) { let pos_x = position.getX(i) let pos_y = position.getY(i) let pos_z = position.getZ(i) pos_x -= speed pos_y -= speed pos_z -= speed if (pos_x < -range) pos_x = range if (pos_y < -range) pos_y = range if (pos_z < -range) pos_z = range position.setX(i, pos_x) position.setY(i, pos_y) position.setZ(i, pos_z) } // 更新 position position.needsUpdate = true } } export default Snow
index.js
import * as THREE from 'three' import {OrbitControls} from "three/examples/jsm/controls/OrbitControls" import Snow from "./snow"; import snowImg from "@/assets/textures/particles/snowflake1.png"; const {innerWidth: WIDTH, innerHeight: HEIGHT} = window const scene = new THREE.Scene() const camera = new THREE.PerspectiveCamera(45, WIDTH / HEIGHT, .1, 1000) camera.position.set(0, 0, 160) camera.lookAt(scene.position) const ambientLight = new THREE.AmbientLight(0x666666) scene.add(ambientLight) const spotLight = new THREE.SpotLight(0xffffff) spotLight.castShadow = true spotLight.position.set(-50, 80, 50) scene.add(spotLight) const snow = new Snow(10000, 100, snowImg) scene.add(snow.particle) const renderer = new THREE.WebGLRenderer({antialias: true}) renderer.setSize(WIDTH, HEIGHT) renderer.shadowMap.enabled = true document.body.appendChild(renderer.domElement) new OrbitControls(camera, renderer.domElement) const render = () => { snow.snowing(.3, .03) requestAnimationFrame(render) renderer.render(scene, camera) } render()