使用 Three.js 创建烟花粒子特效教程

使用 Three.js 创建烟花粒子特效教程

今天,我们将使用 Three.js 来实现一个简单而美观的烟花粒子效果。烟花会在屏幕随机位置生成,粒子在爆炸后呈现出散射、下降、逐渐消散的动态效果。先来看一下效果。

请添加图片描述

第一步:搭建基础场景

在正式实现烟花效果前,我们需要一个可以显示内容的 Three.js 场景。以下代码实现了最基本的场景、相机和渲染器设置。

import * as THREE from "three";// 场景设置
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000
);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);// 相机位置
camera.position.z = 50;
代码逻辑说明
  1. scene:创建一个场景对象,是 Three.js 中所有 3D 元素的容器。
  2. camera:创建透视相机,用于观察场景,参数:
    • 75:视角(FOV)。
    • window.innerWidth / window.innerHeight:宽高比。
    • 0.1 和 1000:相机的近、远平面。
  3. renderer:渲染器将 3D 场景绘制到浏览器中。
  4. 设置相机位置:通过 camera.position.z 拉远视角,确保看到整个场景。

第二步:定义烟花粒子类

在这一步,我们将设计一个 Firework 类,用于模拟每个烟花的粒子效果。
一个烟花包含以下逻辑:

  1. 初始属性
    • 粒子的位置(positions)、速度(velocities)以及颜色(colors)。
    • 设置粒子生命周期(life),用于控制粒子的消失。
  2. 初始化粒子:在烟花爆炸时,粒子会沿着随机方向散开。
  3. 更新粒子状态:粒子随着时间更新位置、缩小大小,并模拟重力作用。
  4. 销毁粒子:当粒子生命周期耗尽时,清除其资源。
1. 定义类和基础属性
class Firework {constructor(x, y, z) {this.geometry = new THREE.BufferGeometry(); // 几何对象存储粒子数据this.count = 10000; // 粒子数量this.positions = new Float32Array(this.count * 3); // 粒子位置this.velocities = []; // 粒子速度this.colors = new Float32Array(this.count * 3); // 粒子颜色this.sizes = new Float32Array(this.count); // 粒子大小this.life = new Float32Array(this.count); // 粒子生命周期}
}

代码逻辑说明

  1. positions:粒子的 3D 空间坐标(x, y, z)。
  2. velocities:粒子的速度向量,用于控制运动方向和速度。
  3. colors:粒子的颜色,以 RGB 格式表示,每个粒子独立设置。
  4. sizes:粒子的大小,用于动态变化。
  5. life:生命周期,用于控制粒子消散。
2. 初始化粒子数据

我们为每个粒子分配一个初始位置和随机运动方向。

for (let i = 0; i < this.count; i++) {const phi = Math.random() * Math.PI * 2; // 水平方向角度const theta = Math.random() * Math.PI;  // 垂直方向角度const velocity = 2 + Math.random() * 2; // 随机速度// 计算速度向量this.velocities.push(velocity * Math.sin(theta) * Math.cos(phi),velocity * Math.sin(theta) * Math.sin(phi),velocity * Math.cos(theta));// 设置初始位置this.positions[i * 3] = x;this.positions[i * 3 + 1] = y;this.positions[i * 3 + 2] = z;// 设置颜色为红色调this.colors[i * 3] = 1.0; // 红色this.colors[i * 3 + 1] = Math.random() * 0.2; // 随机绿色偏移this.colors[i * 3 + 2] = Math.random() * 0.2; // 随机蓝色偏移// 初始大小和生命周期this.sizes[i] = 0.3;this.life[i] = 1.0;
}

代码逻辑说明

  1. 随机方向:通过球面坐标计算粒子散射方向。
  2. 颜色随机性:让每个粒子的颜色略有不同,使整体效果更自然。
  3. 生命周期与大小:初始化每个粒子的生命周期和大小,稍后会动态更新。
3. 创建材质与几何

将粒子属性绑定到 Three.js 的 BufferGeometry 对象上,并为其定义材质。

this.geometry.setAttribute("position",new THREE.BufferAttribute(this.positions, 3)
);
this.geometry.setAttribute("color",new THREE.BufferAttribute(this.colors, 3)
);
this.geometry.setAttribute("size",new THREE.BufferAttribute(this.sizes, 1)
);const material = new THREE.PointsMaterial({size: 0.3,vertexColors: true,blending: THREE.AdditiveBlending,transparent: true,opacity: 0.8,
});this.points = new THREE.Points(this.geometry, material);
scene.add(this.points);

代码逻辑说明

  1. 几何属性:通过 setAttribute 绑定粒子的位置、颜色和大小。
  2. 粒子材质
    • vertexColors: true:允许粒子使用自定义颜色。
    • blending: THREE.AdditiveBlending:粒子叠加效果。
    • transparent: true:支持透明度设置。
  3. 添加到场景:通过 scene.add 将粒子效果添加到 Three.js 场景中。

第三步:更新粒子状态

在这一步,我们将为粒子添加运动、重力效果,并实现逐渐消失的逻辑。粒子在其生命周期内会不断更新位置、大小和透明度,直至完全消散。

1. 更新粒子的逻辑

我们在 Firework 类中定义一个 update 方法,用于逐帧更新粒子状态。粒子的行为包括:

  • 位置更新:根据速度调整粒子位置。
  • 重力效果:粒子会受到向下的重力作用。
  • 生命周期减少:粒子逐渐消散。
  • 尺寸变化:粒子大小随着生命周期减小。
update() {let alive = false; // 标记烟花是否仍然活跃for (let i = 0; i < this.count; i++) {if (this.life[i] > 0) {alive = true;// 更新位置this.positions[i * 3] += this.velocities[i * 3] * 0.1;this.positions[i * 3 + 1] += this.velocities[i * 3 + 1] * 0.1;this.positions[i * 3 + 2] += this.velocities[i * 3 + 2] * 0.1;// 添加重力效果this.velocities[i * 3 + 1] -= 0.05;// 减少生命周期this.life[i] -= 0.015;// 缩小粒子尺寸this.sizes[i] = this.life[i] * 0.3;}}// 更新几何数据this.geometry.attributes.position.needsUpdate = true;this.geometry.attributes.size.needsUpdate = true;return alive;
}

代码逻辑说明

  1. 位置更新:粒子会以其速度向指定方向移动,使用 positions[i * 3 + j] 更新每个轴的坐标。
  2. 重力效果:通过 velocities[i * 3 + 1] 对 y 轴速度施加一个固定的负值,模拟重力。
  3. 生命周期和大小
    • 每帧减少 life[i],模拟粒子的逐渐消失。
    • 粒子尺寸 sizes[i] 由生命周期决定,越接近结束越小。
  4. 几何更新:通过设置 needsUpdatetrue 通知 Three.js 更新粒子属性。

2. 清除已消散的粒子

当粒子完全消失后,我们需要将它从场景中移除,并释放相关的资源。
Firework 类中,定义一个 dispose 方法:

dispose() {scene.remove(this.points); // 从场景移除this.geometry.dispose();   // 释放几何资源this.points.material.dispose(); // 释放材质资源
}

第四步:管理烟花的生成与销毁

现在,我们有了基础场景和粒子类,接下来需要一个管理系统来:

  1. 随机生成烟花:在随机位置创建新的 Firework 实例。
  2. 逐帧更新所有烟花:调用 update 方法并移除已消散的烟花。
  3. 监听窗口变化:确保画布始终适配窗口大小。
1. 存储活跃烟花

创建一个数组 fireworks,用于存储当前所有的活跃烟花:

const fireworks = [];// 随机生成烟花
function createRandomFirework() {const x = (Math.random() * 2 - 1) * 30; // 随机 x 坐标const y = (Math.random() * 2 - 1) * 25; // 随机 y 坐标fireworks.push(new Firework(x, y, 0));  // 将新烟花添加到数组
}

2. 动画循环

animate 函数中,每帧执行以下操作:

  1. 随机生成新的烟花。
  2. 更新现有烟花的状态。
  3. 移除消散的烟花。
  4. 渲染场景。
function animate() {requestAnimationFrame(animate);// 随机生成烟花if (Math.random() < 0.05) {createRandomFirework();}// 更新所有烟花for (let i = fireworks.length - 1; i >= 0; i--) {const alive = fireworks[i].update();if (!alive) {fireworks[i].dispose();fireworks.splice(i, 1); // 从数组移除已消散的烟花}}// 渲染场景renderer.render(scene, camera);
}

3. 窗口大小调整

为了适配不同设备,我们需要监听窗口大小变化并调整相机和渲染器:

function onWindowResize() {camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth, window.innerHeight);
}window.addEventListener("resize", onWindowResize, false);

第五步:启动动画

最后,启动动画循环:

animate();

此时,项目已经完成!运行代码后,你将看到屏幕上随机生成烟花,每个烟花都会散射出无数的粒子,粒子在运动过程中逐渐消失。

到此,我们就完成了烟花

代码

github

https://github.com/calmound/threejs-demo/tree/main/yanhua

gitee

https://gitee.com/calmound/threejs-demo/tree/main/yanhua

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

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

相关文章

神经网络-VggNet

2014年VggNet被推出&#xff0c;获取了ILSVRC2014比赛分类项目的第二名&#xff0c;第一名是GoogleNet&#xff0c;该网络在下节介绍&#xff0c;本节主要介绍VggNet。 VggNet可以称为是一个家族&#xff0c;根据层数的不同包括了A、A-LRN、B、C、D等网络结构&#xff0c;其中…

docker-compose搭建sfpt服务器

1. 搭建 创建sftp目录&#xff0c;进入该目录创建docker-compose.yml文件内容如下&#xff1a; version: 3.7services:sftp:image: atmoz/sftpcontainer_name: sftpports:- "122:22"volumes:- ./sftp-data:/homeenvironment:SFTP_USERS: "liubei:liubei161:10…

计算机视觉目标检测-1

文章目录 摘要Abstract1.目标检测任务描述1.1 目标检测分类算法1.2 目标定位的简单实现思路1.2.1 回归位置 2.R-CNN2.1 目标检测-Overfeat模型2.1.1 滑动窗口 2.2 目标检测-RCNN模型2.2.1 非极大抑制&#xff08;NMS&#xff09; 2.3 目标检测评价指标 3.SPPNet3.1 spatial pyr…

减速机润滑油的选用原则

减速机在投入运行前必须加入适当粘度的润滑油&#xff0c;须使齿轮间摩擦减小&#xff0c;遇高负荷及冲击负荷时&#xff0c;减速机才能充分发挥其机能。那么&#xff0c;应该如何选择减速机的润滑油呢&#xff1f; 1、粘度选择&#xff1a;粘度是齿轮油的一个重要理化指标&…

解线性方程组

直接三角分解&#xff08;LU分解&#xff0c;Doolittle分解&#xff09; ATM分解&#xff08;追赶法&#xff0c;Crout分解&#xff0c;克劳特分解&#xff09; 平方根法&#xff08;Cholesky分解&#xff0c;乔列斯基分解&#xff09; 矩阵的范数

使用 OpenCV 在图像中添加文字

在图像处理任务中&#xff0c;我们经常需要将文本添加到图像中。OpenCV 提供了 cv2.putText() 函数&#xff0c;可以很方便地在图像上绘制文本&#xff0c;支持多种字体、颜色、大小和位置等参数。 本文将详细介绍如何使用 OpenCV 在图像中添加文字&#xff0c;介绍 cv2.putTe…

如何高效学习PHP框架源码

为什么学习php框架源码 学习PHP框架源码是软件开发领域中的一个重要环节&#xff0c;它带来了诸多益处&#xff0c;无论是对于个人技能的提升&#xff0c;还是对于实际项目开发的优化&#xff0c;都有着不可忽视的作用。以下是一些具体的原因&#xff0c;解释了为什么学习PHP框…

HAL库STM32硬件IIC驱动数字电位器MCP4017

目录 一、芯片特性 二、硬件电路 三、工程搭建 四、IIC硬件地址 五、驱动程序 项目需要&#xff0c;最近用到了一个IIC接口的数字电位器&#xff0c;型号&#xff1a;MCP4017T-502E。对应阻值5K&#xff0c;使用STM32G030F6的硬件IIC驱动&#xff0c;发现简单的不得了&…

git设置项目远程仓库指向github的一个仓库

要将你的Git项目设置为指向GitHub上的远程仓库&#xff0c;你需要执行以下步骤&#xff1a; 创建GitHub仓库&#xff1a; 登录到你的GitHub账户。点击右上角的 “” 号&#xff0c;选择 “New repository” 创建一个新的仓库。填写仓库的名称&#xff0c;可以添加描述&#xff…

Vim 编辑器详细教程

Vim 编辑器详细教程 Vim 是一个强大的文本编辑器&#xff0c;以其高效的编辑能力和强大的功能著称&#xff0c;特别适合程序员和文字处理工作者。以下是一个详细的 Vim 教程&#xff0c;从基础操作到高级用法。 1. Vim 基础操作 1.1 Vim 的三种模式 正常模式&#xff08;Nor…

uni-app 中使用微信小程序第三方 SDK 及资源汇总

&#x1f380;&#x1f380;&#x1f380;uni-app 跨端开发系列 &#x1f380;&#x1f380;&#x1f380; 一、uni-app 组成和跨端原理 二、uni-app 各端差异注意事项 三、uni-app 离线本地存储方案 四、uni-app UI库、框架、组件选型指南 五、uni-app 蓝牙开发 六、uni-app …

17.2、应急事件场景与处理流程

目录 常见网络安全应急事件场景网络安全应急处理流程应急演练类型 常见网络安全应急事件场景 应急事件的处理场景&#xff0c;分成四类场景&#xff0c;恶意程序事件&#xff0c;网络攻击事件&#xff0c;还有网站相关的一些安全事件&#xff0c;最后是拒绝服务事件 恶意程序…

PostgreSQL表达式的类型

PostgreSQL表达式是数据库查询和操作中非常重要的组成部分。它们由一个或多个值、运算符和PostgreSQL函数组合而成,用于求值或执行特定的操作。PostgreSQL表达式类似于公式,是用查询语言编写的。它们可以用于查询数据库中的特定数据集,或者在进行数据操作时执行计算和逻辑判…

.NET能做什么?全面解析.NET的应用领域

.NET 是由微软开发的一个开源、跨平台的开发框架。它不仅支持构建各种应用程序&#xff0c;还能运行在不同的操作系统上&#xff0c;包括 Windows、Linux 和 macOS。自从 .NET Core 的推出&#xff0c;.NET 成为了一个现代化的开发平台&#xff0c;能够满足企业和开发者日益多样…

19_HTML5 Web Workers --[HTML5 API 学习之旅]

HTML5 Web Workers 是一种允许 JavaScript 在后台线程中运行的技术&#xff0c;从而不会阻塞用户界面或其他脚本的执行。通过使用 Web Workers&#xff0c;你可以执行复杂的计算任务而不影响页面的响应速度&#xff0c;提升用户体验。 Web Workers 的特点 Web Workers 是 HTM…

十二、SQL 进阶:高级技巧提升查询效率实战指南

SQL 进阶&#xff1a;高级技巧提升查询效率实战指南 一、索引优化&#xff1a;数据库的“高速公路” 索引犹如图书馆里的书籍索引卡&#xff0c;可使数据库迅速定位所需数据&#xff0c;避免全表扫描。例如&#xff0c;在存储员工信息的表employees&#xff08;包含字段emplo…

Java 23和JDK 23详细安装方法,常用命令使用等

Java JDK 23 是 Oracle 提供的最新版本的 Java 开发工具包&#xff0c;它包含了 Java 编程语言的最新特性和改进。本教程将介绍如何安装 JDK 23&#xff0c;并详细讲解一些常用的命令和用法。 一、安装 JDK 23 下载 JDK 23&#xff1a; 提供了 Windows、macOS 和 Linux 的安装…

红黑树 Red-Black Tree介绍

1. 红黑树的定义 红黑树是一种具有如下性质的二叉搜索树&#xff1a; 每个节点是红色或黑色。根节点是黑色。所有叶子节点都是黑色的空节点&#xff08;NIL节点&#xff09;&#xff0c;即哨兵节点。如果一个节点是红色&#xff0c;那么它的子节点一定是黑色。&#xff08;不存…

《解锁 Python 数据挖掘的奥秘》

《解锁 Python 数据挖掘的奥秘》 一、Python 数据挖掘基础&#xff08;一&#xff09;Python 基础与数据挖掘环境搭建&#xff08;二&#xff09;数据挖掘基本流程概述 二、Python 数据挖掘核心技术&#xff08;一&#xff09;数据收集与预处理技术&#xff08;二&#xff09;常…

爆改RagFlow

Rag理论概述 由近期 RAGFlow 的火爆看 RAG 的现状与未来 Ragflow解析参数说明 ♥ RagFlow源码解析 实际的文件解析通过接口 /v1/document/run 进行触发的&#xff0c;实际的处理是在 api/db/services/task_service.py 中的 queue_tasks() 中完成的&#xff0c;此方法会根据文件…