Three.js 雷达波纹效果
效果概述
这个雷达波纹效果具有以下特点:
- 从中心点向外扩散的同心圆波纹(类似投石入水的涟漪)
- 波纹具有渐变的透明度效果
- 支持多个波纹同时存在
- 可通过 GUI 实时调整参数
与传统雷达扫描的区别:
- 传统雷达扫描:一条射线围绕中心旋转,形成扇形扫描区域
- 这个效果:圆形波纹从中心向外扩散,模拟声波或电磁波的传播
RadarPing 函数详解
让我们先看看核心的 RadarPing 函数:
vec3 RadarPing(in vec2 uv, in vec2 center, in float innerTail,
in float frontierBorder, in float timeResetSeconds,
in float radarPingSpeed, float t)
{
vec2 diff = center-uv;
float r = length(diff);
float time = mod(t, timeResetSeconds) * radarPingSpeed;
float ring = smoothstep(time - innerTail, time, r) * (1.0 - smoothstep(time, time + frontierBorder, r));
return vec3(ring);
}
参数解析
uv: 当前像素的纹理坐标center: 雷达中心点位置innerTail: 波纹内侧渐变长度frontierBorder: 波纹外侧边界厚度timeResetSeconds: 波纹循环周期radarPingSpeed: 波纹扩散速度t: 当前时间
核心算法分析
1. 距离计算
vec2 diff = center-uv;
float r = length(diff);
计算当前像素到雷达中心的距离。这是整个效果的基础,因为雷达波纹是以同心圆的形式扩散的。
2. 时间循环处理
float time = mod(t, timeResetSeconds) * radarPingSpeed;
这里使用 mod 函数的原因:
- 循环效果:
mod(t, timeResetSeconds)将时间限制在 0 到timeResetSeconds之间,创造无限循环的效果 - 速度控制:乘以
radarPingSpeed可以控制波纹扩散的快慢 - 重置机制:当时间达到周期上限时自动归零,波纹从中心重新开始
3. 波纹形状生成
float ring = smoothstep(time - innerTail, time, r) * (1.0 - smoothstep(time, time + frontierBorder, r));
这是最关键的部分,让我们分解理解:
第一部分:smoothstep(time - innerTail, time, r)
- 创建波纹的内侧渐变
- 当
r < time - innerTail时,返回 0(完全透明) - 当
r > time时,返回 1(完全不透明) - 在
time - innerTail到time之间平滑过渡
第二部分:(1.0 - smoothstep(time, time + frontierBorder, r))
- 创建波纹的外侧渐变
- 当
r < time时,返回 1(完全不透明) - 当
r > time + frontierBorder时,返回 0(完全透明) - 在
time到time + frontierBorder之间平滑过渡
两部分相乘的效果:
- 只有在特定距离范围内的像素才会显示
- 形成一个从内到外渐变的环形区域
- 随着时间推移,这个环形区域不断向外扩散
为什么使用 smoothstep?
smoothstep 函数是 GLSL 中的内置函数,它提供平滑的 S 型插值曲线。相比于线性插值,它有以下优势:
- 视觉效果更自然:S 型曲线在边界处变化缓慢,中间变化较快,符合人眼对渐变的感知
- 避免硬边缘:直接使用
step函数会产生锐利的边缘,而smoothstep创造平滑过渡 - 性能优化:GPU 对
smoothstep有专门优化,比自定义的平滑函数更高效
多环效果的实现
在主函数中,通过循环创建多个波纹:
for(int i = 0; i < MAX_RINGS; i++){
if (i >= u_ringCount) break;
float timeOffset = float(i) * (resetTimeSec / float(u_ringCount));
vec3 ping = RadarPing(uv, pingCenter, u_gradientRange, 0.00025, resetTimeSec, u_speed, iTime + timeOffset);
totalAlpha += ping.r;
}
关键在于 timeOffset:
- 为每个波纹添加不同的时间偏移
- 确保波纹之间有规律的间隔
- 创造连续扩散的视觉效果
实际应用技巧
1. 参数调优建议
- innerTail (渐变范围):0.05-0.15 之间效果较好
- frontierBorder:设置很小的值(如 0.00025)创造锐利的外边缘
- 速度:根据场景需求调整,游戏中通常 0.1-0.5 合适
2. 性能优化
- 限制最大环数(MAX_RINGS)避免过度绘制
- 使用
discard丢弃完全透明的片元 - 将 alpha 值限制在合理范围内避免过曝
3. 视觉增强
- 可以添加噪声函数增加真实感
- 结合粒子系统模拟雷达探测到的目标
- 添加颜色变化模拟不同强度的信号
总结
RadarPing 函数巧妙地结合了距离计算、时间循环和平滑插值,创造出逼真的雷达扫描效果。mod 函数确保了动画的循环播放,而 smoothstep 函数则提供了自然的渐变过渡。理解这些基础概念后,你就可以创造出各种变化的波纹效果,应用到游戏、数据可视化或艺术创作中。
这种基于数学函数的程序化效果不仅性能优秀,而且高度可控,是现代图形编程中的重要技术。