Vue中用three.js实现网站页面粒子特效
·
第一步:安装插件
/**
* 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>
以上完成即可运行,
更多推荐
已为社区贡献1条内容
所有评论(0)