Three.js 图片抖动粒子特效

🎯 提示词

PROMPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
使用 Three.js 实现图片抖动粒子特效,具体要求:

**核心特效**
- 将图片解析为像素数据
- 根据像素亮度生成粒子深度分布
- 粒子系统沿 Z 轴周期性抖动
- 保留原图色彩信息

**场景与光照**
- 黑色背景
- 坐标轴辅助线辅助调试
- AmbientLight 环境光

**交互与控制**
- TrackballControls 自由旋转缩放
- 相机距离 3000 单位

**技术要求**
- Three.js 版本 (ES Module)
- TrackballControls 控制器
- Canvas 2D Context 解析图片
- 自定义 ShaderMaterial 处理粒子颜色和抖动

📖 效果拆解

层次 视觉效果 技术实现
基础 像素粒子化 ImageData 遍历 + BufferGeometry
核心特效 Z 轴亮度分布 亮度权重映射到 zRange 范围
动态效果 正弦波抖动 amplitude = sin(animationTime)
色彩保留 逐像素颜色 customColor attribute

🔧 核心技术点

1. 图片像素数据读取

为什么需要这个技术:需要获取每个像素的 RGB 值来生成有颜色的粒子系统。

JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function createPixelData() {
    var image = document.createElement("img");
    var canvas = document.createElement("canvas");
    var context = canvas.getContext("2d");

    image.onload = function () {
        canvas.width = image.width;
        canvas.height = image.height;
        context.fillStyle = context.createPattern(image, 'no-repeat');
        context.fillRect(0, 0, imageWidth, imageHeight);
        // 获取像素 RGBA 数据
        imageData = context.getImageData(0, 0, imageWidth, imageHeight).data;
        createPaticles();
    };
    image.src = "https://img1.baidu.com/it/u=232967222,3421933282...";
}

2. 亮度计算与 Z 轴映射

为什么需要这个技术:根据像素亮度决定粒子在 Z 轴上的位置,明亮像素靠近观察者。

JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
var weights = [0.2126, 0.7152, 0.0722];  // RGB 转亮度系数
// 遍历每个像素
for (var i = 0; i < imageHeight; i++) {
    for (var j = 0; j < imageWidth; j++) {
        var color = new THREE.Color();
        color.setRGB(imageData[c] / 255, imageData[c + 1] / 255, imageData[c + 2] / 255);
        // 计算亮度
        var weight = color.r * weights[0] + color.g * weights[1] + color.b * weights[2];
        // 映射到 Z 轴范围
        vertex.z = (zRange * -0.5) + (zRange * weight);
    }
}

3. 粒子 Shader

为什么需要这个技术:自定义顶点着色器实现 Z 轴抖动效果。

GLSL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
uniform float amplitude;
attribute vec3 customColor;
varying vec3 vColor;

void main() {
    vColor = customColor;
    vec4 pos = vec4(position, 1.0);
    // 正弦波抖动
    pos.z *= amplitude;
    vec4 mvPosition = modelViewMatrix * pos;
    // 根据深度调整粒子大小
    gl_PointSize = 2.0 * (300.0 / -mvPosition.z);
    gl_Position = projectionMatrix * mvPosition;
}

4. 动画循环

为什么需要这个技术:持续更新 amplitude 参数实现周期性抖动。

JAVASCRIPT
1
2
3
4
5
6
function update() {
    // 正弦波控制抖动幅度
    shaderUniforms.amplitude.value = Math.sin(animationTime);
    animationTime += animationDelta;
    controls.update();
}

💡 调试与优化

问题类型 表现形式 解决方案
图片跨域失败 CORS 错误或空白 使用同源图片或配置 CORS 头部
粒子过于密集 性能下降 降低图片分辨率或采样间隔
抖动不自然 运动僵硬 调整 animationDelta 或改用其他波形

🚀 扩展思路

变体效果 核心改动 难度
粒子聚合 鼠标点击聚合/散开 ⭐⭐
颜色渐变 粒子颜色随时间变化
3D 漂浮 添加 X/Y 轴随机运动
马赛克效果 用 BoxGeometry 替代 Points ⭐⭐
粒子消散 alpha 随时间衰减 ⭐⭐
图片切换 过渡动画切换多张图片 ⭐⭐⭐

本文档由 ThreeLab 编辑整理,如需转载,请注明出处。