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

背景:在没有cesiumlab官方授权的情况下,对于fbx,obj等模型无法使用坐标系和偏移量进行切片处理 ,此时用cesiumlab的默认参数生产的切片模型数据,默认位置在北京天安门上空,与实际位置有距离很大偏差,不能只通过平移矩阵移动模型到实际位置,还需要对应的旋转矩阵。

目的:通过cesium的内置函数,将模型移动到实际位置。

思路顺序:

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

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

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

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

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

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

具体思路细节可参考csdn文章: Cesium加载3Dtiles模型的平移和旋转

矩阵很抽象,想要了解矩阵相关的详细信息,推荐观看书籍《3D数学基础:图形与游戏开发(第一版)》,网络上很多pdf,注意,请看第一版,不要看第二版,第二版可能是机翻,很多语句难以理解。 

function moveModel(tileset,longitude,latitude,height) {
    //计算世界坐标系中的目标位置offset
    var cartographic = new Cesium.Cartographic.fromCartesian(
      tileset.boundingSphere.center
    );
    var offset = Cesium.Cartesian3.fromDegrees(longitude,latitude,cartographic.height+height);

    //将模型位移至地心
    const origin = tileset.boundingSphere.center;
    const originMatrix = tileset.modelMatrix;//模型的初始变换矩阵
    const backToEarthCenter = new Cesium.Cartesian3(-origin.x,-origin.y,-origin.z);//初始位置到地心的位移向量
    let backToEarthCenterMatrix = Cesium.Matrix4.fromTranslation(backToEarthCenter);//初始位置到地心的变换矩阵
    Cesium.Matrix4.multiply(backToEarthCenterMatrix, originMatrix, backToEarthCenterMatrix);//移动模型到地心的矩阵

    // 旋转模型使得Z轴与世界坐标Z轴重合
    let arrowX = new Cesium.Cartesian3(1, 0, 0);
    let arrowZ = new Cesium.Cartesian3(0, 0, 1);
    let angleToXZ = Cesium.Cartesian3.angleBetween(arrowX, new Cesium.Cartesian3(origin.x, origin.y, 0));//局部Z轴在世界坐标系XY平面上投影到X轴角度,即绕Z顺时针旋转这个角度可以到XZ平面上
    let angleToZ = Cesium.Cartesian3.angleBetween(origin, arrowZ);//然后绕Y轴顺时针旋转此角度可使得Z轴与世界坐标系Z轴重合
    const rotationAngleToXZ = Cesium.Matrix3.fromRotationZ((origin.y>0?-1:+1)*angleToXZ);//绕Z轴旋转的Matrix3矩阵,正角度逆时针旋转
    const rotationAngleToZ = Cesium.Matrix3.fromRotationY(-angleToZ);//绕Y轴旋转的Matrix3矩阵,负角度顺时针旋转
    let rotationAngleToZMatrix = Cesium.Matrix3.multiply(rotationAngleToZ, rotationAngleToXZ, new Cesium.Matrix3);//连续旋转的Matrix3矩阵,即先绕Z轴旋转,后绕Y旋转的矩阵。
    rotationAngleToZMatrix = Cesium.Matrix4.fromRotationTranslation(rotationAngleToZMatrix);//连续旋转的Matrix4矩阵
    Cesium.Matrix4.multiply(rotationAngleToZMatrix, backToEarthCenterMatrix, rotationAngleToZMatrix);//将移动至地心模型,旋转至Z轴重合的矩阵

    // 旋转模型使得X,Y轴与世界坐标X,Y轴重合
    const rotationZ = Cesium.Matrix3.fromRotationZ(-Math.PI/2); // 绕Z轴旋转90°的Matrix3变换矩阵
    let rotationMatrix = Cesium.Matrix4.fromRotationTranslation(rotationZ); // 绕Z轴旋转90°的Matrix4变换矩阵
    Cesium.Matrix4.multiply(rotationMatrix, rotationAngleToZMatrix, rotationMatrix);//将移动至地心模型的物体坐标系,旋转到与世界坐标系重合的矩阵

    //在地心位置,旋转物体坐标系和世界坐标系重合的模型,使得与目标坐标系重合
    const offsetToWorldMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(offset);//获取到以目标位置为原点,的eastNorthUp局部坐标系的变换矩阵
    const backToEarthCenterOffset = new Cesium.Cartesian3(-offset.x, -offset.y, -offset.z);//目标位置到地心的位移向量
    let backToEarthCenterMatrixOffset = Cesium.Matrix4.fromTranslation(backToEarthCenterOffset);//目标位置到地心的变换矩阵
    Cesium.Matrix4.multiply(backToEarthCenterMatrixOffset, offsetToWorldMatrix, backToEarthCenterMatrixOffset);//获得从世界坐标系旋转至目标坐标系的旋转矩阵(只有旋转,没有位移)
    Cesium.Matrix4.multiply(backToEarthCenterMatrixOffset, rotationMatrix, backToEarthCenterMatrixOffset);//将移动至地心模型的物体坐标系,旋转到与目标坐标系重合的矩阵(完成模型的最终旋转,没有位移)
 
    //移动到目标位置
    const backToOriginMatrix = Cesium.Matrix4.fromTranslation(offset);//地心到目标位置位移向量
    const lastMatrix = Cesium.Matrix4.multiply(backToOriginMatrix,backToEarthCenterMatrixOffset,new Cesium.Matrix4());//最终矩阵,即将地心位置的模型移动到目标位置(完成模型的最终旋转,最终位移)
    console.log('最终变换矩阵',lastMatrix);
    return lastMatrix //返回最终变换矩阵
}
let tileset = viewer.scene.primitives.add(
      new Cesium.Cesium3DTileset({
        url: ".../tileset.json",
      })
    );
    
    tileset.readyPromise.then(function (tileset) {
      window.tileset = tileset
      let longitude = 104.98680
      let latitude = 32.20795
      let height = 100
      let modelMatrix = moveModel(tileset,longitude,latitude,height)
      tileset.modelMatrix = modelMatrix;//移动模型
      // 创建圆形包围盒
      let boundingSphere = new Cesium.BoundingSphere(
        tileset.boundingSphere.center,
        tileset.boundingSphere.radius
      );
      //飞向该包围盒
      viewer.camera.flyToBoundingSphere(boundingSphere);
    });

  • 13
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值