Cesium 模型压平

news2024/11/16 7:08:53

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

原理是使用了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.coloradmin.cn/o/1385399.html

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

相关文章

docker-ce 安装与国内源配置 | Ubuntu 20.04

博客原文 文章目录 让apt可以支持HTTPS将官方Docker库的GPG公钥添加到系统中将Docker库添加到APT里更新包列表为了确保修改生效&#xff0c;让新的安装从Docker库里获取&#xff0c;而不是从Ubuntu自己的库里获取&#xff0c;执行&#xff1a;安装 docker-ce配置 docker 阿里源…

Java多线程并发篇----第十四篇

系列文章目录 文章目录 系列文章目录前言一、ReadWriteLock 读写锁二、共享锁和独占锁三、重量级锁(Mutex Lock)四、轻量级锁前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给…

【图解数据结构】深入剖析时间复杂度与空间复杂度的奥秘

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;图解数据结构、算法模板 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 一. ⛳️算法的定义二. ⛳️算法的特性2.1 &#x1f514;输入输出2.2 &#x1f514;输入输出2.3 &…

Multimodal Prototypical Networks for Few-shot Learning

tcGAN is provided with an embedding ϕ T \phi_T ϕT​() of the textual description 辅助信息 作者未提供代码

大模型中的显卡优化与分布式训练策略

目录 前言1 大模型训练优化的目标1.1 简单性1.2. 高效性1.3 廉价性 2 显存的组成与利用2.1 参数存储2.2 梯度计算与存储2.3 中间计算结果2.4 优化器信息 3 优化方法3.1 数据并行3.2 模型并行3.3 零冗余优化器&#xff08;Zero Redundancy Optimizer&#xff09;3.4 Pipeline并行…

前端数据魔法:解析数据透视功能实现

前言 在信息爆炸的时代&#xff0c;数据扮演着关键的角色。从庞大的数据中提取有用的信息并进行有效地分析&#xff0c;是一项充满挑战的任务。为了应对这个挑战&#xff0c;数据透视表这一工具应运而生。它通过重新排列和组合数据&#xff0c;使得原始数据更易于理解和分析。…

解决鸿蒙APP的内存泄漏

解决鸿蒙&#xff08;HarmonyOS&#xff09;应用的内存泄漏问题需要采用一系列的策略和技术。与解决Android内存泄漏类似&#xff0c;以下是一些建议&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1…

增强FAQ搜索引擎:发挥Elasticsearch中KNN的威力

英文原文地址&#xff1a;https://medium.com/nerd-for-tech/enhancing-faq-search-engines-harnessing-the-power-of-knn-in-elasticsearch-76076f670580 增强FAQ搜索引擎&#xff1a;发挥Elasticsearch中KNN的威力 2023 年 10 月 21 日 在一个快速准确的信息检索至关重要的…

收银系统源码,连锁店收银系统源码

智慧新零售系统是一套线下线上一体化的收银系统。致力于给零售门店提供『多样化线下收银』、『ERP进销存』、『o2o小程序商城』、『精细化会员管理』、『丰富营销插件』等一体化行业解决方案&#xff01; 一、多样化线下收银 1.聚合收款码 ①适用商户&#xff1a;小微门店&am…

在 .NET 中使用可以漫游的 Web 凭据

Windows 凭据管理器是一个内置在 Windows 操作系统中的功能&#xff0c;为用户提供一种安全的方式来存储和管理凭据。本文主要介绍如何在 .NET 中使用可以漫游的 Web 凭据&#xff0c;以及使用中的基本事项。 1. 引言 在前面的文章《试用 Windows Terminal 中的 Terminal Chat…

SwiftUI CoreData Picker

开发多账本功能 CoreData 与 Picker 的使用 上代码&#xff1a; // // TestZhangBenPicker.swift // pandabill // // Created by 朱洪苇 on 2024/1/14. //import SwiftUIstruct TestZhangBenPicker: View {FetchRequest(sortDescriptors: [SortDescriptor(\.cc_at)],anima…

人工智能与六西格玛设计:一场颠覆性的融合之旅

随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;和六西格玛设计&#xff08;Six Sigma&#xff09;已成为当今企业追求卓越的关键工具。当这两大领域相遇&#xff0c;它们将引发一场创新与变革的狂潮。本文将探讨AI与六西格玛设计结合的潜力&#xff0c;以及…

MySQL 查看表结构简单命令

一、简单描述表结构&#xff0c;字段类型 desc tabl_name; # 表名 显示表结构&#xff0c;字段类型&#xff0c;主键&#xff0c;是否为空等属性。 二、查询表中列的注释信息 select * from information_schema.columns where table_schema db #表所在数据库 and table_n…

易基因:表观遗传学和表观转录组修饰在植物金属和准金属暴露中的作用 | 抗逆综述

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 非必需金属&#xff08;non-essential metal&#xff09;和准金属&#xff08;metalloid&#xff0c;也称类金属&#xff09;对土壤的污染是全球许多地区面临的严重问题。这些非必需金属…

java发送邮件(注:本章以163邮箱为例)

目录 前言 一邮件服务器与传输协议 二.发送邮件思路 2.1注册163邮箱: 2.2、打开邮箱服务获取授权码 三.代码实现邮件发送 3.1第三方jar包 3.2创建邮件工具类 3.3编写测试类 前言 电子邮件的应用非常广泛&#xff0c;例如在某网站注册了一个账户&#xff0c;自动发送一…

Vue报错 Cannot find module ‘../../modules/es6.symbol‘解决办法

在进行webpack打包的时候&#xff0c;会出现Cannot find module XXX’的错误&#xff0c;找不到某个模块的错误&#xff0c;今天给出解决方法&#xff1a; 直接进行npm install重新打包&#xff1b;如果npm install重新打包之后&#xff0c;仍然出现这个问题&#xff0c;可以进…

Springboot 整合阿里云安装的redis

今天购买了一台阿里云实例于是在上面装了一个redis,开始时一直连不上&#xff0c;一直报DENIED Redis is running in protected mode because protected mode is enabled 或者是无法连接的错误&#xff0c;于是检查配置redis.conf中&#xff1a;bind 屏蔽或者0.0.0.0 设置&…

Vue2-Vuex中State、Mutation及mapState辅助函数、mapMutations的基本用法

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。 个人笔记&#xff0c;仅供参考。 state&#xff1a;全局共享的响应式数据 mutation:声明修改全局响应式数据…

FPGA 原理图细节--画引脚

BGA引脚表示 1.1 FPGA此引脚要正确和清晰&#xff0c;会在“Package Pin”中用到次物理接口 1.2, MCU 只用管对应的GPIO逻辑接口就可以了 标识Bank电平 标识出对应Bank的电平&#xff0c;在电路设计中可以清晰的知道对应的脚位输出电平。在"IO std"也方便的选择 Ea…

PPT插件-大珩助手-保留原素材的位置和大小一键替换

保留原素材的位置和大小一键替换 若勾选了一键替换&#xff0c;对于从素材库插入的图形&#xff0c;可以使得它的位置、大小与幻灯片中选中的形状一致 软件介绍 PPT大珩助手是一款全新设计的Office PPT插件&#xff0c;它是一款功能强大且实用的PPT辅助工具&#xff0c;支持W…