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 时间变量

🖼️ 效果预览

Three.js 增强版雷达扫描着色器

🎮 案例演示

立即体验


📖 效果拆解

层次 视觉效果 技术实现
基础 圆形雷达盘 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)

🚀 扩展思路

  1. 目标点标记:添加多个可移动的目标点显示在雷达上
  2. 多雷达叠加:多个雷达同时扫描不同的角度范围
  3. 历史轨迹:保存目标的历史位置形成轨迹线
  4. 3D仰角雷达:扩展到球形或半球形的3D雷达
  5. 敌我识别:添加不同颜色区分友军/敌军目标

📚 相关学习资源


©️ 版权声明

*本文档由 ThreeLab 编辑整理,专注 Three.js 着色器、Web 3D、GIS 可视化技术分享。如需转载,请注明出处。