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

news2025/1/23 6:12:21

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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2280748.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

再见 Crontab!Linux 定时任务的新选择!

引言 说到 Linux 下定时执行任务&#xff0c;大多数人可能会想到 crontab&#xff1f;没错&#xff0c;它的确是 Linux 下比较通用和方便的方式&#xff0c;但是今天我来介绍一种新的方法来创建定时任务并且支持更多更强大的功能。 Systemd 很多小伙伴应该听说过 Systemd&…

Unity入门1

安装之后无法获得许可证&#xff0c;可以考虑重装 新建项目 单击空白处生成脚本 双击c#文件 会自动打开vstudio 检查引用 如果没有引用&#xff0c;重开vstu&#xff0c;或者重新加载项目 hierarchy层级 scenes场景 assets资产 inspector督察 icon图标 资源链接&…

【二叉树】遍历总结!

在很多问题中&#xff0c;熟练掌握二叉树的遍历方法&#xff0c;能够轻松解决很多问题。 新建一棵二叉树root[1,null,2,3] 1、前序遍历 前序遍历的顺序为根节点->左子树->右子树&#xff0c;按照以上二叉树&#xff0c;遍历顺序为[1&#xff0c;2&#xff0c;3]。代码为…

(2)STM32 USB设备开发-USB虚拟串口

例程&#xff1a;STM32USBdevice: 基于STM32的USB设备例子程序 - Gitee.com 本篇为USB虚拟串口教程&#xff0c;没有知识&#xff0c;全是实操&#xff0c;按照步骤就能获得一个STM32的USB虚拟串口。本例子是在野火F103MINI开发板上验证的&#xff0c;如果代码中出现一些外设的…

ASP .NET Core 学习(.NET9)部署(一)windows

在windows部署 ASP .NET Core 的时候IIS是不二选择 一、IIS安装 不论是在window7 、w10还是Windows Server&#xff0c;都是十分简单的&#xff0c;下面以Windows10为例 打开控制面版—程序—启用或关闭Windows功能 勾选图中的两项&#xff0c;其中的子项看需求自行勾选&am…

Java并发编程面试题:线程池Fork/Join(19题)

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

fyne 选项卡设计

用户界面的设计至关重要&#xff0c;它直接影响着用户体验。选卡设计作为一种常见的界面布局方式&#xff0c;能够有效地组织和展示信息&#xff0c;使用户能够方便快捷地浏览和操作。 Fyne 是一个用 Go 语言编写的跨平台 GUI 框架&#xff0c;它提供了丰富的组件和功能&#…

MySQL——主从同步

提醒&#xff1a;进行配置时&#xff0c;需要确保一主两从的操作系统、MySQL版本一致&#xff0c;否则将出现问题 环境介绍 服务器IP主服务器172.25.254.10从服务器-1172.25.254.11从服务器-2172.25.254.12 配置 # 快速配置&#xff0c;选择多重执行&#xff0c;确保版本一…

IDEA中Maven使用的踩坑与最佳实践

文章目录 IDEA中Maven使用的踩坑与最佳实践一、环境配置类问题1. Maven环境配置2. IDEA中Maven配置建议 二、常见问题与解决方案1. 依赖下载失败2. 依赖冲突解决3. 编译问题修复 三、效率提升技巧1. IDEA Maven Helper插件使用2. 常用Maven命令配置3. 多模块项目配置4. 资源文件…

VIVADO-block desgn 中时钟连线报错

问题描述 1.自定义的IP核由于封装不规范&#xff0c;输出的时钟引脚缺少该时钟的相关信息 正常时钟引脚属性 异常的时钟引脚属性 2.run connection automation 中无法找到这种缺少信息的时钟源 3.axi_clk与axi interconnect时钟频率不匹配 解决方案&#xff1a; 1.用BUFG将缺少…

CSDN 博客之星 2024:默语的技术进阶与社区耕耘之旅

CSDN 博客之星 2024&#xff1a;默语的技术进阶与社区耕耘之旅 &#x1f31f; 默语&#xff0c;是一位在技术分享与社区建设中坚持深耕的博客作者。今年&#xff0c;我有幸再次入围成为 CSDN 博客之星TOP300 的一员&#xff0c;这既是对过往努力的肯定&#xff0c;也是对未来探…

BUUCTF_Web(UPLOAD COURSE 1)

打开靶机&#xff0c;发现需要上传文件&#xff0c;尝试一句话木马蚁剑链接 一句话木马 【基本原理】利用文件上传漏洞&#xff0c;往目标网站中上传一句话木马&#xff0c;然后你就可以在本地通过中国菜刀chopper.exe即可获取和控制整个网站目录。表示后面即使执行错误&#…

车载软件架构 --- CP和AP作为中央计算平台的软件架构双核心

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 简单&#xff0c;单纯&#xff0c;喜欢独处&#xff0c;独来独往&#xff0c;不易合同频过着接地气的生活…

docker ubuntu:20.04构建c++ grpc环境

由c grpc必须源码编译&#xff0c;ubuntu版本不同可能出现的问题也不同&#xff0c;这里分享下我的构建过程。 我是vscode结合docker去安装c虚拟环境&#xff0c;我不想污染本机环境。 vscode的插件Dev Containers Dockerfile如下(如果单纯是ubuntu环境构建&#xff0c;可忽略该…

PV-RCNN、PV-RCNN++ 网络结构

paper&#xff1a; PV-RCNN https://arxiv.org/abs/1912.13192PV-RCNN https://arxiv.org/abs/2102.00463 github&#xff1a;使用OpenPCDet进行训练测试 https://github.com/open-mmlab/OpenPCDet PV-RCNN 简介 PV-RCNN的提出是想要综合 point-based 和 voxel-based 3D目…

认识c++

文章目录 1namespace 写博客 &#xff0c;做作业 笔记很关键 1namespace ::域作用限定域 局部域>全局域>命名空间域&#xff08;展开了命名空间域or指定访问命名空间域&#xff09; 不要轻易展开 可以这样解决 方案一 方案二 using namespace std; 直接展开会有风…

接口 V2 完善:基于责任链模式、Canal 监听 Binlog 实现数据库、缓存的库存最终一致性

&#x1f3af; 本文介绍了一种使用Canal监听MySQL Binlog实现数据库与缓存最终一致性的方案。文章首先讲解了如何修改Canal配置以适应订单表和时间段表的变化&#xff0c;然后详细描述了通过责任链模式优化消息处理逻辑的方法&#xff0c;确保能够灵活应对不同数据表的更新需求…

内容中台实施最佳实践解析与应用指南

内容概要 内容中台是一个旨在提升企业内容管理与分发能力的战略性平台&#xff0c;其实施最佳实践对于企业在数字化转型中尤为重要。内容中台的建设&#xff0c;不仅涉及技术层面的架构设计&#xff0c;还需结合组织变革、业务流程优化等多个方面&#xff0c;以实现高效、灵活…

顺序表和链表(详解)

线性表 线性表&#xff08; linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一条直线。…

TCP全连接队列

1. 理解 int listen(int sockfd, int backlog) 第二个参数的作用 backlog&#xff1a;表示tcp全连接队列的连接个数1。 如果连接个数等于backlog1&#xff0c;后续连接就会失败&#xff0c;假设tcp连接个数为0&#xff0c;最大连接个数就为1&#xff0c;并且不accept获取连接…