Three.js 交互式着色器效果 | 三维可视化 / AI 提示词

📋 AI 提示词

prompt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
使用 Three.js 实现**交互式着色器效果**,具体要求:

【核心特效】
- 五种交互模式:涟漪效果、粒子跟随、画笔效果、引力场、声音可视化
- 实时响应鼠标/触摸输入
- 点击产生扩散涟漪
- 鼠标速度影响效果强度

【场景与光照】
- 深蓝色背景 (#0f0f23 → #1e1e3f 径向渐变)
- OrbitControls 自由视角控制
- 自定义着色器实现交互反馈

【交互与控制】
- 鼠标移动:控制效果方向
- 鼠标点击:触发涟漪扩散
- 鼠标拖拽:绘制轨迹
- GUI 面板切换交互类型、调节灵敏度和衰减

【技术要求】
- Three.js 版本 (ES Module)
- 自定义顶点着色器实现交互变形
- 自定义片元着色器实现五种交互效果
- 完整的鼠标和触摸事件处理

🖼️ 效果预览

交互式着色器效果

🎮 案例演示

立即体验


📖 效果拆解

层次 视觉效果 技术实现
基础 3D平面几何体 PlaneGeometry (10×10, 256×256分段)
核心特效 五种交互效果 片元着色器实现涟漪/粒子/画笔/引力/声波
增强细节 点击涟漪扩散 基于点击位置和时间的动态波纹
交互控制 实时响应 鼠标/触摸事件 + 速度追踪

🔧 核心技术点

1. 涟漪效果

为什么需要这个技术:模拟水滴落入水面产生的扩散波纹,是最直观的交互反馈。

glsl
1
2
3
4
5
6
7
8
9
10
11
float rippleEffect(vec2 pos) {
  vec2 clickPos = vec2(uClickX, uClickY);
  float distanceToClick = length(pos - clickPos);
  float waveSpeed = 2.0;
  float waveFront = uTimeSinceClick * waveSpeed;
  float waveWidth = 0.3;
  float wave = smoothstep(waveFront - waveWidth, waveFront, distanceToClick) -
              smoothstep(waveFront, waveFront + waveWidth, distanceToClick);
  wave *= exp(-distanceToClick * 2.0);
  return wave * uMouseDown;
}

2. 粒子跟随效果

为什么需要这个技术:模拟粒子被鼠标吸引并聚集的效果,产生有趣的视觉反馈。

glsl
1
2
3
4
5
6
7
8
float particleFollow(vec2 pos) {
  vec2 mousePos = vec2(uMouseX, uMouseY);
  float distanceToMouse = length(pos - mousePos);
  float attraction = 1.0 / (1.0 + distanceToMouse * 10.0);
  float noise = sin(pos.x * 20.0 + uTime * 3.0) * 0.1;
  attraction += noise;
  return attraction;
}

3. 画笔效果

为什么需要这个技术:模拟鼠标移动时在画布上绘制轨迹的效果。

glsl
1
2
3
4
5
6
7
float brushEffect(vec2 pos) {
  vec2 mousePos = vec2(uMouseX, uMouseY);
  float distanceToMouse = length(pos - mousePos);
  float brushSize = 0.1;
  float brush = 1.0 - smoothstep(0.0, brushSize, distanceToMouse);
  return brush;
}

4. 引力场效果

为什么需要这个技术:模拟黑洞或引力场对周围物质的吸引效果。

glsl
1
2
3
4
5
6
7
8
float gravityField(vec2 pos) {
  vec2 mousePos = vec2(uMouseX, uMouseY);
  float distanceToMouse = length(pos - mousePos);
  float gravity = 1.0 / (distanceToMouse * distanceToMouse + 0.01);
  float angle = atan(pos.y - mousePos.y, pos.x - mousePos.x);
  float swirl = sin(angle * 3.0 + uTime * 2.0) * 0.5 + 0.5;
  return gravity * swirl;
}

5. 鼠标/触摸事件处理

为什么需要这个技术:实现流畅的交互响应,跟踪鼠标位置、速度和点击状态。

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const interactionState = {
  mouseX: 0.0,
  mouseY: 0.0,
  mouseDown: false,
  clickPosition: new THREE.Vector2(0, 0),
  timeSinceClick: 0.0,
  velocity: new THREE.Vector2(0, 0),
};

renderer.domElement.addEventListener('mousemove', (event) => {
  interactionState.mouseX = (event.clientX / window.innerWidth) * 2 - 1;
  interactionState.mouseY = -(event.clientY / window.innerHeight) * 2 + 1;
  const deltaX = interactionState.mouseX - interactionState.dragPosition.x;
  const deltaY = interactionState.mouseY - interactionState.dragPosition.y;
  interactionState.velocity.x = deltaX * 10;
  interactionState.velocity.y = deltaY * 10;
  interactionState.dragPosition.set(interactionState.mouseX, interactionState.mouseY);
});

renderer.domElement.addEventListener('mousedown', (event) => {
  interactionState.mouseDown = true;
  interactionState.clickPosition.set(interactionState.mouseX, interactionState.mouseY);
  interactionState.timeSinceClick = 0.0;
});

6. uniform 变量更新

为什么需要这个技术:将 JavaScript 的交互状态实时传递到着色器。

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function animate() {
  interactionState.timeSinceClick += 0.016;

  material.uniforms.uMouseX.value = interactionState.mouseX;
  material.uniforms.uMouseY.value = interactionState.mouseY;
  material.uniforms.uMouseDown.value = interactionState.mouseDown ? 1.0 : 0.0;
  material.uniforms.uClickX.value = interactionState.clickPosition.x;
  material.uniforms.uClickY.value = interactionState.clickPosition.y;
  material.uniforms.uTimeSinceClick.value = interactionState.timeSinceClick;
  material.uniforms.uVelocityX.value = interactionState.velocity.x;
  material.uniforms.uVelocityY.value = interactionState.velocity.y;

  requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);
}

💡 调试与优化

问题类型 表现形式 解决方案
涟漪不扩散 点击后没有波纹 检查 uTimeSinceClick 是否正常递增
粒子聚集过快 引力场效果过于强烈 增加 distanceToMouse * distanceToMouse 的系数
触摸不支持 移动端无法交互 添加 touchstarttouchmove 事件监听
性能问题 复杂场景帧率低 减少 PlaneGeometry 分段数 (256→128)

🚀 扩展思路

变体效果 核心改动 难度
多点触控 支持多个手指同时产生独立涟漪 ⭐⭐
颜色交互 根据鼠标速度或位置改变颜色 ⭐⭐
轨迹历史 保留鼠标轨迹历史,形成拖尾效果 ⭐⭐
物理模拟 添加粒子系统的物理碰撞 ⭐⭐⭐
导出功能 将交互绘制结果导出为图片 ⭐⭐

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