HTML5 Canvas和JavaScript的3D粒子星系效果

HTML部分

  • 基本结构包括<html>, <head>, 和 <body>标签。
  • <title>标签设置了页面标题为"优化版3D粒子星系"。
  • <style>块定义了一些基本样式:
    • body:无边距,隐藏滚动条,黑色背景,禁用触摸动作以提高性能。
    • canvas:设置鼠标指针为移动图标(暗示用户可以拖动)。

JavaScript部分

配置与类定义
  1. 配置对象 (config):

    • 定义了粒子数量、引力强度、连线范围等参数,用于调整粒子系统的行为。
  2. Vector3 类

    • 使用Float32Array存储三维向量数据,提供对x, y, z分量的访问方法,有助于提升计算性能。
  3. ParticleSystem 类

    • 构造函数:初始化画布、上下文、粒子数组和其他必要属性。
    • init 方法:初始化粒子系统,包括粒子生成、事件监听器绑定和动画启动。
    • resize 方法:处理窗口大小变化时的重绘逻辑,使用防抖技术避免频繁重绘。
    • draw 方法:核心渲染逻辑,利用离屏Canvas进行绘制以提高性能,并对每个粒子进行位置更新和投影计算。
    • animate 方法 :动画循环,调用draw方法并请求下一帧动画。
    • destroy 方法:清理资源,取消动画帧请求并移除事件监听器。
关键特性与优化点
  1. 性能优化

    • 减少粒子数量 (PARTICLE_COUNT: 150) 和降低引力强度 (GRAVITY: 0.3) 以减少计算负荷。
    • 使用Float32Array代替普通数组来存储数值,提高数值计算效率。
    • 禁用透明通道 (alpha: false) 提高绘图性能。
    • 利用离屏Canvas (bufferCanvas) 进行绘制,减少主Canvas的重绘次数。
    • 使用防抖处理窗口大小变化 (resize方法),防止频繁触发重绘。
  2. 用户体验优化

    • 支持鼠标和触摸设备的交互,使粒子系统在不同设备上都能良好工作。
    • 页面隐藏时自动暂停动画 (visibilitychange事件监听),节省资源。
  3. 视觉效果

    • 动态计算每个粒子的位置、角度和距离,模拟出3D旋转效果。
    • 根据时间动态调整粒子颜色 (color: hsl(${Math.random()*360}, 70%, 50%)),增加视觉层次感。
    • 实现粒子的缩放和投影效果,增强立体感。

<!DOCTYPE html>

<html>

<head>

<title>优化版3D粒子星系</title>

<style>

body {

margin: 0;

overflow: hidden;

background: #000;

touch-action: none;

}

canvas {

cursor: move;

/* 移除滤镜提升性能 */

}

</style>

</head>

<body>

<canvas id="canvas"></canvas>

<script>

// 性能优化配置

const config = {

PARTICLE_COUNT: 150, // 减少粒子数量

GRAVITY: 0.3, // 降低引力强度

LINE_THRESHOLD: 80, // 缩小连线范围

ZOOM_SPEED: 0.0005,

ROTATION_SPEED: 0.0001,

COLOR_CYCLE: 0.0002

};

// 使用Float32Array提升计算性能

class Vector3 {

constructor() {

this.data = new Float32Array(3);

}

set x(v) { this.data[0] = v; }

set y(v) { this.data[1] = v; }

set z(v) { this.data[2] = v; }

get x() { return this.data[0]; }

get y() { return this.data[1]; }

get z() { return this.data[2]; }

}

class ParticleSystem {

constructor() {

this.canvas = document.getElementById('canvas');

this.ctx = this.canvas.getContext('2d', { alpha: false }); // 关闭透明通道

this.particles = [];

this.core = new Vector3();

this.mouse = new Vector3();

this.animationFrame = null;

this.init();

}

init() {

// 初始化粒子

for(let i=0; i<config.PARTICLE_COUNT; i++) {

this.particles.push({

pos: new Vector3(),

vel: new Vector3(),

angle: Math.PI * 2 * Math.random(),

distance: 100 + Math.random() * 400,

mass: 0.5 + Math.random(),

color: `hsl(${Math.random()*360}, 70%, 50%)`

});

}

// 节流处理

this.resize();

window.addEventListener('resize', () => this.resize());

this.canvas.addEventListener('mousemove', e => this.handleMove(e));

this.canvas.addEventListener('touchmove', e => this.handleTouch(e), {passive: true});

this.animate();

}

// 使用防抖优化resize

resize = () => {

cancelAnimationFrame(this.animationFrame);

this.canvas.width = window.innerWidth;

this.canvas.height = window.innerHeight;

this.core.x = this.canvas.width/2;

this.core.y = this.canvas.height/2;

this.animationFrame = requestAnimationFrame(this.animate);

}

draw() {

// 使用离屏Canvas提升渲染性能

if(!this.bufferCanvas) {

this.bufferCanvas = document.createElement('canvas');

this.bufferCtx = this.bufferCanvas.getContext('2d');

this.bufferCanvas.width = this.canvas.width;

this.bufferCanvas.height = this.canvas.height;

}

const ctx = this.bufferCtx;

ctx.fillStyle = 'rgb(0,0,0)';

ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);

const time = performance.now();

this.particles.forEach(particle => {

// 优化后的运动计算

particle.angle += config.ROTATION_SPEED / particle.mass;

const x = Math.cos(particle.angle) * particle.distance;

const z = Math.sin(particle.angle) * particle.distance;

const y = Math.sin(time*0.001 + particle.angle) * 30;

// 投影计算

const scale = 150 / (150 + z);

const px = x * scale + this.core.x;

const py = y * scale + this.core.y;

// 绘制优化

ctx.beginPath();

ctx.arc(px, py, 1.5, 0, Math.PI*2);

ctx.fillStyle = particle.color;

ctx.fill();

});

// 单次绘制到主Canvas

this.ctx.drawImage(this.bufferCanvas, 0, 0);

}

animate = () => {

this.draw();

this.animationFrame = requestAnimationFrame(this.animate);

}

// 添加销毁方法

destroy() {

cancelAnimationFrame(this.animationFrame);

window.removeEventListener('resize', this.resize);

}

}

const system = new ParticleSystem();

// 页面隐藏时自动暂停

document.addEventListener('visibilitychange', () => {

if(document.hidden) system.destroy();

});

</script>

</body>

</html>

相关推荐
赵大仁11 分钟前
React Native 与 Expo
javascript·react native·react.js
程序员与背包客_CoderZ1 小时前
Node.js异步编程——Callback回调函数实现
前端·javascript·node.js·web
清灵xmf2 小时前
从 Set、Map 到 WeakSet、WeakMap 的进阶之旅
前端·javascript·set·map·weakset·weakmap
WenGyyyL2 小时前
研读论文——《用于3D工业异常检测的自监督特征自适应》
人工智能·python·深度学习·机器学习·计算机视觉·3d
belldeep2 小时前
python:trimesh 用于 STL 文件解析和 3D 操作
python·3d·stl
Leo.yuan2 小时前
3D 数据可视化系统是什么?具体应用在哪方面?
大数据·数据库·3d·信息可视化·数据分析
Unity官方开发者社区2 小时前
Android App View——团结引擎车机版实现安卓应用原生嵌入 3D 开发场景
android·3d·团结引擎1.5·团结引擎车机版
11054654012 小时前
11、参数化三维产品设计组件 - /设计与仿真组件/parametric-3d-product-design
前端·3d
高德技术2 小时前
IJCAI 2025 | 高德首个原生3D生成基座大模型「G3PT」重塑3D生成的未来
3d
运维@小兵3 小时前
vue使用路由技术实现登录成功后跳转到首页
前端·javascript·vue.js