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


     Cesium加载3Dtiles模型的平移和旋转_3dtiles先旋转再平移示例-CSDN博客

    Cesium 平移cesiumlab生产的3Dtiles切片模型到目标经纬度-CSDN博客

    【ArcGIS+CityEngine】自行制作Lod1城市大尺度白膜数据_cityengine 生成指定坐标集指定区域的白模-CSDN博客

     

    Cesium手动建模模型用Cesiumlab转3D Tiles模型位置不对,调整模型位置至指定经纬度

    以上次ArcGIS+CityEngine制作的白膜为例:

    4f752f25cb9d44b3a4f939fa33489b53.png 导出至FBX/OBJ

    9ed27a1b9052489ba23c27bdc7e1c5ad.png

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

    ba4783a331d74217b610e12287fbabea.png

     但是发现模型位置不正确,默认位置在北京天安门上空,需要将模型调整至指定经纬度位置!!

    8919cf952c3f4649ae2b68010140a9eb.png

    起初以为只需做平移变化,平移至指定经纬度

    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. })

     但是平移的结果存在问题!!!模型为倾斜的,发生旋转了,未贴地,需要调整!!!

    6e07d025cdbe4890a5550db1929c2df0.png

    9be40aa62fd846bfb1afb29210084bcb.png

    why: 

    在Cesium中,当你尝试在全局坐标系下直接平移3D Tiles数据时,可能会遇到模型变得不平(即模型的几何形状在视觉上扭曲或倾斜)的问题。这通常是因为平移操作没有考虑到原始模型与地球表面之间的相对位置关系

    6b34996fcd234506be6a879bdc39af66.png

     

    How: 

    1. 使用地球表面的局部坐标系
      尝试将平移操作转换为地球表面的局部坐标系中的移动。这通常涉及到计算目标位置与当前位置之间的地球表面距离,并沿着地球表面移动模型。然而,Cesium的API可能不直接支持这种操作,因此你可能需要实现一些自定义的逻辑。

    2. 调整模型矩阵以考虑地球曲率
      如果你直接在模型矩阵中设置平移,你需要确保这个平移是沿着地球表面的切线方向进行的,而不是简单地沿着全局坐标系的X、Y、Z轴。这可能需要你根据目标经纬度计算出一个合适的平移向量,该向量应该考虑到地球表面的曲率

    Solution:

    1. 将模型平移回世界坐标系原点(地心)

    2. 将局部坐标Z轴调整到与世界坐标Z轴重合

    3. 将局部坐标X,Y轴调整到与世界坐标X,Y轴重合

    4. 将目标位置的eastNorthUp局部坐标系平移回世界坐标系原点(地心)

    5. 旋转物体坐标系与目标坐标系重合

    6. 平移到目标位置,即为最终变换矩阵

     理论基础:GAMES101 Lecture 04 Transformation Cont._哔哩哔哩_bilibili

    d81c0fd210cb4705a7d57de445acd3bc.png

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

     平移

    aee04959641341cfb95d7172cf3093f2.png

    解释:

    • 红点: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. tileset.readyPromise.then(function (tileset) {
    46. window.tileset = tileset
    47. let longitude = 104.98680
    48. let latitude = 32.20795
    49. let height = 100
    50. let modelMatrix = moveModel(tileset,longitude,latitude,height)
    51. tileset.modelMatrix = modelMatrix;//移动模型
    52. // 创建圆形包围盒
    53. let boundingSphere = new Cesium.BoundingSphere(
    54. tileset.boundingSphere.center,
    55. tileset.boundingSphere.radius
    56. );
    57. //飞向该包围盒
    58. viewer.camera.flyToBoundingSphere(boundingSphere);
    59. });

     

     

  • 相关阅读:
    网站监控定时任务网址url监控神器
    MyBatis-Plus入门案例
    LeetCode 3. 无重复字符的最长子串
    【fiddler学习笔记】——安装、原理、使用
    Vue(十)——页面路由(2)
    模式分类与“组件协作模式”
    计算机毕业设计SSM毕业设计管理系统【附源码数据库】
    微服务系统架构的演变
    Java开发者的Golang进修指南:从0->1带你实现协程池
    【Vue2】VantUI项目-基础入门02
  • 原文地址:https://blog.csdn.net/m0_55049655/article/details/140987883