基于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的沙盒中就可以找到,非常方便,只需要进行参数的替换便可
将我们的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为例