<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>粒子特效</title>
<style>
body {
margin: 0;
overflow: hidden;
background: #000;
}
canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas id="universeCanvas"></canvas>
<script type="module">
import * as THREE from "https://cdn.skypack.dev/three@0.136.0";
import { OrbitControls } from "https://cdn.skypack.dev/three@0.136.0/examples/jsm/controls/OrbitControls";
import { FontLoader } from "https://cdn.skypack.dev/three@0.136.0/examples/jsm/loaders/FontLoader";
import { TextGeometry } from "https://cdn.skypack.dev/three@0.136.0/examples/jsm/geometries/TextGeometry";
// 创建宇宙星辰场景
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
const renderer = new THREE.WebGLRenderer({ canvas: document.getElementById("universeCanvas") });
renderer.setSize(window.innerWidth, window.innerHeight);
camera.position.set(0, 4, 21);
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
const gu = { time: { value: 0 } };
const sizes = [];
const shift = [];
const pushShift = () => {
shift.push(
Math.random() * Math.PI,
Math.random() * Math.PI * 2,
(Math.random() * 0.9 + 0.1) * Math.PI * 0.1,
Math.random() * 0.9 + 0.1
);
};
const pts = new Array(50000).fill().map(() => {
sizes.push(Math.random() * 1.5 + 0.5);
pushShift();
return new THREE.Vector3().randomDirection().multiplyScalar(Math.random() * 0.5 + 9.5);
});
for (let i = 0; i < 100000; i++) {
const r = 10, R = 40;
const rand = Math.pow(Math.random(), 1.5);
const radius = Math.sqrt(R * R * rand + (1 - rand) * r * r);
pts.push(new THREE.Vector3().setFromCylindricalCoords(radius, Math.random() * 2 * Math.PI, (Math.random() - 0.5) * 2));
sizes.push(Math.random() * 1.5 + 0.5);
pushShift();
}
const g = new THREE.BufferGeometry().setFromPoints(pts);
g.setAttribute("sizes", new THREE.Float32BufferAttribute(sizes, 1));
g.setAttribute("shift", new THREE.Float32BufferAttribute(shift, 4));
const m = new THREE.PointsMaterial({
size: 0.125,
transparent: true,
depthTest: false,
blending: THREE.AdditiveBlending,
onBeforeCompile: (shader) => {
shader.uniforms.time = gu.time;
shader.vertexShader = `
uniform float time;
attribute float sizes;
attribute vec4 shift;
varying vec3 vColor;
${shader.vertexShader}
`.replace(`gl_PointSize = size;`, `gl_PointSize = size * sizes;`)
.replace(`#include <color_vertex>`,
`#include <color_vertex>
float d = length(abs(position)/vec3(40.,10.,40));
d=clamp(d,0.,1.);
vColor = mix(vec3(227.,155.,0.),vec3(100.,50.,255.),d)/255.;`)
.replace(`#include <begin_vertex>`,
`#include <begin_vertex>
float t = time;
float moveT = mod(shift.x + shift.z * t,PI2);
float moveS = mod(shift.y + shift.z * t,PI2);
transformed += vec3(cos(moveS) * sin(moveT),cos(moveT),sin(moveS)*sin(moveT)) * shift.w;`);
shader.fragmentShader = `
varying vec3 vColor;
${shader.fragmentShader}
`.replace(`#include <clipping_planes_fragment>`,
`#include <clipping_planes_fragment>
float d = length(gl_PointCoord.xy - 0.5);`)
.replace(`vec4 diffuseColor = vec4( diffuse, opacity );`,
`vec4 diffuseColor = vec4( vColor, smoothstep(0.5, 0.1, d));`);
},
});
const stars = new THREE.Points(g, m);
stars.rotation.order = "ZYX";
stars.rotation.z = 0.2;
scene.add(stars);
// 创建爱心形状的粒子系统
const heartShape = [];
const heartCount = 1000;
for (let i = 0; i < heartCount; i++) {
const t = Math.PI - 2 * Math.PI * Math.random();
const x = 16 * Math.pow(Math.sin(t), 3);
const y = 13 * Math.cos(t) - 5 * Math.cos(2 * t) - 2 * Math.cos(3 * t) - Math.cos(4 * t);
heartShape.push(new THREE.Vector3(x, y, 0).multiplyScalar(0.2));
}
const heartGeometry = new THREE.BufferGeometry().setFromPoints(heartShape);
const heartMaterial = new THREE.PointsMaterial({
size: 0.1,
color: 0xff66cc,
transparent: true,
blending: THREE.AdditiveBlending,
});
const heart = new THREE.Points(heartGeometry, heartMaterial);
heart.position.set(0, 0, -5);
scene.add(heart);
// 这里可以把xx改名字
const loader = new FontLoader();
loader.load("https://threejs.org/examples/fonts/helvetiker_regular.typeface.json", (font) => {
const textGeometry = new TextGeometry("xxx I love you", {
font: font,
size: 1, // 增加字体大小
height: 0.2,
curveSegments: 12,
});
const textMaterial = new THREE.MeshBasicMaterial({ color: 0xff6699 });
const textMesh = new THREE.Mesh(textGeometry, textMaterial);
textMesh.position.set(-5, 0, 0); // 将文字位置置于中心偏左,以便看见
scene.add(textMesh);
// 使文本始终面向相机
textMesh.lookAt(camera.position);
textMesh.onBeforeRender = function () {
textMesh.lookAt(camera.position);
};
});
// 动画循环
const clock = new THREE.Clock();
const render = () => {
requestAnimationFrame(render);
controls.update();
const elapsed = clock.getElapsedTime();
gu.time.value = elapsed * Math.PI;
stars.rotation.y = elapsed * 0.05;
heart.rotation.y = Math.sin(elapsed) * 0.5;
heart.rotation.x = Math.cos(elapsed) * 0.2;
renderer.render(scene, camera);
};
render();
</script>
</body>
</html>
粒子代码模块
最新推荐文章于 2025-04-24 17:46:29 发布