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 lightconst 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 = truecontrols.dampingFactor = 0.25controls.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.hqwc.cn/news/315215.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【CASS精品教程】CASS11坐标换带方法(单点计算、批量计算)

参考阅读:【Pix4d精品教程】Pix4d中央子午线细化设置(测区跨两个分带) 文章目录 一、坐标换带概述二、CASS坐标换带1. 单点转换2. 批量转换三、应用场景一、坐标换带概述 坐标换带是将一个投影带的平面直角坐标系换算成另外一个投影带的平面直角坐标系的过程。这一过程主要…

selenium3自动化测试(这一篇就够了)——自学篇

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

论文阅读:基于MCMC的能量模型最大似然学习剖析

On the Anatomy of MCMC-Based Maximum Likelihood Learning of Energy-Based Models 相关代码&#xff1a;点击 本文只介绍关于MCMC训练的部分&#xff0c;由此可知&#xff0c;MCMC常常被用于训练EBM。最后一张图源于Implicit Generation and Modeling with Energy-Based Mod…

android开发百度地图api实现定位图标随手机方向转动

该功能的实现依赖于手机中的传感器元件如陀螺仪、加速度计等&#xff0c;具体开发详见android的官方开发文档&#xff1a; 传感器概览 | Android 开发者 | Android Developershttps://developer.android.com/guide/topics/sensors/sensors_overview?hlzh-cn要自定义一个传…

【Bootstrap学习 day7】

Bootstrap按钮 按钮样式 使用.btn相关类实现 <button type"button" class"btn">基本按钮</button> <button type"button" class"btn btn-primary">主要按钮</button> <button type"button" cl…

再见2023,你好2024!

大家好&#xff0c;我是老三&#xff0c;本来今天晚上打算出去转一转&#xff0c;陆家嘴打车实在太艰难了&#xff0c;一公里多的路&#xff0c;司机走了四十分钟&#xff0c;还没到&#xff0c;再加上身体不适&#xff0c;咳嗽地比较厉害&#xff0c;所以还是宅在酒店里&#…

【Linux驱动】设备树模型的LED驱动 | 查询方式的按键驱动

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《Linux驱动》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f36e;设备树模型的LED驱动&#x1f369;设备树文件&#x1f369;驱动程序 &#x1…

OpenCV-12绘制图像

OpenCV提供了许多绘制图像的API&#xff0c;可以在图像上绘制各种图形&#xff0c;例如直线&#xff0c;矩形&#xff0c;圆&#xff0c;椭圆等图形。 一、画直线 利用API line&#xff08;img, pt1, pt2, color, thickness, lineType, shift&#xff09;可以绘制直线。 其中…

都2024年了!你还不知道在Docker中安装jdk?

目录 前言&#xff1a; Docker安装JDK(8) 查看以及安装的镜像 拉取JDK&#xff08;8&#xff09;的镜像文件 ​编辑 运行容器 进入容器 检查安装 如果我的博客帮助到你&#xff0c;麻烦点个小小的赞即可 前言&#xff1a; 在2024年&#xff0c;Docker已经成为了容器化…

Excel文件怎么找回?记牢这3个简单方法!

“我的Excel中有很多重要的数据&#xff0c;但是在清理电脑时&#xff0c;我不小心把表格删除了&#xff0c;有什么方法可以找回Excel文件吗&#xff1f;” 在使用电脑时&#xff0c;我们经常使用Excel处理各种数据。但如果误删除了Excel文件&#xff0c;或者由于其他原因导致文…

杰发科技AC7840——Eclipse环境DMA注意事项

0.序 用 户 使 用 DMA 时 &#xff0c; 所 有 DMA 搬 运 的 SRAM 数 据 都 必 须 存 放 在 SRAM_U 区 (0x20000000~0x2000EFFF) 。 1. 修改办法 第一步&#xff1a; RAM定义 /* Specify the memory areas */ MEMORY {FLASH (rx) : ORIGIN 0x00000000, LENGT…

mysql中释放表空间的几种方式

删除数据命令 DELETE FROM sys_audit_log WHERE create_time < DATE_SUB(DATE(NOW()),INTERVAL 1 MONTH) 删除前表空间信息&#xff1a; 删除后未处理空间 查看实际行数 SELECT COUNT(*) FROM sys_audit_log; 返回结果&#xff1a;4673 执行分析后表统计&#xff1a; A…