Cesium中3DTiles模子平移至指定经纬度

[复制链接]
发表于 2026-2-11 23:37:38 | 显示全部楼层 |阅读模式
 Cesium加载3Dtiles模子的平移和旋转_3dtiles先旋转再平移示例-CSDN博客
Cesium 平移cesiumlab生产的3Dtiles切片模子到目标经纬度-CSDN博客
【ArcGIS+CityEngine】自行制作Lod1都会大标准白膜数据_cityengine 天生指定坐标集指定地域的白模-CSDN博客

 
Cesium手动建模模子用Cesiumlab转3D Tiles模子位置不对,调解模子位置至指定经纬度
从前次ArcGIS+CityEngine制作的白膜为例:
 导出至FBX/OBJ

然后在CesiumLab中转化为3D Tiles模子

 但是发现模子位置不准确,默认位置在北京天安门上空,必要将模子调解至指定经纬度位置!!

早先以为只需做平移厘革,平移至指定经纬度:
  1. tileset.readyPromise.then(function() {
  2.         // // 获取tileset的中心点坐标
  3.         const boundingSphere = tileset.boundingSphere
  4.         const center = boundingSphere.center
  5.         // 将中心点坐标转换为WGS84坐标系下的经纬度
  6.         const cartographic = Cesium.Cartographic.fromCartesian(center)
  7.         console.log(cartographic)
  8.         const longitude = Cesium.Math.toDegrees(cartographic.longitude)
  9.         const latitude = Cesium.Math.toDegrees(cartographic.latitude)
  10.         const height = Cesium.Math.toDegrees(cartographic.height)
  11.         // const startLon = 116.391005;
  12.         // const startLat = 39.906623
  13.         // 将经纬度调整为研究区域的经纬度
  14.         const areaLongitude = 118.792930
  15.         // const areaLongitude = 114.150301
  16.         const areaLatitude = 31.9707912
  17.         // 计算tileset的平移量,并将其应用到modelMatrix中
  18.         const translation = Cesium.Cartesian3.fromDegrees(areaLongitude, areaLatitude)
  19.         const centerNew = Cesium.Cartesian3.fromDegrees(longitude, latitude)
  20.         const translationVector = Cesium.Cartesian3.subtract(translation, centerNew, new Cesium.Cartesian3())
  21.         const translationMatrix = Cesium.Matrix4.fromTranslation(translationVector);
  22.         console.log(translationMatrix)
  23.         tileset.modelMatrix = translationMatrix
  24.         viewer.zoomTo(tileset)
  25.       })
复制代码
 但是平移的效果存在标题!!!模子为倾斜的,发生旋转了,未贴地,必要调解!!!


why: 

在Cesium中,当你实行在全局坐标系下直接平移3D Tiles数据时,大概会碰到模子变得不平(即模子的多少形状在视觉上扭曲或倾斜)的标题。这通常是由于平移利用没有思量到原始模子与地球外貌之间的相对位置关系

 
How: 


  • 使用地球外貌的局部坐标系
    实行将平移利用转换为地球外貌的局部坐标系中的移动。这通常涉及到盘算目标位置与当前位置之间的地球外貌间隔,并沿着地球外貌移动模子。然而,Cesium的API大概不直接支持这种利用,因此你大概必要实现一些自界说的逻辑。
  • 调解模子矩阵以思量地球曲率
    如果你直接在模子矩阵中设置平移,你必要确保这个平移是沿着地球外貌的切线方向举行的,而不是简单地沿着全局坐标系的X、Y、Z轴。这大概必要你根据目标经纬度盘算出一个符合的平移向量,该向量应该思量到地球外貌的曲率
  Solution:
  

  • 将模子平移回天下坐标系原点(地心)
  • 将局部坐标Z轴调解到与天下坐标Z轴重合
  • 将局部坐标X,Y轴调解到与天下坐标X,Y轴重合
  • 将目标位置的eastNorthUp局部坐标系平移回天下坐标系原点(地心)
  • 旋转物体坐标系与目标坐标系重合
  • 平移到目标位置,即为终极变更矩阵
 理论根本:GAMES101 Lecture 04 Transformation Cont._哔哩哔哩_bilibili

Cesium中局部平移、旋转3D Tiles模子Cesium局部平移、缩放、旋转思绪及代码实现 - 小专栏
 平移

   表明:
  

  • 红点:frompoint(地表点)
  • 蓝点:targetpoint(frompoint局部坐标向东向北向上偏移各 310、-140、10米 后得到的目标点)
  • 红向量:地表点向量
  • 蓝向量:目标点向量
  • 绿向量:平移向量。如果是局部坐标,那么就是 (310, -140, 10),如果是天下坐标下的,那就是 蓝向量 - 红向量
cesium 的场景数据终极都是天下坐标的,以是要求的是绿向量的天下坐标表达,然后构造平移矩阵。
  现在是已知红向量和局部坐标的绿向量,要先求蓝向量,才气得到天下坐标的绿向量。
  1. tileset.readyPromise.then(function() {
  2.         let params = {
  3.           position: tileset.boundingSphere.center,
  4.           tx: -1974,
  5.           ty: 2433,
  6.           tz: -33.9
  7.         }
  8.         // 重定向坐标
  9.         const m = Cesium.Transforms.eastNorthUpToFixedFrame(params.position);//获取到以模型中心为原点,Z轴垂直地表的局部坐标系,以矩阵表示,此矩阵为将局部坐标系变换到世界坐标系的变换矩阵
  10.         //设置平移向量
  11.         const tempTranslation = new Cesium.Cartesian3(params.tx, params.ty, params.tz);//平移向量
  12.         // 获取平移矩阵
  13.         const offset = Cesium.Matrix4.multiplyByPoint(m, tempTranslation, new Cesium.Cartesian3(0, 0, 0));//局部坐标中(tx,ty,tz)在世界坐标系中位置
  14.         const translation = Cesium.Cartesian3.subtract(offset, params.position, new Cesium.Cartesian3());//终点世界坐标减去原点世界坐标得到世界坐标系下平移向量
  15.         // 重新设置其位置大小
  16.         tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
  17.         viewer.scene.primitives.add(tileset)
  18.         viewer.flyTo(tileset)
  19.       })
  20.     },
复制代码
旋转
  1. function moveModel(tileset,longitude,latitude,height) {
  2.     //计算世界坐标系中的目标位置offset
  3.     var cartographic = new Cesium.Cartographic.fromCartesian(
  4.       tileset.boundingSphere.center
  5.     );
  6.     var offset = Cesium.Cartesian3.fromDegrees(longitude,latitude,cartographic.height+height);
  7.     //将模型位移至地心
  8.     const origin = tileset.boundingSphere.center;
  9.     const originMatrix = tileset.modelMatrix;//模型的初始变换矩阵
  10.     const backToEarthCenter = new Cesium.Cartesian3(-origin.x,-origin.y,-origin.z);//初始位置到地心的位移向量
  11.     let backToEarthCenterMatrix = Cesium.Matrix4.fromTranslation(backToEarthCenter);//初始位置到地心的变换矩阵
  12.     Cesium.Matrix4.multiply(backToEarthCenterMatrix, originMatrix, backToEarthCenterMatrix);//移动模型到地心的矩阵
  13.     // 旋转模型使得Z轴与世界坐标Z轴重合
  14.     let arrowX = new Cesium.Cartesian3(1, 0, 0);
  15.     let arrowZ = new Cesium.Cartesian3(0, 0, 1);
  16.     let angleToXZ = Cesium.Cartesian3.angleBetween(arrowX, new Cesium.Cartesian3(origin.x, origin.y, 0));//局部Z轴在世界坐标系XY平面上投影到X轴角度,即绕Z顺时针旋转这个角度可以到XZ平面上
  17.     let angleToZ = Cesium.Cartesian3.angleBetween(origin, arrowZ);//然后绕Y轴顺时针旋转此角度可使得Z轴与世界坐标系Z轴重合
  18.     const rotationAngleToXZ = Cesium.Matrix3.fromRotationZ((origin.y>0?-1:+1)*angleToXZ);//绕Z轴旋转的Matrix3矩阵,正角度逆时针旋转
  19.     const rotationAngleToZ = Cesium.Matrix3.fromRotationY(-angleToZ);//绕Y轴旋转的Matrix3矩阵,负角度顺时针旋转
  20.     let rotationAngleToZMatrix = Cesium.Matrix3.multiply(rotationAngleToZ, rotationAngleToXZ, new Cesium.Matrix3);//连续旋转的Matrix3矩阵,即先绕Z轴旋转,后绕Y旋转的矩阵。
  21.     rotationAngleToZMatrix = Cesium.Matrix4.fromRotationTranslation(rotationAngleToZMatrix);//连续旋转的Matrix4矩阵
  22.     Cesium.Matrix4.multiply(rotationAngleToZMatrix, backToEarthCenterMatrix, rotationAngleToZMatrix);//将移动至地心模型,旋转至Z轴重合的矩阵
  23.     // 旋转模型使得X,Y轴与世界坐标X,Y轴重合
  24.     const rotationZ = Cesium.Matrix3.fromRotationZ(-Math.PI/2); // 绕Z轴旋转90°的Matrix3变换矩阵
  25.     let rotationMatrix = Cesium.Matrix4.fromRotationTranslation(rotationZ); // 绕Z轴旋转90°的Matrix4变换矩阵
  26.     Cesium.Matrix4.multiply(rotationMatrix, rotationAngleToZMatrix, rotationMatrix);//将移动至地心模型的物体坐标系,旋转到与世界坐标系重合的矩阵
  27.     //在地心位置,旋转物体坐标系和世界坐标系重合的模型,使得与目标坐标系重合
  28.     const offsetToWorldMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(offset);//获取到以目标位置为原点,的eastNorthUp局部坐标系的变换矩阵
  29.     const backToEarthCenterOffset = new Cesium.Cartesian3(-offset.x, -offset.y, -offset.z);//目标位置到地心的位移向量
  30.     let backToEarthCenterMatrixOffset = Cesium.Matrix4.fromTranslation(backToEarthCenterOffset);//目标位置到地心的变换矩阵
  31.     Cesium.Matrix4.multiply(backToEarthCenterMatrixOffset, offsetToWorldMatrix, backToEarthCenterMatrixOffset);//获得从世界坐标系旋转至目标坐标系的旋转矩阵(只有旋转,没有位移)
  32.     Cesium.Matrix4.multiply(backToEarthCenterMatrixOffset, rotationMatrix, backToEarthCenterMatrixOffset);//将移动至地心模型的物体坐标系,旋转到与目标坐标系重合的矩阵(完成模型的最终旋转,没有位移)
  33.     //移动到目标位置
  34.     const backToOriginMatrix = Cesium.Matrix4.fromTranslation(offset);//地心到目标位置位移向量
  35.     const lastMatrix = Cesium.Matrix4.multiply(backToOriginMatrix,backToEarthCenterMatrixOffset,new Cesium.Matrix4());//最终矩阵,即将地心位置的模型移动到目标位置(完成模型的最终旋转,最终位移)
  36.     console.log('最终变换矩阵',lastMatrix);
  37.     return lastMatrix //返回最终变换矩阵
  38. }
  39. ------------------------------------------------------------------------------------------
  40. let tileset = viewer.scene.primitives.add(
  41.       new Cesium.Cesium3DTileset({
  42.         url: ".../tileset.json",
  43.       })
  44.     );
  45.    
  46.     tileset.readyPromise.then(function (tileset) {
  47.       window.tileset = tileset
  48.       let longitude = 104.98680
  49.       let latitude = 32.20795
  50.       let height = 100
  51.       let modelMatrix = moveModel(tileset,longitude,latitude,height)
  52.       tileset.modelMatrix = modelMatrix;//移动模型
  53.       // 创建圆形包围盒
  54.       let boundingSphere = new Cesium.BoundingSphere(
  55.         tileset.boundingSphere.center,
  56.         tileset.boundingSphere.radius
  57.       );
  58.       //飞向该包围盒
  59.       viewer.camera.flyToBoundingSphere(boundingSphere);
  60.     });
复制代码
 
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表