概述
Cesium 中包含兩種添加 model 的方法,分別為:
- 通過
viewer.entities.add()
函數添加 - 通過
viewer.scene.primitives.add()
函數添加
兩種方法本質上是相通的,方法 1
對方法 2
在某種程度上進行了封裝。
兩種方法的區別
表面區別
方法 1
通過指定 model 的 position 和 orientation 來控制模型的位置,對模型進行精確變換的難度較大;方法 2
通過 modelMatrix 控制模型的位置和方向,可進行較為精確的模型變換。- 對相機操作時
方法 1
提供了較為方便的 viewer.trackedEntity 函數;方法 2
追蹤 model 較為復雜,需要手動操作相機變換。 - 對模型進行縮放、變換等操作,
方法 1
需要修改 object.id(Entity 類型) 中 model(ModelGraphics 類型) 的 scale 和 nodeTransformations;方法 2
可以直接修改 object.primitive(model 類型) 中的 scale 和 modelMatrix。
深層探究
分別使用方法 1
和方法 2
建立兩個模型,然后對其進行點擊操作,查看點擊得到的物體,方法 1
和方法 2
返回的都為同樣的 object 對象,其結構如下所示。
{
id: object
mesh: ModelMesh
node: ModeNode
primitive: Model
}
其不同的是,方法 2
中的 id 對象為用戶自定義對象,方法 1
中的 Entity 對象。因此方法 1
相當於首先通過 方法 2
中的 Cesium.Model.fromGltf() 函數建立 Model,通過該 Model 建立對應的 Entity(方法暫未嘗試,因為 Entity 構造函數中的 options.model 接收的是 ModelGraphics 類型,而不是 Model 類型),將 Entity 賦予對象的 id 屬性,實現雙向綁定,具體的實現可能要參考 viewer.entities.add() 的源碼實現。
從 Entity 獲得 Model 的方法
function getModelForEntity(entity) {
var primitives = viewer.scene.primitives;
for (var i = 0; i < primitives.length; i++) {
var primitive = primitives.get(i);
if (primitive instanceof Cesium.Model && primitive.id === entity) {
return primitive;
}
}
};
其它知識點
構建的對象中還包含 ModelMesh 和 ModeNode,ModelMesh 中包含了模型的網格和材質,ModeNode 中包含了一個 transform,可以在運行時對模型進行動態變換,以實現自定義模型動畫。
示例代碼
- 方法1
function createModel(url, height) {
viewer.entities.removeAll();
var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, height);
var heading = Cesium.Math.toRadians(135);
var pitch = 0;
var roll = 0;
var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr);
var entity = viewer.entities.add({
name : url,
position : position,
orientation : orientation,
model : {
uri : url,
minimumPixelSize : 128,
maximumScale : 20000
}
});
viewer.trackedEntity = entity;
}
- 方法2
function createModel(url, height, heading, pitch, roll) {
height = Cesium.defaultValue(height, 0.0);
heading = Cesium.defaultValue(heading, 0.0);
pitch = Cesium.defaultValue(pitch, 0.0);
roll = Cesium.defaultValue(roll, 0.0);
var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
var origin = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, height);
var modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(origin, hpr);
scene.primitives.removeAll(); // Remove previous model
model = scene.primitives.add(Cesium.Model.fromGltf({
url : url,
modelMatrix : modelMatrix,
minimumPixelSize : 128
}));
model.readyPromise.then(function(model) {
model.color = Cesium.Color.fromAlpha(getColor(viewModel.color), Number(viewModel.alpha));
model.colorBlendMode = getColorBlendMode(viewModel.colorBlendMode);
model.colorBlendAmount = viewModel.colorBlendAmount;
// Play and loop all animations at half-speed
model.activeAnimations.addAll({
speedup : 0.5,
loop : Cesium.ModelAnimationLoop.REPEAT
});
var camera = viewer.camera;
// Zoom to model
var controller = scene.screenSpaceCameraController;
var r = 2.0 * Math.max(model.boundingSphere.radius, camera.frustum.near);
controller.minimumZoomDistance = r * 0.5;
var center = Cesium.Matrix4.multiplyByPoint(model.modelMatrix, model.boundingSphere.center, new Cesium.Cartesian3());
var heading = Cesium.Math.toRadians(230.0);
var pitch = Cesium.Math.toRadians(-20.0);
camera.lookAt(center, new Cesium.HeadingPitchRange(heading, pitch, r * 2.0));
}).otherwise(function(error){
window.alert(error);
});
}