雷达扫描2

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 实现**增强版雷达扫描着色器**,具体要求:
【核心特效】
- 360度旋转扫描线
- 扫描尾迹渐变消失效果
- 雷达范围网格标记
- 角度刻度线显示
【场景与光照】
- 深蓝色背景 (#0a1929)
- 从上方俯视角度 (相机位置 y=800)
- OrbitControls 轨道控制器
- 自定义材质实现扫描动画
【交互与控制】
- OrbitControls 鼠标拖拽旋转
- 鼠标滚轮缩放
- GUI 面板调节雷达颜色、扫描速度、尾迹宽度、透明度等
【技术要求】
- Three.js 版本 (ES Module)
- MeshBasicMaterial + onBeforeCompile 实现自定义着色器
- 使用 `atan()` 函数计算角度
- 实时更新的 uniform 时间变量
🖼️ 效果预览
🎮 案例演示
📖 效果拆解
| 层次 | 视觉效果 | 技术实现 |
|---|---|---|
| 基础 | 圆形雷达盘 | CircleGeometry (半径240) + 旋转矩阵 |
| 核心特效 | 旋转扫描线 | 片元着色器基于角度差的尾迹效果 |
| 增强细节 | 网格和刻度线 | GridHelper + 自定义角度标记 |
| 交互控制 | 参数实时调节 | GUI 控制颜色/速度/宽度/透明度 |
🔧 核心技术点
1. 扫描线角度计算
为什么需要这个技术:实现雷达扫描线绕中心旋转的效果,基于片段与X轴的角度差。
glsl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
float calcAngle(vec3 oFrag) {
float fragAngle;
const vec3 ox = vec3(1, 0, 0);
float dianji = oFrag.x * ox.x + oFrag.z * ox.z;
float oFrag_length = length(oFrag);
float ox_length = length(ox);
float yuxian = dianji / (oFrag_length * ox_length);
fragAngle = acos(yuxian);
fragAngle = degrees(fragAngle);
if(oFrag.z > 0.0) {
fragAngle = -fragAngle + 360.0;
}
float scanAngle = uTime * uSpeed - floor(uTime * uSpeed / 360.0) * 360.0;
float angle = scanAngle - fragAngle;
if(angle < 0.0) {
angle = angle + 360.0;
}
return angle;
}
2. 尾迹渐变透明度
为什么需要这个技术:让扫描线后面产生逐渐消失的尾迹效果,增加视觉美感。
glsl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void main() {
#include <opaque_fragment>
if(length(vPosition) == 0.0 || length(vPosition) > uRadius - 2.0) {
gl_FragColor = vec4(outgoingLight, diffuseColor.a);
} else {
float angle = calcAngle(vPosition);
if(angle < uFollowWidth) {
float opacity = 1.0 - angle / uFollowWidth;
gl_FragColor = vec4(outgoingLight, diffuseColor.a * opacity);
} else {
gl_FragColor = vec4(outgoingLight, 0.0);
}
}
}
3. 圆形几何体旋转
为什么需要这个技术:将平面圆形变为水平放置的雷达盘面。
javascript
1
2
3
const circleGeometry = new THREE.CircleGeometry(radarData.radius, 1000);
const rotateMatrix = new THREE.Matrix4().makeRotationX((-Math.PI / 180) * 90);
circleGeometry.applyMatrix4(rotateMatrix);
4. 雷达范围网格标记
为什么需要 this技术:创建同心圆网格和角度刻度线,增强雷达的专业感。
javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function createRadarMarkers(radius, count) {
const markers = new THREE.Group();
const material = new THREE.LineBasicMaterial({ color: 0x226644, opacity: 0.3, transparent: true });
for(let i = 1; i <= count; i++) {
const circle = new THREE.RingGeometry(radius * i / count, radius * i / count + 1, 100);
const edges = new THREE.EdgesGeometry(circle);
const line = new THREE.LineSegments(edges, material);
line.rotation.x = Math.PI / 2;
markers.add(line);
}
for(let i = 0; i < 12; i++) {
const angle = (i * 30) * Math.PI / 180;
const lineGeometry = new THREE.BufferGeometry().setFromPoints([
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(Math.cos(angle) * radius, 0, Math.sin(angle) * radius)
]);
const line = new THREE.Line(lineGeometry, material);
markers.add(line);
}
return markers;
}
5. GUI 控制面板
为什么需要这个技术:提供友好的交互界面,实时调节雷达参数。
javascript
1
2
3
4
5
6
7
const gui = new GUI();
gui.addColor('radarColor', '#00ff00').name('雷达颜色');
gui.addColor('scanColor', '#00ffff').name('扫描颜色');
gui.add(radarData, 'radius', 100, 500).name('雷达半径');
gui.add(radarData, 'speed', 50, 600).name('扫描速度');
gui.add(radarData, 'followWidth', 30, 300).name('尾迹宽度');
gui.add(radarData, 'opacity', 0.1, 1.0).name('透明度');
💡 调试与优化
| 问题类型 | 表现形式 | 解决方案 |
|---|---|---|
| 扫描线方向错误 | 扫描线旋转方向与预期相反 | 修改 scanAngle 的符号 |
| 尾迹不对称 | 尾迹在一侧过宽 | 检查 angle < uFollowWidth 条件是否正确 |
| 中心点闪烁 | 原点处颜色异常 | 添加 length(vPosition) == 0.0 判断 |
| 性能问题 | 复杂场景帧率低 | 减少 CircleGeometry 分段数 (1000→500) |
🚀 扩展思路
- 目标点标记:添加多个可移动的目标点显示在雷达上
- 多雷达叠加:多个雷达同时扫描不同的角度范围
- 历史轨迹:保存目标的历史位置形成轨迹线
- 3D仰角雷达:扩展到球形或半球形的3D雷达
- 敌我识别:添加不同颜色区分友军/敌军目标
📚 相关学习资源
©️ 版权声明
*本文档由 ThreeLab 编辑整理,专注 Three.js 着色器、Web 3D、GIS 可视化技术分享。如需转载,请注明出处。







京公网安备 11010502038735号
💬 评论区
评论功能即将上线,敬请期待!