Cesium设置模型朝向速度矢量方向

这篇具有很好参考价值的文章主要介绍了Cesium设置模型朝向速度矢量方向。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Cesium设置模型朝向速度矢量方向

1. 需求场景

现有一段飞机起飞、爬升的轨迹数据,需要在Cesium中模拟出飞行过程动画,要求飞机模型的姿态随着速度矢量方向变化,而不是一直保持飞机模型的原始状态。

2. 技术路线

Cesium.Entity类中有属性orientation 可以用来控制实体模型model的朝向,当不设置该属性时,模型就保持原始状态。如下图所示:

cesium调整模型方向,Cesium,前端

根据需求,飞机模型应该向上仰起来,有两种方式可以达到目标。

2.1 VelocityOrientationProperty

Cesium提供了VelocityOrientationProperty类,通过该类可以直接设置实体的orientation属性,其内部会自动计算速度矢量,设置后飞机模型就会沿着速度矢量的方向,官方文档示例代码:

// Create an entity with position and orientation.
var position = new Cesium.SampledProperty();
position.addSamples(...);
var entity = viewer.entities.add({
  position : position,
  orientation : new Cesium.VelocityOrientationProperty(position)
}));

实际应用时示例代码:

entity.orientation = new Cesium.VelocityOrientationProperty(entity.position);

效果如下图:

cesium调整模型方向,Cesium,前端

2.2 VelocityVectorProperty

第一种方式基本就可以解决问题,但是有一种情况:三维模型本身有问题,有些三维模型从其他格式转换过来,在导入到Cesium后会发现有翻转、角度偏移等现象,需要在上一步的基础上(先将模型变换到速度矢量方向),再进行一些模型旋转变换。

通过VelocityVectorProperty可以计算出速度矢量,通过速度矢量、要沿参考轴旋转的角度(heading、pitch、rool)就可以计算出最终的朝向四元数(quaternion),将该四元数设置给实体的orientation属性即可。

核心代码如下:

    /**
     * 计算朝向四元数
     * X轴正向指向运动方向;Y轴在水平面内垂直于X轴,正向指向右侧;Z轴通过右手法则确定
     * @param {Cartesian3} position 位置
     * @param {Cartesian3} velocity 速度向量
     * @param {*} rotateX 绕X轴旋转的角度(roll)
     * @param {*} rotateY 绕Y轴旋转的角度(pitch)
     * @param {*} rotateZ 绕Z轴旋转的角度(heading)
     * @returns 
     */
    function getQuaternion(position, velocity, rotateX, rotateY, rotateZ) {
      // 1、计算站心到模型坐标系的旋转平移矩阵
      // 速度归一化
      let normal = Cesium.Cartesian3.normalize(velocity, new Cesium.Cartesian3());
      // 计算模型坐标系的旋转矩阵
      let satRotationMatrix = Cesium.Transforms.rotationMatrixFromPositionVelocity(position, normal, Cesium.Ellipsoid.WGS84);
      // 模型坐标系到地固坐标系旋转平移矩阵
      let m = Cesium.Matrix4.fromRotationTranslation(satRotationMatrix, position);
      // 站心坐标系(东北天坐标系)到地固坐标系旋转平移矩阵
      var m1 = Cesium.Transforms.eastNorthUpToFixedFrame(position, Cesium.Ellipsoid.WGS84, new Cesium.Matrix4());
      // 站心到模型坐标系的旋转平移矩阵
      let m3 = Cesium.Matrix4.multiply(Cesium.Matrix4.inverse(m1, new Cesium.Matrix4()), m, new Cesium.Matrix4());

      // 2、模型姿态旋转矩阵
      rotateX = rotateX || 0;
      rotateY = rotateY || 0;
      rotateZ = rotateZ || 0;
      let heading = rotateZ, pitch = rotateY, roll = rotateX;
      let postureHpr = new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(heading), Cesium.Math.toRadians(pitch), Cesium.Math.toRadians(roll));
      let postureMatrix = Cesium.Matrix3.fromHeadingPitchRoll(postureHpr);

      // 3、最终的旋转矩阵
      let mat3 = Cesium.Matrix4.getMatrix3(m3, new Cesium.Matrix3());
      let finalMatrix = Cesium.Matrix3.multiply(mat3, postureMatrix, new Cesium.Matrix3());
      let quaternion1 = Cesium.Quaternion.fromRotationMatrix(finalMatrix);
      let hpr = Cesium.HeadingPitchRoll.fromQuaternion(quaternion1);
      let q2 = Cesium.Transforms.headingPitchRollQuaternion(position, hpr);
      return q2;
    }

控制台测试代码:

        // 当前时刻速度向量、位置
        let curVelocityVector = entity.velocityVector.getValue(viewer.clock.currentTime, new Cesium.Cartesian3());
        let curPosition = entity.position.getValue(viewer.clock.currentTime, new Cesium.Cartesian3());
        // 计算朝向四元数
        var quaternion = getQuaternion(curPosition, curVelocityVector);
        // 设置实体朝向,验证是否指向速度矢量方向
        entity.orientation = quaternion;

实际应用代码:

var viewer, entity;
    function startup(Cesium) {
      "use strict";
      //Sandcastle_Begin
      viewer = new Cesium.Viewer("cesiumContainer");
      var scene = viewer.scene;

      // Cesium查看器
      viewer.extend(Cesium.viewerCesiumInspectorMixin);

      // CZML中的orientation并不考虑速度矢量方向
      let dataSourcePromise = Cesium.CzmlDataSource.load("../../SampleData/CZML/Aircraft2.czml");
      dataSourcePromise.then(function (dataSource) {
        viewer.dataSources.add(dataSource);

        // 获取实体
        entity = viewer.dataSources.getByName("1610994859816914946")[0].entities.getById("1610994859816914946");

        // 添加属性:速度向量
        entity.velocityVector = new Cesium.VelocityVectorProperty(entity.position, true);

        /* // 当前时刻速度向量、位置
        let curVelocityVector = entity.velocityVector.getValue(viewer.clock.currentTime, new Cesium.Cartesian3());
        let curPosition = entity.position.getValue(viewer.clock.currentTime, new Cesium.Cartesian3());
        // 计算朝向四元数
        var quaternion = getQuaternion(curPosition, curVelocityVector);
        // 设置实体朝向,验证是否指向速度矢量方向
        entity.orientation = quaternion; */


        let rotateX = 0;
        let rotateY = 0;
        let rotateZ = 0;
        var property = new Cesium.SampledProperty(Cesium.Quaternion);
        if (entity.position instanceof Cesium.CompositePositionProperty) {
          let intervals = entity.position.intervals;
          for (let i = 0; i < intervals.length; i++) {
            const interval = intervals.get(i);
            let positions = interval.data._property._values;
            interval.data._property._times.forEach((time, index) => {

              let curVelocityVector = entity.velocityVector.getValue(time, new Cesium.Cartesian3());
              let curPosition = entity.position.getValue(time, new Cesium.Cartesian3());
              // 计算朝向四元数
              var quaternion = getQuaternion(curPosition, curVelocityVector, rotateX, rotateY, rotateZ);
              // 添加采样值
              property.addSample(time, quaternion);
            });
          }
        }

        // 将转换后的四元数设置给实体
        entity.orientation = property;
      })


      Sandcastle.finishedLoading();
    }
    if (typeof Cesium !== "undefined") {
      window.startupCalled = true;
      startup(Cesium);
    }

    /**
     * 计算朝向四元数
     * X轴正向指向运动方向;Y轴在水平面内垂直于X轴,正向指向右侧;Z轴通过右手法则确定
     * @param {Cartesian3} position 位置
     * @param {Cartesian3} velocity 速度向量
     * @param {*} rotateX 绕X轴旋转的角度(roll)
     * @param {*} rotateY 绕Y轴旋转的角度(pitch)
     * @param {*} rotateZ 绕Z轴旋转的角度(heading)
     * @returns 
     */
    function getQuaternion(position, velocity, rotateX, rotateY, rotateZ) {
      // 1、计算站心到模型坐标系的旋转平移矩阵
      // 速度归一化
      let normal = Cesium.Cartesian3.normalize(velocity, new Cesium.Cartesian3());
      // 计算模型坐标系的旋转矩阵
      let satRotationMatrix = Cesium.Transforms.rotationMatrixFromPositionVelocity(position, normal, Cesium.Ellipsoid.WGS84);
      // 模型坐标系到地固坐标系旋转平移矩阵
      let m = Cesium.Matrix4.fromRotationTranslation(satRotationMatrix, position);
      // 站心坐标系(东北天坐标系)到地固坐标系旋转平移矩阵
      var m1 = Cesium.Transforms.eastNorthUpToFixedFrame(position, Cesium.Ellipsoid.WGS84, new Cesium.Matrix4());
      // 站心到模型坐标系的旋转平移矩阵
      let m3 = Cesium.Matrix4.multiply(Cesium.Matrix4.inverse(m1, new Cesium.Matrix4()), m, new Cesium.Matrix4());

      // 2、模型姿态旋转矩阵
      rotateX = rotateX || 0;
      rotateY = rotateY || 0;
      rotateZ = rotateZ || 0;
      let heading = rotateZ, pitch = rotateY, roll = rotateX;
      let postureHpr = new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(heading), Cesium.Math.toRadians(pitch), Cesium.Math.toRadians(roll));
      let postureMatrix = Cesium.Matrix3.fromHeadingPitchRoll(postureHpr);

      // 3、最终的旋转矩阵
      let mat3 = Cesium.Matrix4.getMatrix3(m3, new Cesium.Matrix3());
      let finalMatrix = Cesium.Matrix3.multiply(mat3, postureMatrix, new Cesium.Matrix3());
      let quaternion1 = Cesium.Quaternion.fromRotationMatrix(finalMatrix);
      let hpr = Cesium.HeadingPitchRoll.fromQuaternion(quaternion1);
      let q2 = Cesium.Transforms.headingPitchRollQuaternion(position, hpr);
      return q2;
    }

3. 参考链接

[1]. 【Cesium】计算模型的朝向四元数,实现模型运动中调整朝向文章来源地址https://www.toymoban.com/news/detail-684919.html

到了这里,关于Cesium设置模型朝向速度矢量方向的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Cesium:3DTiles三维模型高度调整

            地形遮挡属性          如下两张图所示,输入高度值,根据需要调整模型高度。例如:针对近地面的管线数据,可能有一部分是埋在地下的,那么,如果开启了地形遮挡属性(即:设置为true,默认是false),那么,在进行场景渲染加载模型切片时,就会进行深度测

    2024年02月11日
    浏览(73)
  • Cesium示例程序学习和讲解(4)-调整3DTiles模型高度

    本节主要讲解的内容? 在三维场景中如何加载3dtiles模型,如何调整模型在场景中的高度 涉及的主要接口有? Cesium3DTileset、HeadingPitchRange、Cartographic、Matrix4 介绍下HeadingPitchRange接口接相关参数介绍? 当使用Cesium框架进行三维场景渲染时,常常需要在场景中创建相机视图。而

    2024年02月10日
    浏览(30)
  • Cesium 实战 - Blender调整模型组件原点,实现直升机尾翼旋转

    某个项目需求,在操作直升机模型的时候,希望直升机机翼和尾翼旋转起来。 机翼旋转比较容易,找到组件名称,按照之前的 《Cesium 实战 - AGI_articulations 扩展:模型自定义关节动作》设置即可实现。 但是在设置尾翼的时候,出现问题,这里记录一下问题以及解决方法。 本

    2024年02月15日
    浏览(49)
  • Cesium加载ArcGIS的PBF矢量切片服务

    在 Cesium 中,我们使用的地图服务均为传统的栅格切片服务 。即在服务端渲染好图片并进行切片,客户端请求获取图片后直接显示。 而矢量切片则有别于传统的栅格切片,它在服务端切片存储的是矢量数据的描述文件,最终的渲染在客户端完成。 事实上矢量切片技术目前已

    2024年02月05日
    浏览(26)
  • Cesium 3Dtiles偏移调整

    Cesium 3Dtiles偏移调整可以通过以下步骤进行: 根据前后经纬度和高度计算变换矩阵-平移矩阵: step1: 根据tileset的边界球体中心点的笛卡尔坐标得到经纬度坐标。 step2: 根据经纬度和高度0,得到地面笛卡尔坐标。 step3: 根据经纬度和需要的高度,得到偏移后的笛卡尔坐标。 st

    2024年01月25日
    浏览(32)
  • Cesium 实战教程 - 调整 3dtiles 倾斜摄影大小

    之前由于误解遇到一个特殊的需求: 想要把三维球上叠加倾斜摄影进行自由放大缩小,跟随地图的缩放进行缩放。 后来经过搜索、尝试,终于实现了需求。 但是,后来发现是误解需求了,甲方只是需要放大缩小地图,不需要改变倾斜摄影的比例。 不过也算是学习了一个功能

    2024年02月12日
    浏览(29)
  • 【Cesium】调整3DTile/tileset的位置到某个经纬度/某个地点/城市

    前提: 模型本身有地理位置信息,模型本身就能显示在地球表面了(而不是在地表下的球心或其他奇奇怪怪的位置) 以下是将tileset的位置调整到北京(在WGS84坐标系下)的正确代码: 在以上代码中,我们首先获取tileset的中心点坐标,并将其转换为WGS84坐标系下的经纬度。然后,我

    2024年02月12日
    浏览(31)
  • 【Cesium学习(六)】Cesium加载3D模型(3D tiles和glTF模型)

    前面我们学习到了绘制基本的形状,但是Cesium还可以加载3D模型,因为像高德地图这种的技术来加载大型复杂的建筑模型性能不加,所有只能想Cesium这种专门做3D地图的技术。接下来就学习一下如何加载模型。 Cesium目前支持两种模型方案,一个是使用3D tiles, 另一个是加载g

    2024年02月07日
    浏览(36)
  • 056:cesium 七种方法设置颜色

    第056个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中设置颜色,这里用到了7种方法,查看API,还有很多种方法 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 示例效果

    2024年02月05日
    浏览(22)
  • cesium中3dtiles贴地问题设置

    当我们转换得到3dtiles格式数据后,将数据添加到cesium中:   模型可能出现以下不贴地的情况: 对于此类问题,解决办法参考如下: 模型定位: 修改后,模型贴地显示如下(设置不同的偏移量可以获得不同高度的模型): 

    2024年02月11日
    浏览(21)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包