Cesium設(shè)置模型朝向速度矢量方向
1. 需求場(chǎng)景
現(xiàn)有一段飛機(jī)起飛、爬升的軌跡數(shù)據(jù),需要在Cesium中模擬出飛行過程動(dòng)畫,要求飛機(jī)模型的姿態(tài)隨著速度矢量方向變化,而不是一直保持飛機(jī)模型的原始狀態(tài)。
2. 技術(shù)路線
在Cesium.Entity
類中有屬性orientation
可以用來控制實(shí)體模型model
的朝向,當(dāng)不設(shè)置該屬性時(shí),模型就保持原始狀態(tài)。如下圖所示:
根據(jù)需求,飛機(jī)模型應(yīng)該向上仰起來,有兩種方式可以達(dá)到目標(biāo)。
2.1 VelocityOrientationProperty
Cesium提供了VelocityOrientationProperty
類,通過該類可以直接設(shè)置實(shí)體的orientation
屬性,其內(nèi)部會(huì)自動(dòng)計(jì)算速度矢量,設(shè)置后飛機(jī)模型就會(huì)沿著速度矢量的方向,官方文檔示例代碼:
// 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)
}));
實(shí)際應(yīng)用時(shí)示例代碼:
entity.orientation = new Cesium.VelocityOrientationProperty(entity.position);
效果如下圖:
2.2 VelocityVectorProperty
第一種方式基本就可以解決問題,但是有一種情況:三維模型本身有問題,有些三維模型從其他格式轉(zhuǎn)換過來,在導(dǎo)入到Cesium后會(huì)發(fā)現(xiàn)有翻轉(zhuǎn)、角度偏移等現(xiàn)象,需要在上一步的基礎(chǔ)上(先將模型變換到速度矢量方向),再進(jìn)行一些模型旋轉(zhuǎn)變換。
通過VelocityVectorProperty
可以計(jì)算出速度矢量,通過速度矢量、要沿參考軸旋轉(zhuǎn)的角度(heading、pitch、rool)就可以計(jì)算出最終的朝向四元數(shù)(quaternion),將該四元數(shù)設(shè)置給實(shí)體的orientation
屬性即可。
核心代碼如下:
/**
* 計(jì)算朝向四元數(shù)
* X軸正向指向運(yùn)動(dòng)方向;Y軸在水平面內(nèi)垂直于X軸,正向指向右側(cè);Z軸通過右手法則確定
* @param {Cartesian3} position 位置
* @param {Cartesian3} velocity 速度向量
* @param {*} rotateX 繞X軸旋轉(zhuǎn)的角度(roll)
* @param {*} rotateY 繞Y軸旋轉(zhuǎn)的角度(pitch)
* @param {*} rotateZ 繞Z軸旋轉(zhuǎn)的角度(heading)
* @returns
*/
function getQuaternion(position, velocity, rotateX, rotateY, rotateZ) {
// 1、計(jì)算站心到模型坐標(biāo)系的旋轉(zhuǎn)平移矩陣
// 速度歸一化
let normal = Cesium.Cartesian3.normalize(velocity, new Cesium.Cartesian3());
// 計(jì)算模型坐標(biāo)系的旋轉(zhuǎn)矩陣
let satRotationMatrix = Cesium.Transforms.rotationMatrixFromPositionVelocity(position, normal, Cesium.Ellipsoid.WGS84);
// 模型坐標(biāo)系到地固坐標(biāo)系旋轉(zhuǎn)平移矩陣
let m = Cesium.Matrix4.fromRotationTranslation(satRotationMatrix, position);
// 站心坐標(biāo)系(東北天坐標(biāo)系)到地固坐標(biāo)系旋轉(zhuǎn)平移矩陣
var m1 = Cesium.Transforms.eastNorthUpToFixedFrame(position, Cesium.Ellipsoid.WGS84, new Cesium.Matrix4());
// 站心到模型坐標(biāo)系的旋轉(zhuǎn)平移矩陣
let m3 = Cesium.Matrix4.multiply(Cesium.Matrix4.inverse(m1, new Cesium.Matrix4()), m, new Cesium.Matrix4());
// 2、模型姿態(tài)旋轉(zhuǎn)矩陣
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、最終的旋轉(zhuǎn)矩陣
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;
}
控制臺(tái)測(cè)試代碼:
// 當(dāng)前時(shí)刻速度向量、位置
let curVelocityVector = entity.velocityVector.getValue(viewer.clock.currentTime, new Cesium.Cartesian3());
let curPosition = entity.position.getValue(viewer.clock.currentTime, new Cesium.Cartesian3());
// 計(jì)算朝向四元數(shù)
var quaternion = getQuaternion(curPosition, curVelocityVector);
// 設(shè)置實(shí)體朝向,驗(yàn)證是否指向速度矢量方向
entity.orientation = quaternion;
實(shí)際應(yīng)用代碼:文章來源:http://www.zghlxwxcb.cn/news/detail-684919.html
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);
// 獲取實(shí)體
entity = viewer.dataSources.getByName("1610994859816914946")[0].entities.getById("1610994859816914946");
// 添加屬性:速度向量
entity.velocityVector = new Cesium.VelocityVectorProperty(entity.position, true);
/* // 當(dāng)前時(shí)刻速度向量、位置
let curVelocityVector = entity.velocityVector.getValue(viewer.clock.currentTime, new Cesium.Cartesian3());
let curPosition = entity.position.getValue(viewer.clock.currentTime, new Cesium.Cartesian3());
// 計(jì)算朝向四元數(shù)
var quaternion = getQuaternion(curPosition, curVelocityVector);
// 設(shè)置實(shí)體朝向,驗(yàn)證是否指向速度矢量方向
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());
// 計(jì)算朝向四元數(shù)
var quaternion = getQuaternion(curPosition, curVelocityVector, rotateX, rotateY, rotateZ);
// 添加采樣值
property.addSample(time, quaternion);
});
}
}
// 將轉(zhuǎn)換后的四元數(shù)設(shè)置給實(shí)體
entity.orientation = property;
})
Sandcastle.finishedLoading();
}
if (typeof Cesium !== "undefined") {
window.startupCalled = true;
startup(Cesium);
}
/**
* 計(jì)算朝向四元數(shù)
* X軸正向指向運(yùn)動(dòng)方向;Y軸在水平面內(nèi)垂直于X軸,正向指向右側(cè);Z軸通過右手法則確定
* @param {Cartesian3} position 位置
* @param {Cartesian3} velocity 速度向量
* @param {*} rotateX 繞X軸旋轉(zhuǎn)的角度(roll)
* @param {*} rotateY 繞Y軸旋轉(zhuǎn)的角度(pitch)
* @param {*} rotateZ 繞Z軸旋轉(zhuǎn)的角度(heading)
* @returns
*/
function getQuaternion(position, velocity, rotateX, rotateY, rotateZ) {
// 1、計(jì)算站心到模型坐標(biāo)系的旋轉(zhuǎn)平移矩陣
// 速度歸一化
let normal = Cesium.Cartesian3.normalize(velocity, new Cesium.Cartesian3());
// 計(jì)算模型坐標(biāo)系的旋轉(zhuǎn)矩陣
let satRotationMatrix = Cesium.Transforms.rotationMatrixFromPositionVelocity(position, normal, Cesium.Ellipsoid.WGS84);
// 模型坐標(biāo)系到地固坐標(biāo)系旋轉(zhuǎn)平移矩陣
let m = Cesium.Matrix4.fromRotationTranslation(satRotationMatrix, position);
// 站心坐標(biāo)系(東北天坐標(biāo)系)到地固坐標(biāo)系旋轉(zhuǎn)平移矩陣
var m1 = Cesium.Transforms.eastNorthUpToFixedFrame(position, Cesium.Ellipsoid.WGS84, new Cesium.Matrix4());
// 站心到模型坐標(biāo)系的旋轉(zhuǎn)平移矩陣
let m3 = Cesium.Matrix4.multiply(Cesium.Matrix4.inverse(m1, new Cesium.Matrix4()), m, new Cesium.Matrix4());
// 2、模型姿態(tài)旋轉(zhuǎn)矩陣
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、最終的旋轉(zhuǎn)矩陣
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】計(jì)算模型的朝向四元數(shù),實(shí)現(xiàn)模型運(yùn)動(dòng)中調(diào)整朝向文章來源地址http://www.zghlxwxcb.cn/news/detail-684919.html
到了這里,關(guān)于Cesium設(shè)置模型朝向速度矢量方向的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!