使用 Three.js 创建动态粒子效果

今天,带大家使用粒子实现一个粒子飞毯的效果,我们先来看一下效果。

实现

初始化场景

首先创建一个场景,所有 3D 对象都会被添加到这个场景中。

javascript 复制代码
const scene = new THREE.Scene();

相机和渲染器

配置相机和渲染器来捕捉和显示场景。

相机
  • 使用 PerspectiveCamera 提供广角视图。
渲染器
  • 创建 WebGLRenderer 渲染器,将画布设置为全屏。
javascript 复制代码
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  100
);
camera.position.z = 13;

const renderer = new THREE.WebGLRenderer({
  canvas: document.querySelector("canvas"),
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));

添加粒子

我们将创建一个由数十万个小粒子组成的云,这些粒子可以模拟星空或任何动态环境效果。粒子的创建涉及两个主要组成部分:几何体和材质。

我们使用 BufferGeometry 来存储粒子的位置信息。每个粒子是通过三个坐标(x, y, z)定义的,所以对于 count 个粒子,我们需要一个长度为 count * 3 的数组来存储它们的位置。

javascript 复制代码
const particlesGeometry = new THREE.BufferGeometry();
const count = 500000; // 粒子数量
const positions = new Float32Array(count * 3); // 存储位置的数组
const colors = new Float32Array(count * 3); // 存储颜色的数组

for (let i = 0; i < count * 3; i += 3) {
  positions[i] = (Math.random() - 0.5) * 10; // x位置
  positions[i + 1] = (Math.random() - 0.5) * 10; // y位置
  positions[i + 2] = (Math.random() - 0.5) * 10; // z位置

  colors[i] = Math.random(); // r颜色
  colors[i + 1] = Math.random(); // g颜色
  colors[i + 2] = Math.random(); // b颜色
}

这里的随机数 Math.random() - 0.5 范围为 -0.50.5,乘以 10 来扩展粒子云的空间分布。

粒子材质

粒子材质决定了粒子的视觉效果,如大小、颜色和透明度。我们使用 PointsMaterial 并启用 vertexColors 使每个粒子可以有独立的颜色。

vertexColors: 允许每个粒子使用与其关联的顶点颜色,从而实现每个粒子拥有不同颜色的效果。

注意这里,我们使用了 load 一个透明贴图,这样可以让粒子看起来更加自然。

javascript 复制代码
const particlesMaterial = new THREE.PointsMaterial({
  size: 0.02, // 粒子大小
  alphaMap: textureLoader.load("/point.png"), // 粒子透明贴图
  transparent: true, // 开启透明度
  vertexColors: true, // 使用顶点颜色
});

上面的几个属性,我们在更加详细的介绍一下

  • size:定义了每个粒子点的屏幕上渲染的大小,单位为像素。它控制了粒子的基本尺寸,但实际视觉大小还会受到 sizeAttenuation 属性的影响,后者决定了粒子大小是否随着与摄像机的距离而变化。如果 sizeAttenuation 设置为 true(默认值),粒子大小将随距离变小,模拟现实世界中远处对象看起来更小的透视效果。
  • alphaMap:为每个粒子指定一个纹理贴图,该贴图的透明度(alpha 通道)将被用来影响粒子的透明度。这个功能使得粒子可以具有不均匀的透明度,从而创造更加自然或复杂的视觉效果,如模拟星星或发光粒子等。使用纹理的灰度值来决定相应区域的透明度。
  • 用于开启材质的透明处理。在使用 alphaMap 或者在材质颜色中指定 alpha 值小于 1 的情况下,需要将此属性设置为 true 以确保 Three.js 正确处理透明度。没有启用 transparent 时,即使材质具有透明纹理或颜色值,也会被渲染为完全不透明。
  • vertexColors:用于开启顶点颜色处理。当设置为 true 时,粒子的颜色将由顶点颜色决定,而不是整个粒子使用单一颜色。这使得每个粒子可以具有不同的颜色,从而实现更加丰富多彩的效果。

控制器

使用 OrbitControls 允许用户通过鼠标来旋转和缩放视图。

javascript 复制代码
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;

动画循环

创建动画循环来实时更新粒子位置和渲染场景。

更新粒子位置

我们在这里使用简单的三角函数来模拟粒子的垂直移动,创建类似波浪的效果。通过三角函数 Math.sin,我们可以为每个粒子创建一个周期性变化的动画效果,使其在 y 轴方向上波动。

javascript 复制代码
const tick = () => {
  const elapsedTime = clock.getElapsedTime(); // 获取从开始到现在的时间

  // 使粒子在y轴方向上根据时间变化
  for (let i = 0; i < count; i++) {
    const i3 = i * 3;
    const x = positions[i3]; // 获取粒子当前x位置
    positions[i3 + 1] = Math.sin(elapsedTime + x) * 0.3; // 根据时间和x位置计算新的y位置
  }

  particlesGeometry.attributes.position.needsUpdate = true; // 通知Three.js位置数据已更新
};

这里,Math.sin(elapsedTime + x) 的使用将每个粒子的动画周期与其 x 位置关联起来,创建更自然的波动效果。乘以 0.3 是为了控制波动的幅度,不让粒子移动得太极端。

渲染场景

在每次动画循环的最后,我们调用 renderer.render 方法来绘制更新后的场景:

javascript 复制代码
renderer.render(scene, camera);
window.requestAnimationFrame(tick); // 请求下一帧继续动画

代码

github

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

gitee

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

学习threejs:www.threejs3d.com

相关推荐
棋丶几秒前
VUE2和VUE3的区别
开发语言·前端·javascript
天才小网管10 分钟前
运动相机拍摄的视频打不开怎么办
数码相机·无人机
MR_Colorful11 分钟前
基于YOLO5的机械臂视觉抓取实现
数码相机
Pandaconda20 分钟前
【Golang 面试题】每日 3 题(二十三)
开发语言·后端·面试·golang·go·channel
sun00770023 分钟前
C++中,typename
开发语言·c++
C++小厨神38 分钟前
Go语言的数据库交互
开发语言·后端·golang
screct_demo1 小时前
详细讲一下Vue的路由Vue Router的安装,配置,基础用法和详细用法以及实践中应用
前端·javascript·vue.js
林涧泣1 小时前
【Uniapp-Vue3】使用ref定义响应式数据变量
前端·vue.js·uni-app
PieroPc1 小时前
特制一个自己的UI库,只用CSS、图标、emoji图 日后慢用!!!
javascript·css·ui
HelloZheQ1 小时前
CSS 变量:让你的样式更灵活、更易维护
前端·css·tensorflow