🌌 Three.js 几何变化动画配合噪声粒子教程:让你的代码也会“呼吸”

一、前言:当数学遇上艺术 🎨

Three.js 是 WebGL 的魔术师,它能在浏览器里召唤出立方体、星系、时间感与情绪。而当它遇上"噪声粒子(Noise Particles)",我们就能做出一种仿佛会呼吸的几何动画。

这不仅仅是动画,而是一种"数据哲学" ------ 在浮点与顶点之间,每一个粒子都在询问存在的意义。


二、底层原理🌊:几何变化与噪声的"粒子哲学"

1. 几何变化(Geometry Morphing)

  • 几何的顶点(vertex)是动态的向量集合,你可以理解为一群情绪不稳定的小点。
  • 改变它们的坐标,就是让它们"跳舞"。

2. 噪声(Noise)

  • 普通的随机数像是喝多了的鹦鹉,杂乱无章。
  • 而噪声(如 Perlin Noise 或 Simplex Noise)是"带旋律的随机"------一种自然界常见的渐变模式。

通过给每个顶点一个"噪声驱动的偏移",我们就能得到有机的变化感。想象一下海浪、呼吸、风中的草。


三、技术结构:怎么让坐标"呼吸"🌬️

我们利用以下逻辑:

  1. 创建基础几何体,例如球体或平面;
  2. 在每一帧中,为每个顶点叠加一层噪声偏移;
  3. 通过时间参数让噪声随帧变化,从而产生动态效果;
  4. 同时结合粒子(PointMaterial)渲染,让几何看起来像在散发能量。

四、核心代码讲解:JS 实战 💻

ini 复制代码
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { SimplexNoise } from "three/examples/jsm/math/SimplexNoise.js"; // 引入噪声

// 🌍 初始化场景
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x080808);

// 📷 相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;

// 🎞️ 渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 🧭 控制器
const controls = new OrbitControls(camera, renderer.domElement);

// 🌐 创建几何体点云
const geometry = new THREE.SphereGeometry(1, 128, 128);
const material = new THREE.PointsMaterial({
  color: 0x66ccff,
  size: 0.02,
});
const points = new THREE.Points(geometry, material);
scene.add(points);

// 🌪 生成噪声对象
const noise = new SimplexNoise();

// 🔄 动画逻辑
function animate() {
  requestAnimationFrame(animate);

  const time = performance.now() * 0.001; // 时间参数

  geometry.attributes.position.needsUpdate = true; // 告诉Three.js刷新顶点
  const positions = geometry.attributes.position.array;

  // 🌀 每个顶点加上噪声偏移
  for (let i = 0; i < positions.length; i += 3) {
    const x = positions[i];
    const y = positions[i + 1];
    const z = positions[i + 2];
    const n = noise.noise3d(x * 0.7, y * 0.7, time * 0.3);
    positions[i] = x + n * 0.05;
    positions[i + 1] = y + n * 0.05;
    positions[i + 2] = z + n * 0.05;
  }

  points.rotation.y += 0.002;
  renderer.render(scene, camera);
}

animate();

// 📱 自适应
window.addEventListener("resize", () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});

💡 核心思想

每一帧我们重新计算顶点位置 + 噪声干扰,让几何体轻微抖动,形似"呼吸球体"。通过 PointsMaterial 将物体转化为粒子可视化。


五、为什么噪声让动画看起来"自然"🌾

大自然不喜欢陡峭的转折。

风不会突然变向,波浪不会瞬间下沉。

噪声用于建立"连续的不确定性":

  • 每个点都有随机偏移;
  • 但这种随机变化是逐渐的,而非突兀;
  • 结果就是------流畅、有机、具有生命感。

🎭 一句话概括

噪声就是"让随机数装得像命运"的艺术。


六、小技巧 🌈

  • 做光影交互:可以让粒子颜色随噪声变化,像极了能量在流动。
  • 混合多层噪声:叠加快慢两层噪声,获得更复杂的形态。
  • 用 GUI 调参:让用户通过滑杆调节噪声强度与速度,实验不同"生命频率"。

七、附录:响应式可视化布局图🌐

下面是一个 HTML 可运行版本(自动适配屏幕),直接复制运行👇

ini 复制代码
<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8" />
  <title>Three.js 噪声粒子呼吸球</title>
  <script src="https://cdn.jsdelivr.net/npm/three@0.161.0/build/three.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/three@0.161.0/examples/js/controls/OrbitControls.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/three@0.161.0/examples/js/math/SimplexNoise.js"></script>
  <style>
    body { margin: 0; background: #000; overflow: hidden; }
    canvas { display: block; width: 100%; height: 100%; }
  </style>
</head>
<body>
  <script>
    const scene = new THREE.Scene();
    scene.background = new THREE.Color(0x000010);

    const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
    camera.position.z = 5;

    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    const controls = new THREE.OrbitControls(camera, renderer.domElement);

    const geo = new THREE.SphereGeometry(1, 128, 128);
    const mat = new THREE.PointsMaterial({ color: 0x44ccff, size: 0.02 });
    const mesh = new THREE.Points(geo, mat);
    scene.add(mesh);

    const noise = new SimplexNoise();

    function animate() {
      requestAnimationFrame(animate);
      const t = Date.now() * 0.001;
      const pos = geo.attributes.position.array;

      for (let i = 0; i < pos.length; i += 3) {
        const x = pos[i], y = pos[i+1], z = pos[i+2];
        const n = noise.noise3d(x*0.7, y*0.7, t*0.3);
        pos[i] = x + n * 0.05;
        pos[i+1] = y + n * 0.05;
        pos[i+2] = z + n * 0.05;
      }

      geo.attributes.position.needsUpdate = true;
      mesh.rotation.y += 0.002;
      renderer.render(scene, camera);
    }

    animate();

    window.addEventListener("resize", () => {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(window.innerWidth, window.innerHeight);
    });
  </script>
</body>
</html>

八、结语:代码的呼吸 🌬️

当你看到屏幕上那一片不断律动的粒子球,请记得:

每一个顶点,都在计算与随机之间寻找平衡;

每一阵噪声,都是动态世界的轻叹。

于是,当数字开始"呼吸",我们也许就在靠近计算的艺术

🌟 致程序员的浪漫宣言:

"我在浏览器里造了一个星球,它并不完美,但它会呼吸。" 🌐💙

相关推荐
GIS之路8 分钟前
GDAL 实现矢量裁剪
前端·python·信息可视化
是一个Bug12 分钟前
后端开发者视角的前端开发面试题清单(50道)
前端
Amumu1213813 分钟前
React面向组件编程
开发语言·前端·javascript
持续升级打怪中35 分钟前
Vue3 中虚拟滚动与分页加载的实现原理与实践
前端·性能优化
GIS之路39 分钟前
GDAL 实现矢量合并
前端
hxjhnct41 分钟前
React useContext的缺陷
前端·react.js·前端框架
冰暮流星1 小时前
javascript逻辑运算符
开发语言·javascript·ecmascript
前端 贾公子1 小时前
从入门到实践:前端 Monorepo 工程化实战(4)
前端
菩提小狗1 小时前
Sqlmap双击运行脚本,双击直接打开。
前端·笔记·安全·web安全
前端工作日常1 小时前
我学习到的AG-UI的概念
前端