Cesium 模型压平

最近整理了下手上的代码,以下是对模型压平的说明。

原理是使用了customShader来重新设置了模型的着色器,通过修改模型顶点的坐标来实现了压平。

废话不多说,下面上代码:

/*** @class* @description 3dtiles模型压平*/
class Flat {/*** * @param {Cesium.Cesium3DTileset} tileset 三维模型* @param {Object} opt * @param {Number} opt.flatHeight 压平高度 */constructor(tileset, opt) {if (!tileset) return;this.tileset = tileset;this.opt = opt || {};this.flatHeight = this.opt.flatHeight || 0;this.center = tileset.boundingSphere.center.clone();this.matrix = Cesium.Transforms.eastNorthUpToFixedFrame(this.center.clone());this.localMatrix = Cesium.Matrix4.inverse(this.matrix, new Cesium.Matrix4());// 多面的坐标数组this.regionList = [];// 多个面坐标转为局部模型坐标this.localPositionsArr = [];}/*** 添加压平面* @param {Object} attr 参数* @param {Cesium.Cartesian3[]} attr.positions 压平面坐标* @param {Number} attr.height 压平深度,当前不支持单独设置* @param {Number} attr.id 唯一标识*/addRegion(attr) {let { positions, height, id } = attr || {};// this.flatHeight = height;if (!id) id = (new Date()).getTime() + "" + Number(Math.random() * 1000).toFixed(0);this.regionList.push(attr);for (let i = 0; i < this.regionList.length; i++) {let item = this.regionList[i];const positions = item.positions;let localCoor = this.cartesiansToLocal(positions);this.localPositionsArr.push(localCoor);}const funstr = this.getIsinPolygonFun(this.localPositionsArr);let str = ``;for (let i = 0; i < this.localPositionsArr.length; i++) {const coors = this.localPositionsArr[i];const n = coors.length;let instr = ``;coors.forEach((coordinate, index) => {instr += `points_${n}[${index}] = vec2(${coordinate[0]}, ${coordinate[1]});\n`;})str += `${instr}if(isPointInPolygon_${n}(position2D)){vec4 tileset_local_position_transformed = vec4(tileset_local_position.x, tileset_local_position.y, ground_z, 1.0);vec4 model_local_position_transformed = czm_inverseModel * u_tileset_localToWorldMatrix * tileset_local_position_transformed;vsOutput.positionMC.xy = model_local_position_transformed.xy;vsOutput.positionMC.z = model_local_position_transformed.z+ modelMC.z*0.002;return;}`;}this.updateShader(funstr, str);}/*** 根据id删除压平的面* @param {String} id 唯一标识*/removeRegionById(id) {if (!id) return;this.regionList = this.regionList.filter((attr) => {return attr.id != id;})this.localPositionsArr = [];for (let i = 0; i < this.regionList.length; i++) {let item = this.regionList[i];const positions = item.positions;let localCoor = this.cartesiansToLocal(positions);this.localPositionsArr.push(localCoor);}const funstr = this.getIsinPolygonFun(this.localPositionsArr);let str = ``;for (let i = 0; i < this.localPositionsArr.length; i++) {const coors = this.localPositionsArr[i];const n = coors.length;let instr = ``;coors.forEach((coordinate, index) => {instr += `points_${n}[${index}] = vec2(${coordinate[0]}, ${coordinate[1]});\n`;})str += `${instr}if(isPointInPolygon_${n}(position2D)){vec4 tileset_local_position_transformed = vec4(tileset_local_position.x, tileset_local_position.y, ground_z, 1.0);vec4 model_local_position_transformed = czm_inverseModel * u_tileset_localToWorldMatrix * tileset_local_position_transformed;vsOutput.positionMC.xy = model_local_position_transformed.xy;vsOutput.positionMC.z = model_local_position_transformed.z+ modelMC.z*0.002;return;}`;}this.updateShader(funstr, str);}/*** 销毁*/destroy() {this.tileset.customShader = undefined;}/*** 根据数组长度,构建 判断点是否在面内 的压平函数*/getIsinPolygonFun(polygons) {let pmap = polygons.map((polygon) => polygon.length);let uniqueArray = this.getUniqueArray(pmap);let str = ``;uniqueArray.forEach(length => {str += `vec2 points_${length}[${length}];bool isPointInPolygon_${length}(vec2 point){int nCross = 0; // 交点数const int n = ${length}; for(int i = 0; i < n; i++){vec2 p1 = points_${length}[i];vec2 p2 = points_${length}[int(mod(float(i+1),float(n)))];if(p1[1] == p2[1]){continue;}if(point[1] < min(p1[1], p2[1])){continue;}if(point[1] >= max(p1[1], p2[1])){continue;}float x = p1[0] + ((point[1] - p1[1]) * (p2[0] - p1[0])) / (p2[1] - p1[1]);if(x > point[0]){nCross++;}}return int(mod(float(nCross), float(2))) == 1;}`})return str}updateShader(vtx1, vtx2) {let flatCustomShader = new Cesium.CustomShader({uniforms: {u_tileset_localToWorldMatrix: {type: Cesium.UniformType.MAT4,value: this.matrix,},u_tileset_worldToLocalMatrix: {type: Cesium.UniformType.MAT4,value: this.localMatrix,},u_flatHeight: {type: Cesium.UniformType.FLOAT,value: this.flatHeight,},},vertexShaderText: `// 所有isPointInPolygon函数${vtx1}void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput){vec3 modelMC = vsInput.attributes.positionMC;vec4 model_local_position = vec4(modelMC.x, modelMC.y, modelMC.z, 1.0);vec4 tileset_local_position = u_tileset_worldToLocalMatrix * czm_model * model_local_position;vec2 position2D = vec2(tileset_local_position.x,tileset_local_position.y);float ground_z = 0.0 + u_flatHeight;// 多个多边形区域${vtx2}}`,});this.tileset.customShader = flatCustomShader;}// 数组去重,不能处理嵌套的数组getUniqueArray = (arr) => {return arr.filter(function (item, index, arr) {//当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素return arr.indexOf(item, 0) === index;});}// 世界坐标转数组局部坐标cartesiansToLocal(positions) {let arr = [];for (let i = 0; i < positions.length; i++) {let position = positions[i];let localp = Cesium.Matrix4.multiplyByPoint(this.localMatrix,position.clone(),new Cesium.Cartesian3())arr.push([localp.x, localp.y]);}return arr;}}export default Flat;

调用方式:

let flatTool = new Flat(tileset, {flatHeight: -30});flatTool.addRegion({positions : positions,id : new Date().getTime()});

以下是仓库地址:

CesiumExp-tilesetFlat: 3dtiles模型压平
 

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

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

相关文章

推荐给前端程序员的5款浏览器插件

所谓“工欲善其事&#xff0c;必先利其器”。Chrome&#xff08;谷歌浏览器&#xff09; 应该是程序员或者互联网行业人员使用最多的浏览器了。而在日常开发中&#xff0c;下面几款 浏览器 扩展也许能让你的开发工作事半功倍 。 1、Vimium vimium 是一个旨在将你的双手从鼠标…

【力扣·每日一题】2645. 构造有效字符串的最小插入数(动态规划 贪心 滚动数组优化 C++ Go)

题目链接 题意 给你一个字符串 word &#xff0c;你可以向其中任何位置插入 “a”、“b” 或 “c” 任意次&#xff0c;返回使 word 有效 需要插入的最少字母数。 如果字符串可以由 “abc” 串联多次得到&#xff0c;则认为该字符串 有效 。 提示&#xff1a; 1 < w o r…

C++核心编程(包含:内存、函数、引用、类与对象、文件操作等)【持续更新】

&#x1f308;个人主页&#xff1a;godspeed_lucip &#x1f525; 系列专栏&#xff1a;C从基础到进阶 C核心编程&#x1f30f;1 内存分区模型&#x1f384;1.1 程序运行前&#x1f384;1.2 程序运行后&#x1f384;1.3 new操作符 &#x1f30f;2 引用&#x1f384;2.1 引用的基…

【Golang开源项目】Golang高性能内存缓存库BigCache设计与分析

项目地址 BigCache 是一个快速&#xff0c;支持并发访问&#xff0c;自淘汰的内存型缓存&#xff0c;可以在存储大量元素时依然保持高性能。BigCache将元素保存在堆上却避免了GC的开销。 背景介绍 BigCache的作者在项目里遇到了如下的需求&#xff1a; 支持http协议支持 10…

Linux shell编程学习笔记39:df命令

0 前言1 df命令的功能、格式和选项说明 1.1 df命令的功能1.2 df命令的格式1.3 df命令选项说明 2 df命令使用实例 2.1 df&#xff1a;显示主要文件系统信息2.2 df -a&#xff1a;显示所有文件系统信息2.3 df -t[]TYPE或--type[]TYPE&#xff1a;显示TYPE指定类型的文件系统信…

解决英特尔无线网卡WiFi或者蓝牙突然消失问题

winR&#xff0c;输入“devmgmt.msc”&#xff0c;检查设备管理器中的无线网卡驱动是否安装好。 访问https://www.intel.cn/content/www/cn/zh/download/19351/windows-10-and-windows-11-wi-fi-drivers-for-intel-wireless-adapters.html下载对应系统版本的英特尔无线网卡WiFi…

LeetCode 22. 括号生成

22. 括号生成 数字 n 代表生成括号的对数&#xff0c;请你设计一个函数&#xff0c;用于能够生成所有可能的并且 有效的 括号组合。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;["((()))","(()())","(())()","()(())"…

遇到问题不要慌,轻松搞定内存泄露

当一个系统在发生 OOM 的时候&#xff0c;行为可能会让你感到非常困惑。因为 JVM 是运行在操作系统之上的&#xff0c;操作系统的一些限制&#xff0c;会严重影响 JVM 的行为。故障排查是一个综合性的技术问题&#xff0c;在日常工作中要增加自己的知识广度。多总结、多思考、多…

基于PyQT的图片批处理系统

项目背景&#xff1a; 随着数字摄影技术的普及&#xff0c;人们拍摄和处理大量图片的需求也越来越高。为了提高效率&#xff0c;开发一个基于 PyQt 的图片批处理系统是很有意义的。该系统可以提供一系列图像增强、滤波、水印、翻转、放大缩小、旋转等功能&#xff0c;使用户能够…

自动化网络监控:每分钟自动检测网站可用性

&#x1f9d9;‍♂️ 诸位好&#xff0c;吾乃诸葛妙计&#xff0c;编程界之翘楚&#xff0c;代码之大师。算法如流水&#xff0c;逻辑如棋局。 &#x1f4dc; 吾之笔记&#xff0c;内含诸般技术之秘诀。吾欲以此笔记&#xff0c;传授编程之道&#xff0c;助汝解技术难题。 &…

基于TCP技术在ROS1和ROS2中实现多机通讯

文章目录 概要准备工作ROS1中实现服务端功能CMakeLists.txt代码ROS2中实现客户端功能CMakeLists.txt代码参考概要 两台主机共用一个网络,分别为ROS1和ROS2版本,为了实现两台主机之间的通讯,采用TCP通讯技术。 准备工作 打开防火墙: sudo ufw enable打开目标端口:例如打开…

SpringBoot:详解依赖注入和使用配置文件

&#x1f3e1;浩泽学编程&#xff1a;个人主页 &#x1f525; 推荐专栏&#xff1a;《深入浅出SpringBoot》《java项目分享》 《RabbitMQ》《Spring》《SpringMVC》 &#x1f6f8;学无止境&#xff0c;不骄不躁&#xff0c;知行合一 文章目录 前言一、&#x1f3…

[python]基本输出输入函数

语法结构print(输出内容) print()函数完整的语法格式&#xff1a; print(value,...,sep ,end\n,fileNone)sep为连接符&#xff0c;end为结束符 注意字符串和整数无法连接 ASCII码 print(chr(98)) #使用chr()将98转换成ASCII表中的字符&#xff0c;输出bpython3以unicode进行内…

力扣精选算法100题——等于目标值的两个数or三数之和(双指针专题)

目录 &#x1f6a9;等于目标值的俩个数 第一步&#xff1a;了解题意 第二步&#xff1a;算法原理 第三步&#xff1a;代码实现 &#x1f6a9;三数之和 第一步&#xff1a;了解题意 第二步&#xff1a;算法原理 思路&#xff1a; ❗不漏&#xff1a; ❗去重: &#xf…

Simulink旧版本如何打开新版的模型文件

Simulink旧版本如何打开新版的模型文件 当用旧版本Simulink软件打开模型时会报错&#xff0c;是因为版本不兼容造成的 解决办法 在simulink的选项中去掉 do not load models created with newer version of Simulink

计算机视觉的应用

计算机视觉&#xff08;Computer Vision&#xff09;是一门研究如何让计算机能够理解和分析数字图像或视频的学科。简单来说&#xff0c;计算机视觉的目标是让计算机能够像人类一样对视觉信息进行处理和理解。为实现这个目标&#xff0c;计算机视觉结合了图像处理、机器学习、模…

分享用 vector的vector实现一个二维数组并初始化的逆置矩阵问题

题目名称 867.转置矩阵 目录 题目名称 867.转置矩阵 1.题目 2.题目分析 3.题目知识点 3.1vector的构造函数 3.2vector构造二维数组 最后&#x1f490; 推荐阅读顺序: 1.题目->2.题目分析->3.题目知识点 1.题目 如果矩阵 matrix为 m 行 n列&#xff0c;则转置后的矩…

【Python学习】Python学习15-模块

目录 【Python学习】Python学习15-模块 前言创建语法引入模块from…import 语句from…import* 语句搜索路径PYTHONPATH 变量-*- coding: UTF-8 -*-导入模块现在可以调用模块里包含的函数了PYTHONPATH 变量命名空间和作用域dir()函数globals() 和 locals() 函数reload() 函数Py…

Python中如何简化if...else...语句

一、引言 我们通常在Python中采用if...else..语句对结果进行判断&#xff0c;根据条件来返回不同的结果&#xff0c;如下面的例子。这段代码是一个简单的Python代码片段&#xff0c;让用户输入姓名并将其赋值给变量user_input。我们能不能把这几行代码进行简化&#xff0c;优化…

RocketMQ源码阅读-Message拉取与消费-Consumer篇

RocketMQ源码阅读-Message拉取与消费-Consumer篇 1. Consumer2. PushConsumer3. PushConsumer 订阅3.1 subscribe订阅3.2 registerMessageListener注册监听器 4. PushConsumer 消息队列Rebalance4.1 Rebalance流程4.2 Rebalance策略AllocateMessageQueueAveragelyAllocateMessa…