Threejs项目实战之四:实现地图雷达效果

最终效果

最近事情比较多,今晚难得有空,就抽空完成了一个使用Threejs实现地图雷达扫描效果的程序,下面说下代码实现的原理及核心代码,老规矩,先看下效果图
在这里插入图片描述# 实现原理
通过加载模型文件,实现模型的加载,这里使用的是FBX模型,通过Threejs提供的FBXLoader来加载fbx模型,加载完成后,通过traverse方法遍历模型,并对该模型的子类进行不同的颜色设置,这里主要是对建筑的颜色定义和对地面的颜色定义;然后,通过使用threejs提供的CircleGeometry创建几何体,并设置其材质;最后,通过使用着色器对雷达效果进行渲染,通过调用THREE.Clock()创建一个计时器实现雷达的扫描动画

代码实现

创建项目

使用vite构建工具创建一个vue项目,具体如何创建就不在赘述了,如果你还不知道如何创建项目,建议你先不要看下面的内容了,先看下基础的vue3框架再来阅读下面的内容
创建项目后,删除vite构建工具为我们创建的HelloWord.vue文件和style.css中的样式,删除App.vue中的样式,并在components文件夹下新建DigitalMapView.vue文件
创建完成后的基础代码如下
APP.vue代码

<template>
  <DigitalMapView></DigitalMapView>
</template>
<script setup> 
import DigitalMapView from './components/DigitalMapView.vue';
</script>
<style scoped> 
</style>

style.css中的样式代码如下:
*{ margin: 0; padding: 0; list-style: none; }

DigitalMapView.vue的核心代码

  • 在DigitalMapView.vue的template模板中添加一个div,id设置为scene,作为承载Threejs的容器;
    template模板中代码如下:
<template>
  <div id="scene"></div>
</template>
  • 在script标签中引入threejs、OrbitControls 、FBXLoader 及vue中的onMounted 生命周期函数
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
import { onMounted } from 'vue';
  • 创建场景、相机、灯光、渲染器、控制器等Threejs用到的各个要素
const initScene = () => {
  scene = new THREE.Scene()
  scene.background = new THREE.Color(0xcccccc)
  scene.environment = new THREE.Color(0xcccccc)
}
const initCamera = () => {
  camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000)
  camera.position.set(600, 750, -1221)
  scene.add(camera)
}
// 添加灯光
const initLight = () => {
  const light = new THREE.AmbientLight(0xadadad); // 环境光,soft white light
  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5); // 方向光
  directionalLight.position.set(100, 100, 0);
  scene.add(light);
  scene.add(directionalLight);
} 
const initRenderer = () => {
  renderer = new THREE.WebGLRenderer({ antialias: true })
  renderer.setSize(window.innerWidth, window.innerHeight)
  document.getElementById('scene').appendChild(renderer.domElement)
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
  renderer.setClearColor(new THREE.Color('#32373E'), 1);
}
// 添加控制器
const initControl = () => {
  controls = new OrbitControls(camera, renderer.domElement)
  controls.enableDamping = true
  controls.dampingFactor = 0.25
  controls.enableZoom = true
}
// 渲染循环
const playAnimate = () => {
  const animate = function () {
    requestAnimationFrame(animate) 
    renderer.render(scene, camera)
  }
  animate()
}
  • 添加FBX模型
    使用FBXLoader加载fbx模型
    loader = new FBXLoader()
      loader.load('public/data/shanghai.fbx', (object) => {
        model = object 
        model.traverse((child) => {
         // 设置城市建筑(mesh物体),材质基本颜色
        if (child.name == 'CITY_UNTRIANGULATED') {
          const materials = Array.isArray(child.material) ? child.material : [child.material]
          materials.forEach((material) => {
            // material.opacity = 0.6;
            material.transparent = true;
            material.color.setStyle("#9370DB");
          })
    
        }
        // 设置城市地面(mesh物体),材质基本颜色
        if (child.name == 'LANDMASS') {
          const materials = Array.isArray(child.material) ? child.material : [child.material]
          materials.forEach((material) => {
            // material.opacity = 0.6;
            material.transparent = true;
            material.color.setStyle("#030912");
          })
        }
      })
       scene.add(model) 
    })
    

刷新浏览器,可以看到此时模型已经加载到页面
在这里插入图片描述

  • 雷达效果实现
    首先在场景中绘制一个圆
  const radarData = {
    position: {
      x: 0,
      y: 20,
      z: 0
    },
    radius: 240, 
    color: '#f005f0', 
    opacity: 0.5, 
    speed: 300, 
    followWidth: 220, 
  }
  // 创建几何体
  const circleGeometry = new THREE.CircleGeometry(radarData.radius, 1000)
  const rotateMatrix = new THREE.Matrix4().makeRotationX(-Math.PI / 180 * 90) 
  circleGeometry.applyMatrix4(rotateMatrix)
  // 创建材质
  const material = new THREE.MeshPhongMaterial({
    color: radarData.color,
    opacity: radarData.opacity,
    transparent: true,
  })
  const radar = new THREE.Mesh(circleGeometry, material)

使用着色器渲染雷达效果

  const vertex = `
    varying vec3 vPosition;
    void main() {
      vPosition = position;
  `
  shader.vertexShader = shader.vertexShader.replace('void main() {', vertex)
  const fragment = `
    uniform float uRadius;     
    uniform float uTime;            
    uniform float uSpeed; 
    uniform float uFollowWidth; 
    varying vec3 vPosition;  
    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;
    }
    void main() {
  `

  const fragementColor = `    
    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 ); 
      }
    }    
  `
    shader.fragmentShader = shader.fragmentShader.replace('void main() {', fragment)
    shader.fragmentShader = shader.fragmentShader.replace('gl_FragColor = vec4( outgoingLight, diffuseColor.a );', fragementColor)
  }

最后,通过定义事件来实现雷达扫描的动画效果

 const dt = clock.getDelta();
    time.value += dt; 
    startTime.value += dt;
    if (startTime.value >= startLength.value) {
      startTime.value = startLength.value;
    }

好了,今天就先写到这里,有问题评论区留言,喜欢的小伙伴点赞关注+收藏哦!

  • 19
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: 雷达测控是一种常见的遥感技术,通过使用雷达设备来获取目标物体的位置信息,进而实现目标物体跟踪和测控的功能。three.js是一个强大的JavaScript库,用于在网页上创建和渲染3D图形,而Cesium是一个开源的地理信息系统库,用于创建地球表面的3D可视化。 结合three.js和Cesium,我们可以实现雷达测控的可视化效果。首先,我们需要使用Cesium创建一个地球表面的3D场景,将目标物体的位置数据与地球模型关联起来。Cesium提供了许多API来实现地图的交互和展示功能,我们可以使用这些API来控制地球的旋转、缩放等操作,以及在地球表面上添加其他的标记和图层。 通过three.js的框架,我们可以创建3D模型来代表目标物体。我们可以使用three.js提供的几何体和材质来创建一个雷达设备的模型,并将其放置在Cesium创建的场景中的目标物体的位置上。这样,雷达设备的模型就能够随着地球的旋转和缩放而移动和调整位置。 除了将雷达设备的模型放置在地球表面上,我们还可以通过three.js的灯光和阴影效果,使整个场景更加逼真。我们可以通过调整灯光的位置和强度,使雷达设备的模型有更真实的光照效果,并通过阴影效果来增加场景的深度和立体感。 总之,通过结合three.js和Cesium,我们可以实现雷达测控的可视化效果,提供一个交互性强、真实感强的系统。用户可以通过控制操作来旋转、放大、缩小地球模型,并观察目标物体在地球表面的位置和状态。这样的系统可以为雷达测控提供更直观、更方便的展示和分析平台。 ### 回答2: three.js是一个用于创建和渲染3D图形的JavaScript库,而Cesium是一个用于创建和渲染地理信息的JavaScript库。结合使用这两个库可以实现雷达测控系统。 雷达测控系统中,雷达用于侦测目标物体的位置和运动状态,而测控系统则负责接收雷达的数据,并对目标进行跟踪和分析。在结合three.js和cesium之前,通常需要使用其他的工具或方法将雷达数据进行处理和可视化。但借助three.js和cesium,我们可以更加方便地实现整个雷达测控系统的可视化。 首先,我们可以使用three.js创建雷达的几何模型和纹理材质,以展示雷达设备的外观和形态。可以通过three.js的相机、光照和渲染器等功能,将雷达设备渲染成逼真的3D模型,并将其放置在场景中。 接着,我们可以使用cesium的地理坐标系功能,将雷达设备的位置精确地在地球表面上定位。通过cesium的地球模型,我们可以实现雷达设备的地理信息的可视化显示,包括地形、地图等。可以将地球模型和雷达设备模型进行融合,形成一个整体的测控系统模型。 此外,我们可以通过three.js和cesium提供的API,将雷达数据以点云或网格的形式进行可视化。可以根据雷达测量到的目标物体的距离、速度等信息,将其以点云或网格的形式展示在场景中,并通过三维空间的位置、颜色等属性,对目标物体进行可视化分析和跟踪。 最后,借助three.js和cesium的交互功能,我们可以实现雷达测控系统的交互操作,例如缩放、旋转、选择目标等。通过用户的交互操作,可以对目标物体进行测控系统的控制和调整,进一步提高雷达测控系统的可视化效果和用户体验。 综上所述,借助three.js和cesium,我们可以更加方便地实现雷达测控系统的可视化,包括雷达设备、地球表面的地理信息以及目标物体的可视化分析和跟踪。这种结合使用能够提高雷达测控系统的效率和准确性,同时也提升了用户对系统的理解和操作能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九仞山

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值