vue中使用高德地图自定义掩膜背景结合threejs

技术架构

vue3+高德地图2.0+threejs

代码步骤

这里我们就用合肥市为主要的地区,将其他地区扣除,首先使用高德的webapi的DistrictSearch功能,使用该功能之前记得检查一下初始化的时候是否添加到plugins中,然后搜索合肥市的行政数据。

district.search(targetArea.name, (status, result) => {      if (status === "complete") {        //设置中心点        map.setCenter([result.districtList[0].center.lng, result.districtList[0].center.lat], true);                                                                //整个世界        let outer = [new AMap.LngLat(-360, 90, true), new AMap.LngLat(-360, -90, true), new AMap.LngLat(360, -90, true), new AMap.LngLat(360, 90, true)];                                //合肥市边界信息        let holes = result.districtList[0].boundaries;        let pathArray = [outer];
        // 绘制行政区划        pathArray.push.apply(pathArray, holes);
            // 在合肥市内描边        let polygon1 = new AMap.Polygon({path: [outer],          strokeColor: "#00eeff",          strokeWeight: 5,          fillOpacity: 0,        });                                                                    //添加至地图                                polygon.setPath(pathArray);              map.add(polygon);                                                     }    });  

这里就已经有了整个城市的轮廓。

图片

我们的需求是自定义背景,首先我们需要获取到除了合肥市以外的地区,这里我们使用threejs,版本是0.157.0,大家这里可以安装和我一样的版本保证不会出错,版本太高会有问题,控制台 npm i three@0.157.0,在代码中import * as THREE from "three"导入,这里我们单独将threejs业务代码分出去。​​​​​​​

------继续上面的代码----------
//先获取地图画布的大小const innerHeight = mapRef.value.clientHeight;const innerWidth = mapRef.value.clientWidth;
let options = {    pathArray,    center: [result.districtList[0].center.lng, result.districtList[0].center.lat],    size: {      innerWidth,      innerHeight,    },  };                //这里传入数据,单独写一个js文件来处理threejs业务 ,instace是AMapcreateThreeLayer(instance, map, options);

收集到我们需要的数据之后单独建一个js文件,先安装一个插件叫turf,这个插件非常善于处理地图上的数学、多边型,先 npm i @turf/turf,再导入import * as turf from "@turf/turf,下面开始写逻辑。​​​​​​​

import * as THREE from "three";import * as turf from "@turf/turf";
let glLayer;let camera, renderer, scene, raycaster;let customCoords = null;
/** * @description 创建ThreeLayer */export function createThreeLayer(instance, map, options) {  const { polygon, center, size } = options;
  customCoords = map.customCoords;  // 地图中心转换为墨卡托  const centerCoord = customCoords.lngLatToCoord(center);
  // polygon是传入的多边形坐标,是一个非遮罩区域,outer外边框是整个地图的边界  const outer = polygon[0];  const inner = polygon[1];
  // inner的bbox  const turfPoints = inner.map((item) => [item.lng, item.lat]);  const innerBbox = turf.bbox(turf.polygon([turfPoints]));  // 最小正方形  const squared = turf.square(innerBbox);  // 转为4个点  const squaredPoints = [    [squared[0], squared[1]],    [squared[0], squared[3]],    [squared[2], squared[3]],    [squared[2], squared[1]],  ];
  // 多边形坐标转换为世界中的坐标  const innerCoords = inner.map((item) => {    return {      ...item,      coord: customCoords.lngLatToCoord([item.lng, item.lat]),    };  });  const outerCoords = outer.map((item) => {    return {      ...item,      coord: customCoords.lngLatToCoord([item.lng, item.lat]),    };  });                //世界边界点  const squaredPointsCoords = squaredPoints.map((item) => customCoords.lngLatToCoord(item));                        //——--------------------——------------继续写代码的位置-------------------------           }

这里将我们所有使用的点转换好了之后就可以创建自定义图层了,接下来开始绘制,这里我们准备两张图片,一张贴图,一张法线贴图(让图片凹凸部分感光,让画面更有质感),所有步骤的解释都在注释里面。​​​​​​​

// 背景贴图  const bgTexture = new THREE.TextureLoader().load("static/three/bg.png");  // 法线背景贴图  const normalTexture = new THREE.TextureLoader().load("static/three/bg_normal.png");
if (!glLayer) {    glLayer = new instance.GLCustomLayer({      zIndex: 10,      init: (gl) => {        camera = new THREE.PerspectiveCamera(45, size.innerWidth / size.innerHeight, 100, 1 << 30);
        renderer = new THREE.WebGLRenderer({          context: gl, // 地图的 gl 上下文        });                                        renderer.autoClear = false;        scene = new THREE.Scene();        // 环境光照和平行光        let aLight = new THREE.AmbientLight(0xffffff, 2);        let dLight = new THREE.DirectionalLight(0xffffff);        dLight.intensity = 6;        dLight.position.set(centerCoord[0], -100000, 50000);        dLight.target.position.set(centerCoord[0], centerCoord[1], 0);        dLight.target.updateMatrixWorld(); 
        scene.add(dLight);        scene.add(aLight);
        // 辅助        // const helper = new THREE.DirectionalLightHelper(dLight, 1);        // scene.add(helper);
                // 辅助坐标轴        // const axesHelper = new THREE.AxesHelper(100000);        // scene.add(axesHelper);


        // 创建遮罩区域,遮罩区域 = outer - inner        const maskShape = new THREE.Shape();
        // 创建outer        maskShape.moveTo(outerCoords[0].coord[0], outerCoords[0].coord[1]);        outerCoords.forEach((item) => {          maskShape.lineTo(item.coord[0], item.coord[1]);        });
        // 创建inner        maskShape.holes.push(new THREE.Path());        maskShape.holes[0].moveTo(innerCoords[0].coord[0], innerCoords[0].coord[1]);        innerCoords.forEach((item) => {          maskShape.holes[0].lineTo(item.coord[0], item.coord[1]);        });
        // 信息添加给多边形        const maskGeometry = new THREE.ShapeGeometry(maskShape);
        // 调整纹理坐标 这里是调整贴图偏移和大小        bgTexture.wrapS = THREE.RepeatWrapping;        bgTexture.wrapT = THREE.RepeatWrapping;        bgTexture.repeat.set(120, 120);        bgTexture.offset.set(0.877, 0.275);                                                                               //这里是调整法线贴图的        normalTexture.wrapS = THREE.RepeatWrapping;        normalTexture.wrapT = THREE.RepeatWrapping;        normalTexture.repeat.set(120, 120);        normalTexture.offset.set(0.877, 0.275);
        // 调整 UV        maskGeometry.computeBoundingBox();        const bbox = maskGeometry.boundingBox;        let size1 = new THREE.Vector2();        bbox.getSize(size1);
        const uvAttribute = maskGeometry.attributes.uv;
        for (let i = 0; i < uvAttribute.count; i++) {          const uv = new THREE.Vector2().fromBufferAttribute(uvAttribute, i);          uv.x = (uv.x - bbox.min.x) / size1.x; // uv坐标映射          uv.y = (uv.y - bbox.min.y) / size1.y;          uvAttribute.setXY(i, uv.x, uv.y);        }
        uvAttribute.needsUpdate = true;
        const maskMaterial = new THREE.MeshStandardMaterial({          map: bgTexture,          side: THREE.DoubleSide,          transparent: true,          normalMap: normalTexture,          roughness: 0.5,          metalness: 0.5,        });
        const maskMesh = new THREE.Mesh(maskGeometry, maskMaterial);        scene.add(maskMesh);
        
      },
      render: () => {        let { near, far, fov, up, lookAt, position } = customCoords.getCameraParams();        camera.near = near;        camera.far = far;        camera.fov = fov;        camera.position.set(...position);        camera.up.set(...up);        camera.lookAt(...lookAt);        camera.updateProjectionMatrix();        renderer.render(scene, camera);        renderer.resetState();      },    });
    map.add(glLayer);
    const animate = () => {      map.render();      requestAnimationFrame(animate);    };    animate();
    function onWindowResize() {      camera.aspect = size.innerWidth / size.innerHeight;      camera.updateProjectionMatrix();      renderer.setSize(size.innerWidth, size.innerHeight);    }    window.addEventListener("resize", onWindowResize);  }

下面放出效果图。

图片

因为加上了法线贴图所以他会像这样。

图片

图片

加入高德地图各种特效之后是这样的效果。

图片

素材放在下面了,需要的朋友可以自取哦~

图片

图片

图片

高德开放平台第二期实战案例,三等奖作品

作者:左文韬

仅代表作者个人观点

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

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

相关文章

02、QLExpress从入门到放弃,相关API和文档

QLExpress从入门到放弃,相关API和文档 一、属性开关 public class ExpressRunner {private boolean isTrace;private boolean isShortCircuit;private boolean isPrecise; }/*** 是否需要高精度计算*/ private boolean isPrecise false;高精度计算在会计财务中非常重要&…

二、OSG学习笔记-入门开发

前一章节&#xff1a;一、OSG学习笔记-编译开发环境-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/145513691 一、环境配置 1、VS需要配置头文件路径如下图&#xff1a;&#xff08;$(OSG_INCLUDE)&#xff09; 这里的OSG_INCLUDE,为环境变量名&#xff0…

C++ Primer 语句作用域

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

Windows逆向工程入门之汇编开发框架解析

公开视频 -> 链接点击跳转公开课程博客首页 -> ​​​链接点击跳转博客主页 目录 环境搭建与配置 Visual Studio配置 X86汇编基础框架 基本程序框架 数据定义与内存访问 过程&#xff08;函数&#xff09;定义 汇编框架解析 代码主体解析 完整代码执行 代码逻…

Android ndk兼容 64bit so报错

1、报错logcat如下 2025-01-13 11:34:41.963 4687-4687 DEBUG pid-4687 A #01 pc 00000000000063b8 /system/lib64/liblog.so (__android_log_default_aborter16) (BuildId: 467c2038cdfa767245f9280e657fdb85) 2025…

工业路由器物联网应用,智慧环保环境数据监测

在智慧环保环境数据监测中工业路由器能连接各类分散的传感器&#xff0c;实现多源环境数据集中采集&#xff0c;并通过多种通信网络稳定传输至数据中心或云平台。 工作人员借助工业路由器可远程监控设备状态与环境数据&#xff0c;还能远程配置传感器参数。远程控制设置数据阈…

QT修仙笔记 事件大圆满 闹钟大成

学习笔记 牛客刷题 闹钟 时钟显示 通过 QTimer 每秒更新一次 QLCDNumber 显示的当前时间&#xff0c;格式为 hh:mm:ss&#xff0c;实现实时时钟显示。 闹钟设置 使用 QDateTimeEdit 让用户设置闹钟时间&#xff0c;可通过日历选择日期&#xff0c;设置范围为当前时间到未来 …

MapReduce到底是个啥?

在聊 MapReduce 之前不妨先看个例子&#xff1a;假设某短视频平台日活用户大约在7000万左右&#xff0c;若平均每一个用户产生3条行为日志&#xff1a;点赞、转发、收藏&#xff1b;这样就是两亿条行为日志&#xff0c;再假设每条日志大小为100个字节&#xff0c;那么一天就会产…

拯救者Y9000P双系统ubuntu22.04安装4070显卡驱动

拯救者Y9000P双系统ubuntu22.04安装4070显卡驱动 1. 前情&#xff1a; 1TB的硬盘&#xff0c;分了120G作ubuntu22.04。/boot: 300MB, / : 40GB, /home: 75G, 其余作swap area。 2. 一开始按这个教程&#xff1a;对我无效 https://blog.csdn.net/Eric_xkk/article/details/1…

Redis 数据类型 List 列表

列表类型是⽤来存储多个有序的字符串&#xff0c;如下图所⽰&#xff0c;a、b、c、d、e 五个元素从左到右组成了⼀个有序的列表&#xff0c;列表中的每个字符串称为元素&#xff08;element&#xff09;&#xff0c;⼀个列表最多可以存储 2^32 - 1个元素。在 Redis 中&#xff…

【devops】Macos 轻量化docker解决方案 orbstack | 不用Docker Desktop启动docker服务

一、orbstack OrbStack is the fast, light, and easy way to run Docker containers and Linux machines. It’s a supercharged WSL and Docker Desktop alternative, all in one easy-to-use app. 二、orbstack 的可视化

RabbitMQ消息队列 发送和接受

步骤 1: 安装 RabbitMQ 首先&#xff0c;需要安装 RabbitMQ&#xff0c;并确保它在运行中。 下载erlang语言包OTP。官网地址&#xff1a;Downloads - Erlang/OTP Rabbitmq官网下载地址&#xff1a;Downloading and Installing RabbitMQ — RabbitMQ 安装MQ注意事项&#xf…

2025最新版Node.js下载安装~保姆级教程

1. node中文官网地址&#xff1a;http://nodejs.cn/download/ 2.打开node官网下载压缩包&#xff1a; 根据操作系统不同选择不同版本&#xff08;win7系统建议安装v12.x&#xff09; 我这里选择最新版win 64位 3.安装node ①点击对话框中的“Next”&#xff0c;勾选同意后点…

Spring Boot 3.4 中 MockMvcTester 的新特性解析

引言 在 Spring Boot 3.4 版本中&#xff0c;引入了一个全新的 MockMvcTester 类&#xff0c;使 MockMvc 测试可以直接支持 AssertJ 断言。本文将深入探讨这一新特性&#xff0c;分析它如何优化 MockMvc 测试并提升测试的可读性。 Spring MVC 示例 为了演示 MockMvcTester 的…

WEB攻防-文件下载文件读取文件删除目录遍历目录穿越

目录 一、文件下载漏洞 1.1 文件下载案例&#xff08;黑盒角度&#xff09; 1.2 文件读取案例&#xff08;黑盒角度&#xff09; 二、文件删除 三、目录遍历与目录穿越 四、审计分析-文件下载漏洞-XHCMS 五、审计分析-文件读取漏洞-MetInfo-函数搜索 六、审计分析-…

01.Docker 概述

Docker 概述 1. Docker 的主要目标2. 使用Docker 容器化封装应用程序的意义3. 容器和虚拟机技术比较4. 容器和虚拟机表现比较5. Docker 的组成6. Namespace7. Control groups8. 容器管理工具9. docker 的优缺点10. 容器的相关技术 docker 官网: http://www.docker.com 帮助文档…

IDEA中常见问题汇总

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

基于蜘蛛蜂优化算法的无人机集群三维路径规划Matlab实现

代码下载&#xff1a;私信博主回复基于蜘蛛蜂优化算法的无人机集群三维路径规划Matlab实现 《基于蜘蛛蜂优化算法的无人机集群三维路径规划》 摘要 本研究针对无人机集群三维路径规划问题&#xff0c;提出了一种基于蜘蛛蜂优化算法的解决方案。以5个无人机构成的集群为研究对…

路由过滤方法与常用工具

路由过滤 定义&#xff1a;路由器在发布或者接收消息时&#xff0c;可能需要对路由信息进行过滤。 作用&#xff1a;控制路由的传播与生成&#xff1b;节省设备和链路资源消耗&#xff0c;保护网络安全。 举例&#xff1a;学习汇总后的路由&#xff0c;而不学习汇总时的明细路由…

仿 RabbitMQ 实现的简易消息队列

文章目录 项目介绍开放环境第三⽅库介绍ProtobufMuduo库 需求分析核⼼概念实现内容 消息队列系统整体框架服务端模块数据管理模块虚拟机数据管理模块交换路由模块消费者管理模块信道&#xff08;通信通道&#xff09;管理模块连接管理模块 客户端模块 公共模块日志类其他工具类…