网格光斑扩散效果
🎯 提示词
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 创建大规模点阵,实现高性能渲染。
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. 扩散光环着色器
根据距离中心点的距离计算扩散效果,支持圆形和横向两种模式。
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 定义加号形状,通过合并多个几何体优化性能。
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 实现平滑的相机动画过渡。
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 编辑整理,如需转载,请注明出处。
💬 评论区
评论功能即将上线,敬请期待!