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

目录

  • 最终效果
  • 代码实现
    • 创建项目
    • DigitalMapView.vue的核心代码

最终效果

最近事情比较多,今晚难得有空,就抽空完成了一个使用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;
    }

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/279208.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【模拟电路】常见电子元器件

一、常见电子元器件 二、电阻器 三、电容器 四、电感器 五、电容电感组成LRC振荡电路 六、保险丝、熔断器 七、锂电池 八、接插件 九、蜂鸣器 立创商城_一站式电子元器件采购自营商城-嘉立创电子商城 华秋商城(原"华强芯城")官网_电子元器件采购网_自营现货电子元器…

Jupyter Notebook又一地理数据可视化扩展!

本次分享一个Jupyter Notebook地理数据可视化扩展&#xff1a;pyl7vp pyl7vpPythonl7vp&#xff0c;如其名&#xff0c;是l7vp在Python3方向的封装&#xff0c;l7vp是蚂蚁集团AntV数据可视化团队开发的地理空间智能应用研发开源平台。 通过pyl7vp可在Jupyter Notebook中轻松完…

大模型系列:OpenAI使用技巧_使用文本向量化Embeding进行分类

文章目录 使用文本向量化Embeding进行分类使用文本向量进行零样本Zero Shot分类 使用文本向量化Embeding进行分类 有许多方法可以对文本进行分类。本笔记本分享了使用嵌入进行文本分类的示例。对于许多文本分类任务&#xff0c;我们已经看到微调模型比嵌入效果更好。请参见微调…

命令模式-举例

开关和电灯之间并不存在直接耦合关系&#xff0c;在命令模式中&#xff0c;发送者与接收者之间引入了新的命令对象&#xff0c;将发送者的请求封装在命令对象中&#xff0c;再通过命令对象来调用接收者的方法。 命令模式的主要缺点如下&#xff1a; 使用命令模式可能会导致某…

Android 13 - Media框架(27)- ACodec(五)

前面几节我们了解了OMXNodeInstance是如何处理setPortMode、allocateBuffer、useBuffer的&#xff0c;这一节我们再回到ACodec&#xff0c;来看看 ACodec start 的其他部分。 我们首先来回顾一下&#xff0c;ACodec start 的状态切换以及处理的事务&#xff0c;我们用一张不太准…

sudo: /usr/bin/sudo must be owned by uid 0 and have the setuid bit set问题解决方案

sudo: /usr/bin/sudo must be owned by uid 0 and have the setuid bit set问题解决方案 当我们使用sudo su切换权限时提示错误&#xff1a; sudo: /usr/bin/sudo must be owned by uid 0 and have the setuid bit set该错误出现原因&#xff1a;是因为/usr/bin/sudo的权限被…

GPT4All : 便捷易用的本地智能问答推理软件(乱记)

安装与使用 去官网 https://gpt4all.io/index.html下载可执行文件。 打开应用即可看到是否共享数据的选项&#xff1a; 然后自动进入模型下载界面 测试 内存占用 缺点&#xff1a;在我本地的轻薄本上运行时&#xff0c;风扇会有轻微噪声&#xff0c;关闭软件很久都没停止。…

详解Vue3中的常见的监听事件click、input和change

本文主要介绍Vue3中的常见的监听事件click、input和change。 目录 一、click点击事件二、input输入事件三、change改变事件 在Vue3中&#xff0c;常见的监听事件有以下几种&#xff1a; 一、click点击事件 click事件是最常见的用户交互事件之一。它在元素被点击时触发&#xf…

简单了解SQL堆叠注入与二次注入(基于sqllabs演示)

1、堆叠注入 使用分号 ; 成堆的执行sql语句 以sqllabs-less-38为例 ?id1 简单测试发现闭合点为单引号 ?id1 order by 3 ?id1 order by 4使用order by探测发现只有三列&#xff08;字段数&#xff09; 尝试简单的联合注入查询 ?id-1 union select 1,database(),user()-…

【Linux系统】文件fd

一.预备知识 文件内容属性进程如果想要访问文件&#xff0c;必须先打开文件&#xff0c;即先将其加载到内存&#xff0c;这个工作由操作系统完成一个进程可以打开多个文件&#xff0c;多个进程可以打开多个文件操作系统要想对这么多打开的文件进行管理&#xff0c;必须“先描述…

4~20mA恒流源 --PLC自控控制

输出部分不接地 1.1&#xff0c; 常规恒流源的方式 用采样电阻 * 电流 控制电压的方式。 负载电阻 * 电流 < 工作电压 1.2&#xff0c;根据运放高阻的特性 Ir Ui/ R, Ir IL, 最大输出电流限制于 RL * Il < Ui. 输出部分接地&#xff0c;工程上更多是用于豪兰德恒流源…

基于yolov2深度学习网络的血细胞检测算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1YOLOv2算法原理 4.2 YOLOv2网络结构 4.3 血细胞检测算法实现 数据集准备 数据预处理 网络训练 模型评估与优化 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MAT…

Can‘t locate IPC/Cmd.pm in @INC (@INC contains:解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

18国签署,全球首份《安全AI系统开发指南》发布

内容概述&#xff1a; 2023年11月27日&#xff0c;美国、英国和其他十几个国家公布了首份关于如何保护AI免受流氓行为侵害的详细国际协议《安全AI系统开发指南》&#xff0c;敦促企业打造“设计安全”的AI系统。协议由英国国家网络安全中心&#xff08;NCSC&#xff09;主导&a…

【Java 进阶篇】深入浅出 Jedis 连接池与工具类

​ 在现代的软件开发中&#xff0c;高效地与数据存储系统进行交互是至关重要的。而对于 Redis 这样的高性能键值存储系统&#xff0c;连接池成为了一个不可或缺的工具。本文将围绕 Jedis 连接池及其工具类展开详细解说&#xff0c;让我们一起揭开连接池的神秘面纱。 走进 Red…

m3u8网络视频文件下载方法

在windows下&#xff0c;使用命令行cmd的命令下载m3u8视频文件并保存为mp4文件。 1.下载ffmpeg&#xff0c;访问FFmpeg官方网站&#xff1a;https://www.ffmpeg.org/进行下载 ffmpeg下载&#xff0c;安装&#xff0c;操作说明 https://blog.csdn.net/m0_53157282/article/det…

鸿蒙OS应用开发之气泡提示

前面学习了弹窗提示,其实有时候只是想在旁边做一些说明,那么采用弹窗的方式就比较麻烦一些,这时可以采用系统里面的气泡提示方式。 系统也提供了几种方式弹出气泡提示,最简单的一种是采用bindPopup属性。它的定义如下: 在后面的参数设置里,也是比较复杂的形式。我们先来演…

【滑动窗口】【差分数组】C++算法:K 连续位的最小翻转次数

作者推荐 动态规划 多源路径 字典树 LeetCode2977:转换字符串的最小成本 本题涉及知识点 滑动窗口 差分数组 LeetCode995: K 连续位的最小翻转次数 给定一个二进制数组 nums 和一个整数 k 。 k位翻转 就是从 nums 中选择一个长度为 k 的 子数组 &#xff0c;同时把子数组中…

Halcon颜色通道的处理decompose3/image_to_channels/channels _to _image

Halcon颜色通道的处理 文章目录 Halcon颜色通道的处理一. 图像的通道二. 访问通道1.访问通道2.获取通道的数量 三. 通道分离与合并1. decompose3算子2. image_to_channels 算子3. compose3算子4. channels_to_image算子 四. 处理RGB信息 由于彩色图像通常包含不止一个通道&…

@Zabbix监控网络设备Trap接口UPDOWN关联告警配置

网络设备Trap接口UPDOWN关联告警配置 文章目录 网络设备Trap接口UPDOWN关联告警配置SNMPTrap描述1.监控平台监控项配置2.监控平台日志接收3.监控平台触发器配置4.监控平台触发器功能测试1&#xff09;告警触发2&#xff09;告警恢复 5.告警解析 SNMPTrap描述 在Zabbix中&#x…