首页 > 其他分享 >Cesium 3DTiles customshader的使用-动态高度设置

Cesium 3DTiles customshader的使用-动态高度设置

时间:2024-07-03 14:58:33浏览次数:24  
标签:tileset positionMC vec4 positionInWorld positionInLocal 3DTiles Cesium customsha

之前要编辑3DTiles 的shader来实现一些例如压平之类的操作 还需要更改源码

Cesium新版本更新了3Dtiles的自定义着色器 可以直接定义两个着色器并往里面传uniform

新版本添加3dtiles的方式发生了改变 原有的方式不能用了

新版本必须通过fromurl函数进行异步添加

async function addTileset(url) {
    try {
        
        let tileset = await Cesium.Cesium3DTileset.fromUrl(
            url, 
            {
            maximumCacheOverflowBytes: 9368709120,
           },
        );
        return tileset;
    } catch (error) {
        console.error(`Error creating tileset: ${error}`);
    }
}

然后在promise.then 里对tiles进行操作

              let tilesetpromise = addTileset(mainJson.RECORDS[i].ModelUrl);
                tilesetpromise.then(tileset=> {
                    tileset.customShader=getShader(tileset)
                    viewer.zoomTo(tileset);
                    viewer.scene.primitives.add(tileset);
                  })

也可以在fromUrl里直接指定customShader 但是我这里要用tiles加载完成之后的一些参数设置uniform 所有在加载完后再指定

getShader函数作用是创建一个customshader 

在顶点着色器对点的坐标进行修改时  要转换到相对坐标系下

否则会是一个很大的坐标 精度问题不说 增加z值时也不是垂直向上的

所以要转换到以tiles包围盒中心的相对坐标系下 

其实这个点可以自己指定  只要在tiles附近就行

function getShader(tileset) {
    let str = getVs();
    let center = tileset.boundingSphere.center.clone();

    let matrix = Cesium.Transforms.eastNorthUpToFixedFrame(center);
    let localMatrix = Cesium.Matrix4.inverse(matrix, new Cesium.Matrix4());
    console.log(localMatrix, tileset.modelMatrix);

    let CustomShader = new Cesium.CustomShader({
        uniforms: {
            M_LocaltoWorld: {
                type: Cesium.UniformType.MAT4,
                value: matrix,
            },
            M_WorldtoLocal: {
                type: Cesium.UniformType.MAT4,
                value: localMatrix,
            },
            center: {
                type: Cesium.UniformType.VEC3,
                value: center,
            },
            height: {
                type: Cesium.UniformType.FLOAT,
                value: height,
            },

        },
        vertexShaderText: str,
    });
    return CustomShader;
}

着色器 对点坐标的操作都要在局部坐标系进行

function getVs() {
    let str=   `
    
  void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {
         vec3 positionMC = vsInput.attributes.positionMC;
        //世界坐标转局部
        vec4 positionInLocal=M_LocaltoWorld*vec4(positionMC,1.0);
        positionInLocal=positionInLocal/positionInLocal.w;
        positionInLocal.z+=height;
        //转回世界坐标
        vec4 positionInWorld=M_WorldtoLocal*positionInLocal;
        positionInWorld=positionInWorld/positionInWorld.w;
        vsOutput.positionMC=positionInWorld.xyz;
        return;
  }
    `
    return str;
 
}

然后是动态更新uniform的问题了

我尝试直接对height的值进行修改 但是没有用

所以要不用字符串拼凑的方式 要不生成一个新的customshader

我用第二种方式 由于我的场景不止添加了一个tiles 所以要遍历

function addHeight() {
    height += 10;
    for (let i =0;i<viewer.scene.primitives.length;i++)
    {
        if(viewer.scene.primitives.get(i) instanceof Cesium.Cesium3DTileset)
        {
            let tile=viewer.scene.primitives.get(i);
            let shader=getShader(tile);
            shader.setUniform("height", height);
            tile.customShader=shader;
        }
    }

然后增加高度 

 有问题 随着height值的增加 模型竟然做的是水平运动 或者高度增加的很少 这与预期完全不符

检查了一下才发现两个变换矩阵写反了 正确的应该是

  void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {
         vec3 positionMC = vsInput.attributes.positionMC;
        //世界坐标转局部 //这里和下面的写反了
        vec4 positionInLocal=M_WorldtoLocal*vec4(positionMC,1.0);
        positionInLocal=positionInLocal/positionInLocal.w;
        positionInLocal.z+=height;
        //转回世界坐标
        vec4 positionInWorld=M_LocaltoWorld*positionInLocal;
        positionInWorld=positionInWorld/positionInWorld.w;
        vsOutput.positionMC=positionInWorld.xyz;
        return;
  }

 改正之后确实高度增加了 但是还是不只是垂直方向的运动 还是有水平方向的运动

发现问题了

vsInput.attributes.positionMC; 并不是直接是世界坐标 这个坐标是做了模型变换的

要把模型坐标转化为世界坐标 增加一个矩阵相乘即可

     vec4 positionInLocal=M_WorldtoLocal*czm_model*vec4(positionMC,1.0);

最后转回去的时候要转回模型坐标

   vec4 positionInWorld=czm_inverseModel*M_LocaltoWorld*positionInLocal;

着色器为

  void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {
         vec3 positionMC = vsInput.attributes.positionMC;
        //世界坐标转局部 要将模型坐标转为世界坐标
        vec4 positionInLocal=M_WorldtoLocal*czm_model*vec4(positionMC,1.0);
        positionInLocal=positionInLocal/positionInLocal.w;
        positionInLocal.z+=height;
        //转回世界坐标 乘逆矩阵
        vec4 positionInWorld=czm_inverseModel*M_LocaltoWorld*positionInLocal;
        positionInWorld=positionInWorld/positionInWorld.w;
        vsOutput.positionMC=positionInWorld.xyz;
        return;
  }
    `

这样就正确了 只有垂直方向的运动

标签:tileset,positionMC,vec4,positionInWorld,positionInLocal,3DTiles,Cesium,customsha
From: https://blog.csdn.net/qq_52254412/article/details/140144775

相关文章

  • Cesium 实现可视域分析
    *前言:尝试了网上好多个版本的可视域分析,感觉都有一些问题,我这个也可能不是最完美的,但是我觉得对我来说够用了,实现效果如下*此示例基于vue3上实现,cesium版本1.101.0,vite-plugin-cesium版本1.2.22新建一个名为ViewshedAnalysis.js的JS文件importglslfrom'./glsl2'/**......
  • cesium 添加 Echarts图层(航线图)
    cesium添加Echarts航线图(下面附有源码)1、实现思路1、在scene上面新增一个canvas画布2、通坐标转换,将经纬度坐标转为屏幕坐标来实现3、将ecarts中每个series数组中元素都加coordinateSystem:‘cesiumEcharts’2、示例代码<!DOCTYPEhtml><htmllang=......
  • Cesium 实战 - 自定义纹理材质系列之 - 涟漪效果
    Cesium实战-自定义纹理材质系列之-涟漪效果核心代码完整代码在线示例Cesium给实体对象(Entity)提供了很多实用的样式,基本满足普通项目需求;但是作为WebGL引擎,肯定不够丰富,尤其是动态效果样式。对于实体对象(Entity),可以通过自定义材质,实现各种动态效果,虽......
  • cesium 添加 Echarts 图层(空气质量点图)
    cesium添加Echarts图层(下面附有源码)1、实现思路1、在scene上面新增一个canvas画布2、通坐标转换,将经纬度坐标转为屏幕坐标来实现3、将ecarts中每个series数组中元素都加coordinateSystem:‘cesiumEcharts’2、示例代码<!DOCTYPEhtml><htmllang="en"><hea......
  • Cesium 实战 - 自定义纹理材质系列之 - 动态扩散效果
    Cesium实战-自定义纹理材质系列之-动态扩散效果核心代码完整代码在线示例Cesium给实体对象(Entity)提供了很多实用的样式,基本满足普通项目需求;但是作为WebGL引擎,肯定不够丰富,尤其是动态效果样式。对于实体对象(Entity),可以通过自定义材质,实现各种动态效......
  • cesium中如何高性能渲染3D模型(附水淹分析模拟)
    大家好,我是日拱一卒的攻城师不浪,专注可视化、数字孪生、前端、nodejs、AI学习、GIS等学习沉淀,这是2024年输出的第18/100篇文章;前言之前在参加城市应急数字孪生项目开发过程中,遇到一个场景,就是模拟水淹分析。也就是说,甲方需要根据你这个平台,在下暴雨的时候,精准监测到城......
  • cesium 点击事件转经纬度坐标
    lethandler=newCesium.ScreenSpaceEventHandler(viewer.scene.canvas); handler.setInputAction(function(e){ console.log('cli',e);//letpickId=viewer.scene.pick(e.position); //点击监听三维数据服务的实体 varcartesian=viewer.camera.......
  • 077:vue+cesium 显示等高线
    作者:还是大剑师兰特,曾为美国某知名大学计算机专业研究生,现为国内GIS领域高级前端工程师,CSDN知名博主,深耕openlayers、leaflet、mapbox、cesium,canvas,echarts等技术开发,欢迎加微信(gis-dajianshi),一起交流。查看本专栏目录-本文是第077个示例文章目录一......
  • 【Cesium】Vue+js+Cesium实现海康监控视频云台控制
    1.硬件设备与视频流接入    如需要一步上一篇博客【Cesium】Vue+js+Cesium实现监控视频流接入-CSDN博客文章浏览阅读308次,点赞12次,收藏17次。Vue2+js+Cesium实现监控视频流接入与相机云台控制https://blog.csdn.net/weixin_51540717/article/details/139614406?csdn_......
  • Cesium4Unreal - # 008 空间碎片
    文章目录空间碎片1思路2步骤2.1创建一个自定义组件2.2重写CreateSceneProxy方法2.3实现自定义的场景代理类2.4在场景代理类中实现绘制逻辑2.5使用自定义组件3代码实现3.1c++代码3.1.1自定义组件代码MyPrimitivePolylineComponent.......