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

news2024/11/18 12:33:29

目录

  • 最终效果
  • 代码实现
    • 创建项目
    • 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;
    }

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

专业服务新篇章:ToB行业运营达人的能力与策略

又逢年底&#xff0c;这两天冷空气南袭&#xff0c;深圳的天气也转为湿冷&#xff0c;又到了年终总结复盘的时候了&#xff0c;其实这样的天气挺适合做深度的思考&#xff0c;清冷的空气&#xff0c;可以让人保持清醒。 月初市场同事希望我写点东西&#xff0c;题目内容自拟&a…

7-验证码识别

文章目录 验证码识别1、验证码的用途和分类验证码的作用验证身份验证行为 验证码的类型静态验证码&#xff1a;图片验证码问答式验证码问答式验证码行为式验证码&#xff1a;点击行为式验证码&#xff1a;拖动间接式验证码&#xff1a;短信、邮件、语音电话无感验证码 2、验证码…

2023年12月青少年软件编程Python等级考试(三级)真题试卷

2023年12月青少年软件编程Python等级考试&#xff08;三级&#xff09;真题试卷 题目总数&#xff1a;38 总分数&#xff1a;100 选择题 第 1 题 单选题 一个非零的二进制正整数&#xff0c;在其末尾添加两个“0”&#xff0c;则该新数将是原数的&#xff1f;&#x…

虹科方案丨从困境到突破:TigoLeap方案引领数据采集与优化变革

来源&#xff1a;虹科工业智能互联 虹科方案丨从困境到突破&#xff1a;TigoLeap方案引领数据采集与优化变革 原文链接&#xff1a;https://mp.weixin.qq.com/s/H3pd5G8coBvyTwASNS_CFA 欢迎关注虹科&#xff0c;为您提供最新资讯&#xff01; 导读 在数字化工厂和智能制造时…

mcu与上位机通讯数据传输测速

问题 如何测量mcu与上位机通讯数据传输速度&#xff1f;&#xff08;串口、USB&#xff09; 解决 可以借助Bus Hound 将显示时间戳勾上。 发送一段固定长度的数据&#xff0c;然后除起始和结束的时间差 最后计算即可。

xadmin-plus

python之Xadmin-plus是什么&#xff1f; xadmin-plus: xadmin的django3.2版本支持。 Xadmin是一个非常优秀的Django Admin插件&#xff0c;可惜的是已经停止更新。Xadmin-plus对其进行了升级兼容。支持python3.10、Django3.2。 特性 Django Admin直接替换基于Twitter Boots…

安装Keras用于影像分割

conda create -n tfkears2024 python3.9.18 activate tfkeras2024 pip install tensorflow-gpu2.9.0 pip install keras pip install scipy pip install ipykernel ipython python -m ipykernel install --name tfkears2024

深度生成模型之GAN基础 ->(个人学习记录笔记)

文章目录 深度生成模型之GAN基础生成对抗网络1. 生成对抗网络如何生成数据2. 生成对抗原理3. GAN的核心优化目标4. D的优化5. GAN的理想状态6. GAN的训练7. 梯度不稳定与模式崩塌(collapse mode)问题8. 梯度消失问题 深度生成模型之GAN基础 生成对抗网络 1. 生成对抗网络如何…

【华为机试】2023年真题B卷(python)-靠谱的车

一、题目 题目描述&#xff1a; 程序员小明打了一辆出租车去上班。出于职业敏感&#xff0c;他注意到这辆出租车的计费表有点问题&#xff0c;总是偏大。 出租车司机解释说他不喜欢数字4&#xff0c;所以改装了计费表&#xff0c;任何数字位置遇到数字4就直接跳过&#xff0c;其…

关于使用 @iconify/iconify图标库组件在vite中的使用

Iconify 是最通用的图标框架&#xff0c;将各种图标库的图标集中在这里的一个组件库&#xff0c;例如ant-design,element-ui等 网站地址如下 https://iconify.design/getting-started/ 使用过程如下 npm install iconify/iconify -S npm install vite-plugin-purge-icons icon…

【SpringBoot3】命令行运行jar包报错可能的一些原因

端口号冲突&#xff1a; 有其他的web程序在运行&#xff0c;占用了8080端口没有主清单属性&#xff1a; 在打包jar包前&#xff0c;没有加入打包的插件spring-boot-maven-plugin&#xff0c;参考1.SpringBoot入门的第一个完整小项目&#xff08;新手保姆版教会打包&#xff09;…

Dockerfile与DockerCompose

Docker的Image结构是怎样的&#xff1f; 镜像是将应用程序 及其需要的 系统函数库、环境、配置、依赖 打包而成。 镜像结构 入口&#xff08; Entrypoint &#xff09; 镜像运行入口&#xff0c;一般是程序启动的脚本和参数 层&#xff08; Layer &#xff09; 在BaseImage基…

Alibaba Cloud Linux镜像操作系统详解(全方位解析)

Alibaba Cloud Linux是基于龙蜥社区OpenAnolis龙蜥操作系统Anolis OS的阿里云发行版&#xff0c;针对阿里云服务器ECS做了大量深度优化&#xff0c;Alibaba Cloud Linux由阿里云官方免费提供长期支持和维护LTS&#xff0c;Alibaba Cloud Linux完全兼容CentOS/RHEL生态和操作方式…

Linux 进程(五) 调度与切换

概念准备 当一个进程放在cpu上运行时&#xff0c;是必须要把进程的代码跑完才会进行下一个进程吗&#xff1f;答案肯定是 不对。现在的操作系统都是基于时间片轮转执行的。 时间片&#xff08;timeslice&#xff09;又称为“量子&#xff08;quantum&#xff09;”或“处理器片…

设计模式之原型模式【创造者模式】

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

数据库云平台新数科技完成B轮融资,打造全链路智能化数据库云平台

数据库云平台软件厂商「北京新数科技有限公司」&#xff08;以下简称「新数科技」&#xff09;已于2023年完成B1轮和B2轮融资&#xff0c;分别由渤海创富和彬复资本投资&#xff1b;义柏资本担任本轮融资独家财务顾问。 新数科技成立于2014年&#xff0c;当前产品矩阵包括数据库…

120基于matlab的LMS自适应滤波算法

基于matlab的LMS自适应滤波算法&#xff0c;如、解相关LMS算法&#xff0c;滤波型LMS算法&#xff0c;变换域LMS算法&#xff0c;输出滤波前后及学习曲线图。数据可更换自己的&#xff0c;程序已调通&#xff0c;可直接运行。 120自适应滤波算法变换域LMS算法 (xiaohongshu.com…

解决Android AAPT: error: resource android:attr/lStar not found. 问题

错误信息 /xxx/gjc/.gradle/caches/transforms-2/files-2.1/930c42acd29d295ce5bc495c3b84423e/core-1.9.0/res/values/values.xml:104:5-113:25: AAPT: error: resource android:attr/lStar not found. not found 资源位置 场景 原Android studio中的项目都是在git上面拉的老项…

cad基础知识1

cad&#xff1a; 点移动会变成线&#xff0c;线移动会变成面&#xff0c;面移动会变成一个实体 f7: 取消cad里的网格 f12: 动态输入 dim&#xff1a;更加智能的标准两端点的距离。 f8:如果按了f8&#xff0c;上下左右都是一条直线&#xff0c;不会变歪。 f9: 开启捕捉模式。 …

实验笔记之——基于windows复现Instant-NGP

之前博客对NeRF-SLAM进行了调研&#xff0c;本博文先复现一下Intant-NGP。 学习笔记之——NeRF SLAM&#xff08;基于神经辐射场的SLAM&#xff09;-CSDN博客文章浏览阅读851次&#xff0c;点赞22次&#xff0c;收藏21次。NeRF 所做的任务是 Novel View Synthesis&#xff08;…