基于Cesium的实景三维模型动态更新-以3Dtiles为例

Posted lwx2233

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于Cesium的实景三维模型动态更新-以3Dtiles为例相关的知识,希望对你有一定的参考价值。

基于Cesium的实景三维模型动态更新-以3Dtiles为例(二)_lwx2233的博客-CSDN博客

紧接上文,我们需要将osgb格式转换为cesium可以读取的3dtiles格式

打开我们的cesiumlab(Cesium实验室官网),在官网下载并随便注册一个号就可以免费使用了。

选择倾斜模型转V4,界面如下:

数据路径为osgb的Data文件夹,空间参考零点坐标则不需要输入,cesiumlab会从与Data文件夹同路径的metadata.xml文件中读取

其他参数不需要修改,选择输出路径即可,静静等待软件的处理:

数据处理完成后,记得点击三维可视,加载刚才生成的3dtiles瓦片,如果打得开的话,恭喜你成功了!

前期准备到这里结束,接下来就到了本研究最核心的部分(有够拖沓的我)

1.获取模型的范围

1.1获取模型中心点

首先我们要获取模型的中心点数据,先查看3Dtiles的原始数据

有些3Dtiles的格式可能不太一样,如果存在region字段的话是比较好办的,如果没有的话,那么就得利用他的transform字段

transform是一个矩阵,模型的几何中心点坐标储存在其中,但是坐标系为地心坐标系:

地心坐标系的模型中心点是可以直接添加在Cesium上的,但是我们需要的不是中心点,是模型的四至,我们需要模型的平面坐标系的四至。

为什么这么说,我们回过头来看3Dtiles中的boundingVolume,其中它包含了一个box的矩阵:

 

box是一个4*3的矩阵,第一行[0,1,2]代表了中心点的[x,y,z]偏移量,第二行[3,4,5]代表了四至的[x,0,0]偏移量,第三第四行以此类推。

得到模型的中心点平面坐标后,加减偏移量就可以获得模型的四至,以下是实现的代码(片段):

tilesset.allTilesLoaded.addEventListener(function a() 
    //单纯的xyz
    var x = tilesset.root.transform[12];
    var y = tilesset.root.transform[13];
    var z = tilesset.root.transform[14];
    var box = tilesset.root._header.boundingVolume.box;
    var centerpoints = [];
    centerpoints.push(x);
    centerpoints.push(y);
    centerpoints.push(z);
    
    console.log(centerpoints)
    
    
    //单纯的经纬度
    var ellipsoid=viewer.scene.globe.ellipsoid;
    var cartesian3=new Cesium.Cartesian3(x,y,z)
    var cartographic=ellipsoid.cartesianToCartographic(cartesian3);
    var lat=Cesium.Math.toDegrees(cartographic.latitude);
    var lng = Cesium.Math.toDegrees(cartographic.longitude);

    
    //获取中心点
    

    var alt = cartographic.height;
    var centerpoint = [];
    centerpoint.push(lat);
    centerpoint.push(lng);
    centerpoint.push(alt);
    console.log(centerpoint);
    
    var k = [1,1,0,1,-1,0,-1,-1,0,-1,1,0];
    var point1 =[] ,point2 = []
    for (var i = 0; i < 4; i++) 
        for (var j = 0; j < 3; j++) 
            point1[j] = box[0 * 3 + j] + k[i * 3 + j] * box[(j + 1) * 3 + j] - k[i * 3 + j] * 5;   
        
        //内缩边界
        xyzTransform(centerpoints, centerpoint, point1);
    
);
//开启地形检测
viewer.scene.globe.depthTestAgainstTerrain = true;


function xyzTransform(xyzbase, centerpoint, box) 
    var d2r = Math.PI/180.0
    var sinL0 = Math.sin(d2r*centerpoint[1]), cosL0 = Math.cos(d2r*centerpoint[1]);  // 经度
    var sinB0 = Math.sin(d2r*centerpoint[0]), cosB0 = Math.cos(d2r*centerpoint[0]);  // 纬度
    var dxyz =[], xyz = [];
    var dxyz0 = -sinL0 * box[0] - sinB0 * cosL0 * box[1] + cosB0 * cosL0 * box[2];
    var dxyz1 = cosL0 * box[0] - sinB0 * sinL0 * box[1] + cosB0 * sinL0 * box[2];
    var dxyz2 = cosB0 * box[1] + sinB0 * box[2];
    dxyz.push(dxyz0)
    dxyz.push(dxyz1)
    dxyz.push(dxyz2)
    for (var i = 0; i < 3; i++) 
        xyz[i] = xyzbase[i] + dxyz[i];
    
    
    var ellipsoid=viewer.scene.globe.ellipsoid;
    var cartesian3=new Cesium.Cartesian3(xyz[0],xyz[1],xyz[2])
    var cartographic=ellipsoid.cartesianToCartographic(cartesian3);
    var lat= Cesium.Math.toDegrees(cartographic.latitude);
    var lng = Cesium.Math.toDegrees(cartographic.longitude);
    

    var alt = cartographic.height;
    window.centerpoint1 = [];
    centerpoint1.push(lat);
    centerpoint1.push(lng);
    centerpoint1.push(alt);
    
    //三维模型的内缩边界
    // createPoint(xyz)
    window.polygon.push(xyz)

地心坐标系转换为平面坐标系,网上的公式很多,只要找一下然后自己写一下就好,这里就不介绍原理了。

这里我们便获得了一个polygon,一个面。

在加减模型的四至point1那里,我添加了一个k矩阵的计算在最后面,它的作用是,使得这个面内缩五米(乘5)

point1[j] = box[0 * 3 + j] + k[i * 3 + j] * box[(j + 1) * 3 + j] - k[i * 3 + j] * 5;  

为什么要这么做呢,因为在polygon被作为裁剪面的时候,由于瓦片的特性,瓦片边缘在不同的层级会出现不同的被狗啃的现象

于是乎我们要留一点缓冲地带,这就是为什么要将裁剪范围内缩一点,留一点重叠度,美观一点。

2.模型压平

接下来我们利用得到的这个裁剪面polygon,对模型进行模型处理,这个功能在cesium的沙盒中就可以找到,非常方便,只需要进行参数的替换便可

Cesium Sandcastle

将我们的polygon参数替换到示例中的白框,便完成了模型压平功能。

如果使用案例不可以的话,欢迎私聊我~也有可能单独开一篇来写模型压平。

3.模型更新

这个就更简单了,我们只需要预加载了新模型,然后将其隐藏。

window.tilesset = new Cesium.Cesium3DTileset(
    url: "http://xx.xx.xxx.xx:xxxx/data/3dtiles/qingxiemodel/tileset.json"//新模型发布的路径
)
// console.log(tilesset)
viewer.scene.primitives.add(tilesset)
window.tilesset.show = false//隐藏新模型

 在旧模型被压平之后再将其展示出来就可以了

window.tilesset.show = true;

至此,基本的实景三维模型动态更新流程就结束了,效果如下:

明天开始是番外篇了,会是一些奇奇怪怪的问题总结,如果有疑问,留在评论区或者私信我,感谢您读我的文章以及对我研究的可定~,下期再会

以上是关于基于Cesium的实景三维模型动态更新-以3Dtiles为例的主要内容,如果未能解决你的问题,请参考以下文章

基于Cesium的实景三维模型动态更新-以3Dtiles为例

基于Cesium的实景三维模型动态更新-以3Dtiles为例

基于Cesium的实景三维模型动态更新-以3Dtiles为例

基于Cesium的实景三维模型动态更新-以3Dtiles为例

基于Cesium的实景三维模型动态更新-以3Dtiles为例

基于Cesium的实景三维模型动态更新-以3Dtiles为例