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.mfbz.cn/a/312566.html

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

相关文章

leetcode 每日一题 2024年01月11日 构造有效字符串的最少插入数

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

辞旧岁,赢新篇,创维汽车召开年度会议立足过去,展望未来

为辞旧迎新&#xff0c;再创辉煌&#xff0c;创维汽车于1月4日-5日召开了事业部年度会议。本次会议将23年整体运营情况作出总结并对新一年的发展作出了目标规划。创维集团、创维汽车创始人黄宏生先生&#xff0c;开沃新能源汽车集团执行董事兼首席运营官诸萍女士&#xff0c;创…

记录一次华为云服务器扩容系统磁盘

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 1. 扩容步骤 1.1 在华为云控制台操作磁盘扩容 1.2 服务器上操作扩容步骤 1&#xff09;fdisk -l 查看扩容情况&#xff0c;确认…

git: Updates were rejected because the tip of your current branch is behind

一、报错含义 由于本地分支的tip落后远程分支&#xff0c;push操作被拒绝。 二、产生原因 我再本地拉去了新的分支并未同步到远程仓库&#xff0c;在新分支进行开发&#xff0c;由于前几天同步也创建了该分支并同步到了远程仓库&#xff0c;导致我本次push失败 三、解决方…

【CSS】首个字符占用多行,并自定义样式

效果 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>首字母大写</title><style&…

C++力扣题目111--二叉树的最小深度

力扣题目链接(opens new window) 给定一个二叉树&#xff0c;找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明: 叶子节点是指没有子节点的节点。 示例: 给定二叉树 [3,9,20,null,null,15,7], 返回它的最小深度 2 思路 看完了这篇104.二…

原生微信小程序-两次设置支付密码校验,密码设置二次确认

效果 具体代码 1、wxml <view style"{{themeColor}}"><view classcontainer><view class"password_content"><view wx:if{{type 1}}><view class"title"><view class"main_title">设置支付密码…

【Android开发】不同Activity之间的数据回传实例(一)摘桃子游戏

一、功能介绍 该项目实现的功能主要有&#xff1a; 在首页显示一个按钮点击该按钮跳转到桃园页面在桃园页面&#xff0c;点击桃子会弹窗显示摘到几个桃子&#xff0c;同时被点击桃子消失&#xff0c;总桃子数1点击退出桃园会返回首页&#xff0c;首页桃子数会根据点击的桃子数…

PPT插件-大珩助手-《提取选中的幻灯片》-选中新建

选中新建 提取选中的幻灯片到新的幻灯文稿中。PDF编辑器可以提取指定的页面到新的PDF文档中&#xff0c;PPT没有这个功能&#xff0c;因此开发。 软件介绍 PPT大珩助手是一款全新设计的Office PPT插件&#xff0c;它是一款功能强大且实用的PPT辅助工具&#xff0c;支持Wps Wo…

锂电池的电压和容量怎么计算?

锂电池组是由电池单体&#xff08;电芯&#xff09;通过串并联来组成 1、串联(S)增加电压&#xff0c;容量不变。 例如&#xff1a;1个磷酸铁锂电池的额定电压为3.2V&#xff0c;容量为4000mAH&#xff0c;将10个磷酸铁锂电芯串联&#xff0c;电池组电压&#xff1a;3.2v*10&a…

usb静电防护芯片选择

方案1 USBLC6-2SC6 优缺点 优点&#xff1a;进出使用不同的焊盘&#xff0c;如果没有焊接好信号必定不能通过。有效的避免了虚焊导致故障。 缺点&#xff1a;不能省略&#xff0c;调试时也不能省略。 原理图 参考价格 参考来源 USB切换方案&#xff0c;多电脑共用USB方案…

leecode1143 | 最长公共子序列

给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些字符&#xff08;也可以不…

2024Flutter岗位面试题总结

StatelessWidget和StatefulWidget的区别是什么&#xff1f; StatelessWidget是一个不可变的类&#xff0c;充当UI布局中某些部分的蓝图&#xff0c;当某个组件在显示期间不需要改变&#xff0c;或者说没有状态&#xff08;State&#xff09;&#xff0c;你可以使用它。 Statef…

【深度学习目标检测】十三、基于深度学习的血细胞识别(python,目标检测,yolov8)

血细胞计数是医学上一种重要的检测手段&#xff0c;用于评估患者的健康状况&#xff0c;诊断疾病&#xff0c;以及监测治疗效果。而目标检测是一种计算机视觉技术&#xff0c;用于在图像中识别和定位特定的目标。在血细胞计数中&#xff0c;目标检测技术可以发挥重要作用。 首先…

git修改最新提交(commit)信息

一、修改最近一次commit信息 1、首先通过git log查看commit信息 2、使用命令git commit --amend进入命令命令模式&#xff0c;按i进入编辑模式&#xff0c;修改好commit信息后按Esc键退出编辑模式&#xff0c;然后输入:wq保存编辑信息&#xff08;注意使用英文输入法&#xf…

D盘能不能随便格式化?根据不同情况来分析

随着计算机技术的发展&#xff0c;D盘已成为许多用户存储重要数据和文件的一部分。然而&#xff0c;当我们想要对D盘进行格式化时&#xff0c;是否可以随意进行操作呢&#xff1f;本文将探讨这一问题&#xff0c;并给出关于“电脑D盘数据格式化后怎么恢复”的相关方法。 图片来…

HarmonyOS@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化

Observed装饰器和ObjectLink装饰器&#xff1a;嵌套类对象属性变化 上文所述的装饰器仅能观察到第一层的变化&#xff0c;但是在实际应用开发中&#xff0c;应用会根据开发需要&#xff0c;封装自己的数据模型。对于多层嵌套的情况&#xff0c;比如二维数组&#xff0c;或者数…

yolov8n 瑞芯微RKNN和地平线Horizon芯片仿真测试部署,部署工程难度小、模型推理速度快

特别说明&#xff1a;参考官方开源的yolov8代码、瑞芯微官方文档、地平线的官方文档&#xff0c;如有侵权告知删&#xff0c;谢谢。 模型和完整仿真测试代码&#xff0c;放在github上参考链接 模型和代码。 因为之前写了几篇yolov8模型部署的博文&#xff0c;存在两个问题&…

机器学习-协同过滤

1、协同过滤要解决的问题 协同过滤算法主要用于推荐系统&#xff0c;推荐系统是信息过载所采用的措施&#xff0c;面对海量的数据信息&#xff0c;从中快速推荐出符合用户特点的物品。一些人的“选择恐惧症”、没有明确需求的人。 解决如何从大量信息中找到自己感兴趣的信息。…

如何一键添加引号和英文逗号,然后可以放入SQL中使用 → WHERE USER_NAME IN (‘张三‘,‘李四‘,‘王五‘)

如何一键添加引号和英文逗号&#xff0c;然后可以放入SQL中使用 → WHERE USER_NAME IN&#xff08;张三,李四,王五&#xff09; 一、背景二、解决方法三、一键添加引号和英文逗号的教程 一、背景 在日常开发中&#xff0c;当处理VARCHAR或VARCHAR2类型的字段时&#xff0c;很…
最新文章