Threejs+Mediapipe控制的3D模型支持动态模糊效果,效果继续升级!

AI 知识库3周前发布
1,472 0 0
熊猫办公
昨天分享的文章Threejs+Mediapipe实现万剑归宗和GPGPU碎片控制器,效果炸裂!中模型还没动起来,今天作者更新了一个支持动画的效果,于是我在它基础上将手势交互也整合进去了。

https://github.com/SahilK-027/Crystal-Bird

作者的模型效果:
3D混元模型生成带绑定动画的模型:
昨天文章里提到的万剑归宗
再分享一个类似案例用在了产品介绍上面,作者详细介绍了制作方法和建模过程:

制作方法:https://elcine.beehiiv.com/p/build-an-interactive-3d-product-showcase-app-with-zero-coding-experience?draft=true案例演示:https://gesturemodel.emergent.host/

Threejs+Mediapipe控制的3D模型支持动态模糊效果,效果继续升级!
这里分享几个这里面涉及的几个技术:
(GPGPU Particles -> Flowfield -> Bloom -> Chromatic Aberration -> Film Grain -> Motion Blur)是目前 WebGL/Three.js 创意编程中非常经典的高端视觉效果组合。它通常用于制作类似“赛博朋克”、“数据流”、“粒子风暴”等极具冲击力的视觉作品。
1. GPGPU Particles (通用 GPU 计算粒子系统)概念:在传统的 CPU 粒子系统中,JavaScript 需要遍历每一个粒子并更新其位置,当粒子数量超过几千时,CPU 会不堪重负导致卡顿。GPGPU (General-Purpose computing on Graphics Processing Units)技术则是利用 GPU 强大的并行计算能力,将几十万甚至上百万的粒子位置计算全部交给 GPU 处理。原理:数据即纹理 (Data Texture):我们将粒子的位置 (x, y, z) 和速度 (vx, vy, vz) 存储在浮点纹理(Floating Point Texture)的 RGBA 通道中。纹理上的每一个像素代表一个粒子。●乒乓缓冲 (Ping-Pong Buffering):我们需要两个纹理缓冲区(Read Buffer 和 Write Buffer)。在每一帧中,着色器读取 Read Buffer 的旧位置,计算新位置写入 Write Buffer,然后交换两者。Three.js 实现:Three.js 官方提供了一个极其有用的工具库GPUComputationRenderer。1.初始化:创建一个存储位置的纹理和一个存储速度的纹理。2.着色器 (Shader):编写一个计算着色器(Fragment Shader),在这个 Shader 里编写物理运动逻辑(例如:gl_FragColor = position + velocity)。3.渲染:在渲染粒子的顶点着色器(Vertex Shader)中,不使用 attribute 中的 position,而是根据粒子的索引(uv坐标)去GPUComputationRenderer计算出的纹理中采样获取位置。

●●●javascript
// 伪代码示例
import{ GPUComputationRenderer }from'three/examples/jsm/misc/GPUComputationRenderer.js';

constgpuCompute = newGPUComputationRenderer(WIDTH, WIDTH, renderer);
constpositionVariable = gpuCompute.addVariable("texturePosition", positionShader, initialPositionTexture);
// ... 设置依赖关系并初始化


2. Flowfield Animation (流场动画)概念:流场(Flowfield)决定了粒子“怎么动”。它本质上是一个向量场,空间中任意一点都有一个对应的力或速度向量。原理:这通常是在 GPGPU 的速度计算 Shader中实现的。最常用的方法是使用噪声算法 (Perlin Noise / Simplex Noise / Curl Noise)。●根据粒子的当前位置 (x, y, z) 作为输入。●通过噪声函数计算出一个向量。●将这个向量作为速度施加给粒子。●Curl Noise (旋度噪声)特别流行,因为它能产生流体般丝滑、无发散的漩涡效果。Three.js 实现:GPUComputationRenderer的 Shader 中引入噪声函数:

●●●glsl
// GLSL Fragment Shader 伪代码
uniform float time;
voidmain() {
vec2 uv = gl_FragCoord.xy / resolution.xy;
vec4 pos =texture2D(texturePosition, uv);

// 使用 Curl Noise 计算方向
vec3 flowDirection =curlNoise(pos.xyz *0.1+ time *0.1);

// 更新速度
gl_FragColor =vec4(flowDirection,1.0);
}


3. Unreal Bloom (虚幻泛光)概念:Bloom(泛光)能让画面中高亮的部分“溢出”光辉,产生朦胧的发光感。它能极大地提升粒子特效的视觉质感,让光点看起来像真正的光源。”Unreal” 指的是一种特定的 Bloom 算法(源自 Unreal Engine 4),它通过多级降采样和升采样(Mipmaps)来实现非常高效且柔和的大范围模糊。Three.js 实现:Three.js 的EffectComposer体系中直接提供了UnrealBloomPass。1.设置 Composer:创建EffectComposer替代默认的renderer.render。2.添加 Pass:RenderPass: 渲染基础场景。▪UnrealBloomPass: 添加泛光。

●●●javascript
import{ UnrealBloomPass }from'three/examples/jsm/postprocessing/UnrealBloomPass.js';

constbloomPass = newUnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5, // strength (强度)
0.4, // radius (半径)
0.85// threshold (阈值,只有亮度超过0.85的像素才会发光)
);
composer.addPass(bloomPass);

提示:为了让粒子发光,粒子的材质颜色通常需要设置得非常亮(例如颜色值大于1.0),或者配合 HDR 环境。


4. Chromatic Aberration (色差/色散)概念:模拟现实摄影中镜头无法将所有颜色的光聚焦在同一点产生的瑕疵。通常表现为画面边缘出现红、绿、蓝颜色的分离(边缘红蓝溢出)。在数字艺术中,它被用来增加“真实感”、“故障感(Glitch)”或“速度感”。原理:在后处理 Shader 中,分别采样 R、G、B 三个通道,但给它们不同的坐标偏移量。偏移量通常与距离屏幕中心的距离成正比。Three.js 实现:这通常需要自定义ShaderPass,或者使用第三方库如postprocessing(vanruesc)。

●●●glsl
// GLSL 简单逻辑
uniform sampler2D tDiffuse;// 屏幕画面
uniform vec2 resolution;

voidmain() {
vec2 uv = gl_FragCoord.xy / resolution;
// 计算到中心的距离
vec2 dist = uv -0.5;

// 偏移量
vec2 offset = dist *0.02;// 0.02 是色差强度

float r =texture2D(tDiffuse, uv + offset).r;
float g =texture2D(tDiffuse, uv).g;// 绿色不动
float b =texture2D(tDiffuse, uv - offset).b;

gl_FragColor =vec4(r, g, b,1.0);
}

在 Three.js 中使用ShaderPass加载这个 Shader 并加入到 composer 链中。


5. Film Grain (胶片颗粒/噪点)概念:模拟老式胶片摄影机在低光环境下产生的随机噪点。作用:1.去色带 (Dithering):在渐变非常细腻的流场中,它可以消除“波纹状”的色彩断层。2.质感:给过于干净的计算机生成图像(CGI)增加粗糙的物理质感。Three.js 实现:同样使用ShaderPass。在片元着色器中,叠加一个基于屏幕坐标和时间的随机高频噪声。

●●●glsl
// 简单的随机函数
floatrandom(vec2 p) {
returnfract(sin(dot(p.xy,vec2(12.9898,78.233))) *43758.5453);
}

voidmain() {
// ... 获取原图颜色 baseColor

// 计算噪声,引入 time 让噪点动起来
float noise =random(uv + time) * strength;

// 叠加噪声 (通常使用 mix 或直接相加)
gl_FragColor = baseColor +vec4(vec3(noise),0.0);
}

Three.js 的 examples 里也有现成的FilmPass可以直接使用。


6. Motion Blur (动态模糊)概念:当物体快速移动时,在人眼或相机快门时间内留下的拖影。对于粒子流场来说,这能极大地增强速度感和连贯性,让粒子看起来像一条条“线”而不是孤立的点。Three.js 实现:在 WebGL 中实现高质量的动态模糊比较昂贵,主要有两种方式:●方法 A: AfterimagePass (残影法 – 简单,常用)原理:每一帧渲染时,不完全清除上一帧的画面,而是将其透明度降低后覆盖在当前帧上。▪优点:性能开销极小。▪缺点:看起来更像“拖尾”而不是物理正确的模糊。▪代码:import { AfterimagePass } from 'three/examples/jsm/postprocessing/AfterimagePass.js';方法 B: Velocity Buffer (基于速度缓冲 – 高级,更真实)原理:渲染场景时,将每个像素的运动速度向量渲染到一个额外的 Framebuffer 中。后处理阶段根据这个速度纹理,沿着速度方向对当前像素进行模糊采样。▪难度:需要修改粒子的材质以输出速度信息,且 Three.js 原生支持较弱,通常建议使用postprocessing库中的MotionBlurEffect


总结:管线流程在 Three.js 的代码结构中,你的渲染循环(Render Loop)大概是这样的:1.GPGPU Update:gpuCompute.compute()-> 更新粒子位置纹理。2.Material Update:将更新后的纹理传给粒子材质的 Uniforms。3.Post-Processing Render:composer.render()。▪EffectComposer内部依次执行:1.RenderPass:画出粒子(此时粒子已经在新位置)。2.UnrealBloomPass:提取高亮粒子,做模糊,叠加回画面(发光)。3.ChromaticAberrationPass:读取发光后的画面,做 RGB 分离。4.FilmGrainPass:给画面盖上一层噪点。5.AfterimagePass:(如果是残影法) 混合上一帧的渲染结果。4.Display:最终结果输出到 Canvas。这套组合拳打下来,原本平平无奇的几个白点,就会变成充满电影质感、流光溢彩的科幻大片效果。
© 版权声明

相关文章