1. 安装three.js(我使用yarn)
yarn add -d three
2. 函数封装
import * as THREE from 'three'
export default function () {
const SEPARATION = 100, AMOUNTX = 50, AMOUNTY = 50;
let camera, scene, renderer;
let particles, count = 0;
let mouseX = 0, mouseY = 0;
let windowHalfX = window.innerWidth / 2;
let windowHalfY = window.innerHeight / 1;
// onMounted(() => {
// init();
// animate();
// })
function init(node: Element) {
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 1000;
scene = new THREE.Scene();
const numParticles = AMOUNTX * AMOUNTY;
const positions = new Float32Array(numParticles * 3);
const scales = new Float32Array(numParticles);
let i = 0, j = 0;
for (let ix = 0; ix < AMOUNTX; ix++) {
for (let iy = 0; iy < AMOUNTY; iy++) {
positions[i] = ix * SEPARATION - ((AMOUNTX * SEPARATION) / 2); // x
positions[i + 1] = 0; // y
positions[i + 2] = iy * SEPARATION - ((AMOUNTY * SEPARATION) / 2); // z
scales[j] = 1;
i += 3;
j++;
}
}
// GLSL代码
const vertexshader = `
attribute float scale;
void main() {
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_PointSize = scale * ( 150.0 / - mvPosition.z );
gl_Position = projectionMatrix * mvPosition;
}`
const fragmentShader = `
uniform vec3 color;
void main() {
if ( length( gl_PointCoord - vec2( 0.5, 0.5 ) ) > 0.475 ) discard;
gl_FragColor = vec4( color, 1.0 );
}`
const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.setAttribute('scale', new THREE.BufferAttribute(scales, 1));
const material = new THREE.ShaderMaterial({
uniforms: {
color: {value: new THREE.Color(0xE6EAEA)}
},
vertexShader: vertexshader,
fragmentShader: fragmentShader
});
particles = new THREE.Points(geometry, material);
scene.add(particles);
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setClearColor(0xffffff, 1);
renderer.setSize(window.innerWidth, window.innerHeight);
node.appendChild(renderer.domElement)
node.style.touchAction = 'none';
node.addEventListener('pointermove', onPointerMove, false);
window.addEventListener('resize', onWindowResize, false);
animate();
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function onPointerMove(event) {
if (event.isPrimary === false) return;
mouseX = event.clientX - windowHalfX;
mouseY = event.clientY - windowHalfY;
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
camera.position.x += (mouseX - camera.position.x) * .05;
camera.position.y += (-mouseY - camera.position.y) * .05;
camera.lookAt(scene.position);
const positions = particles.geometry.attributes.position.array;
const scales = particles.geometry.attributes.scale.array;
let i = 0, j = 0;
for (let ix = 0; ix < AMOUNTX; ix++) {
for (let iy = 0; iy < AMOUNTY; iy++) {
positions[i + 1] = (Math.sin((ix + count) * 0.3) * 50) +
(Math.sin((iy + count) * 0.5) * 50);
scales[j] = (Math.sin((ix + count) * 0.3) + 1) * 20 +
(Math.sin((iy + count) * 0.5) + 1) * 20;
i += 3;
j++;
}
}
particles.geometry.attributes.position.needsUpdate = true;
particles.geometry.attributes.scale.needsUpdate = true;
renderer.render(scene, camera);
count += 0.08;
}
return {
init
}
}
3. template模板使用函数
<template>
<div>
<div ref="webgl" id="webgl" class="webgl">
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import usePointStore from '@/hook/three/PointWaves'
// 生成区域
const webgl = ref()
// 粒子系统
const usePoint = usePointStore()
onMounted(() => {
// 初始化一下
usePoint.init(webgl.value)
})
</script>
<style scoped>
.webgl {
position: absolute;
bottom: 0;
width: 100%;
}
最后
- 有什么问题优先思考、各种尝试、问百度,然后询问AI
- 没有AI的话使用这个吧:rednutmeg.top/aigc_web/pr…
- 有什么问题都可以加群反馈给我