网格光斑扩散效果

🎯 提示词

PROMPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
使用 Three.js 实现网格光斑扩散效果,具体要求:

【核心特效】
- 点阵上的圆形/横向扩散光环
- 网格线与加号标记组合背景
- GSAP 驱动的相机动画

【场景与光照】
- 深蓝色雾效背景
- 海洋纹理地面
- 纯视觉效果,无需光源

【交互与控制】
- OrbitControls 视角控制
- 自动循环动画
- 响应式窗口适配

【技术要求】
- Three.js 最新版本
- GSAP 动画库
- PointsMaterial + onBeforeCompile 着色器扩展

📖 效果拆解

层次 视觉效果 技术实现
基础 海洋纹理地面 PlaneGeometry + 纹理映射
网格层 线条网格 + 加号标记 GridHelper + ShapeGeometry
核心特效 动态扩散光环 Points + 自定义着色器
动画层 相机路径动画 GSAP timeline

🔧 核心技术点

1. 点阵布局生成

使用 BufferGeometry 创建大规模点阵,实现高性能渲染。

JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
const rows = opt.pointLayout.row, cols = opt.pointLayout.col;
const posArr = new Float32Array(rows * cols * 3);
for (let i = 0; i < rows * cols; i++) {
  const r = i % rows, c = Math.floor(i / rows);
  posArr[i * 3]     = (r / (rows - 1)) * opt.gridSize - opt.gridSize / 2;
  posArr[i * 3 + 1] = 0;
  posArr[i * 3 + 2] = (c / (cols - 1)) * opt.gridSize - opt.gridSize / 2;
}
const pointGeo = new THREE.BufferGeometry();
pointGeo.setAttribute('position', new THREE.BufferAttribute(posArr, 3));

2. 扩散光环着色器

根据距离中心点的距离计算扩散效果,支持圆形和横向两种模式。

GLSL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
uniform float uTime, uSpeed, uWidth, uDir;
uniform vec3 uColor;

void main() {
  float radius = uTime * uSpeed;
  float width  = min(uWidth, uTime * 5.0);
  vec2  center = vec2(0.0);
  float dist   = uDir == 1.0 ? abs(vPos.x) : distance(vPos.xz, center);

  if (dist > radius && dist < radius + 2.0 * width) {
    float pct = dist < radius + width
      ? (dist - radius) / width
      : (dist - radius - width) / width;
    vec3 outCol = dist < radius + width
      ? mix(outgoingLight, uColor, pct)
      : mix(uColor, outgoingLight, pct);
    gl_FragColor = vec4(outCol, diffuseColor.a);
  } else {
    gl_FragColor = vec4(outgoingLight, diffuseColor.a);
  }
}

3. 加号形状批量生成

使用 Shape 定义加号形状,通过合并多个几何体优化性能。

JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const plusGeoArr = [];
for (let r = 0; r <= opt.gridDivision; r++) {
  for (let c = 0; c <= opt.gridDivision; c++) {
    const shape = new THREE.Shape([
      new THREE.Vector2(-armLen, -lineW), new THREE.Vector2(-lineW, -lineW),
      new THREE.Vector2(-lineW, -armLen), new THREE.Vector2(lineW, -armLen),
      new THREE.Vector2(lineW, -lineW),   new THREE.Vector2(armLen, -lineW),
      new THREE.Vector2(armLen, lineW),   new THREE.Vector2(lineW, lineW),
      new THREE.Vector2(lineW, armLen),   new THREE.Vector2(-lineW, armLen),
      new THREE.Vector2(-lineW, lineW),   new THREE.Vector2(-armLen, lineW)
    ]);
    plusGeoArr.push(
      new THREE.ShapeGeometry(shape).translate(-half + r * cellSize, -half + c * cellSize, 0)
    );
  }
}
const plusMesh = new THREE.Mesh(mergeGeometries(plusGeoArr), ...);

4. 相机路径动画

使用 GSAP timeline 实现平滑的相机动画过渡。

JAVASCRIPT
1
2
3
gsap.timeline()
  .to(camera.position, { duration: 2.5, x: -20.46, y: 19.30, z: 58.38, ease: 'circ.out' })
  .to(camera.position, { duration: 2.5, x: -0.25,  y: 12.40, z: 14.65, ease: 'circ.out' });

💡 调试与优化

问题类型 表现形式 解决方案
点阵渲染异常 点大小不一致或闪烁 调整 sizeAttenuation 参数,禁用透视衰减
性能问题 大量点导致帧率下降 使用 InstancedMesh 替代 Points,或降低点密度
纹理加载失败 地面显示黑色 检查纹理路径和跨域配置
动画循环不流畅 时间重置时有跳变 使用 mod() 函数实现平滑循环

🚀 扩展思路

变体效果 核心改动 难度
多中心扩散 添加多个扩散源,实现波纹干涉效果 ⭐⭐
颜色渐变 扩散环颜色随时间变化
交互式触发 点击位置作为新的扩散中心 ⭐⭐
高度变化 扩散时带动顶点高度变化 ⭐⭐⭐

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