Cesium设置模型朝向速度矢量方向
文章目录
1. 需求场景
现有一段飞机起飞、爬升的轨迹数据,需要在Cesium中模拟出飞行过程动画,要求飞机模型的姿态随着速度矢量方向变化,而不是一直保持飞机模型的原始状态。
2. 技术路线
在
Cesium.Entity
类中有属性
orientation
可以用来控制实体模型
model
的朝向,当不设置该属性时,模型就保持原始状态。如下图所示:
根据需求,飞机模型应该向上仰起来,有两种方式可以达到目标。
2.1 VelocityOrientationProperty
Cesium提供了
VelocityOrientationProperty
类,通过该类可以直接设置实体的
orientation
属性,其内部会自动计算速度矢量,设置后飞机模型就会沿着速度矢量的方向,官方文档示例代码:
// Create an entity with position and orientation.var position =newCesium.SampledProperty();
position.addSamples(...);var entity = viewer.entities.add({position: position,orientation:newCesium.VelocityOrientationProperty(position)}));
实际应用时示例代码:
entity.orientation =newCesium.VelocityOrientationProperty(entity.position);
效果如下图:
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
*/functiongetQuaternion(position, velocity, rotateX, rotateY, rotateZ){// 1、计算站心到模型坐标系的旋转平移矩阵// 速度归一化let normal = Cesium.Cartesian3.normalize(velocity,newCesium.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,newCesium.Matrix4());// 站心到模型坐标系的旋转平移矩阵let m3 = Cesium.Matrix4.multiply(Cesium.Matrix4.inverse(m1,newCesium.Matrix4()), m,newCesium.Matrix4());// 2、模型姿态旋转矩阵
rotateX = rotateX ||0;
rotateY = rotateY ||0;
rotateZ = rotateZ ||0;let heading = rotateZ, pitch = rotateY, roll = rotateX;let postureHpr =newCesium.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,newCesium.Matrix3());let finalMatrix = Cesium.Matrix3.multiply(mat3, postureMatrix,newCesium.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,newCesium.Cartesian3());let curPosition = entity.position.getValue(viewer.clock.currentTime,newCesium.Cartesian3());// 计算朝向四元数var quaternion =getQuaternion(curPosition, curVelocityVector);// 设置实体朝向,验证是否指向速度矢量方向
entity.orientation = quaternion;
实际应用代码:
var viewer, entity;functionstartup(Cesium){"use strict";//Sandcastle_Begin
viewer =newCesium.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 =newCesium.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 =newCesium.SampledProperty(Cesium.Quaternion);if(entity.position instanceofCesium.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,newCesium.Cartesian3());let curPosition = entity.position.getValue(time,newCesium.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
*/functiongetQuaternion(position, velocity, rotateX, rotateY, rotateZ){// 1、计算站心到模型坐标系的旋转平移矩阵// 速度归一化let normal = Cesium.Cartesian3.normalize(velocity,newCesium.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,newCesium.Matrix4());// 站心到模型坐标系的旋转平移矩阵let m3 = Cesium.Matrix4.multiply(Cesium.Matrix4.inverse(m1,newCesium.Matrix4()), m,newCesium.Matrix4());// 2、模型姿态旋转矩阵
rotateX = rotateX ||0;
rotateY = rotateY ||0;
rotateZ = rotateZ ||0;let heading = rotateZ, pitch = rotateY, roll = rotateX;let postureHpr =newCesium.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,newCesium.Matrix3());let finalMatrix = Cesium.Matrix3.multiply(mat3, postureMatrix,newCesium.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】计算模型的朝向四元数,实现模型运动中调整朝向
版权归原作者 wml00000 所有, 如有侵权,请联系我们删除。