實際Cesium 項目中添加了部分貼地的資源。資源類型有圖片,gltf或者glb的模型。這裏簡單比較一下primitive 和entity。
primitive 基於比較底層的webgl技術,進行渲染資源,所以對於很多自定義的效果支持比較好,靈活度比較高,帶來的開銷就是API複雜,參數多,單獨相對大。
entity, 是對primitive的封裝,操作簡單,一般的效果都能滿足。
本次項目中是爲了通過座標系,變換實體模型對象。目前知道的就是通過primitive加進去的模型,支持座標變換。其他的應該也有,但是沒接觸到。
先看一下效果
其實有兩種思路處理這個問題,一種是做一個glb的模型,另一外一種是通過圖片作爲材質創建primitive對象。實際驗證的效果是通過glb模型創建添加的資源,可以實現座標系的編輯,通過圖片作爲材質創建的primitive對象,無法完成座標變換。調試發現是因爲圖片添加的primitive modelMatrix 爲空。可能也和我操作有關,我親自測試失敗了。
作爲glb模型添加
var targetPosition = Cesium.Cartesian3.fromDegrees(pos[0], pos[1], pos[2] + 0.5);
var headingPitchRoll = new Cesium.HeadingPitchRoll(0, 0, 0);
var modelMatrix = new Cesium.Matrix4();
var modelEntity;
Cesium.Transforms.headingPitchRollToFixedFrame(targetPosition, headingPitchRoll, Cesium.Ellipsoid.WGS84, Cesium.Transforms.eastNorthUpToFixedFrame, modelMatrix);
window.setTimeout(function() {
modelEntity = viewer.scene.primitives.add(Cesium.Model.fromGltf({
id: src_manager._GenGuid("3d_geo_"),
name: name,
url: url,
modelMatrix: modelMatrix,
scale: 2,
colorBlendMode: Cesium.ColorBlendMode.HIGHLIGHT
}));
modelEntity.readyPromise.then(function(modeltemp) {
});
}, 500);
作爲圖片添加的primitive對象,參考鏈接https://zhuanlan.zhihu.com/p/41862338
function addDevImg(pos, size, url) {
var dimensions = new Cesium.Cartesian3(size, size, 1.0);
var positionOnEllipsoid = Cesium.Cartesian3.fromDegrees(parseFloat(pos[0]), parseFloat(pos[1]));
var translateMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(positionOnEllipsoid);
var rotationYMatrix = Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromRotationY(Cesium.Math.toRadians(120.0)));
var scaleMatrix = Cesium.Matrix4.fromScale(dimensions);
var planeYModelMatrix = new Cesium.Matrix4();
Cesium.Matrix4.multiply(translateMatrix, rotationYMatrix, planeYModelMatrix);
Cesium.Matrix4.multiply(planeYModelMatrix, scaleMatrix, planeYModelMatrix);
createPlane(planeYModelMatrix, new Cesium.Color(0.0, 1.0, 0.0, 1.0));
function createPlane(planeModelMatrix, color) {
// 創建平面
/*var planeGeometry = new Cesium.PlaneGeometry({
vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
});*/
var planeGeometry = new Cesium.PlaneGeometry();
var planeGeometryInstance = new Cesium.GeometryInstance({
geometry: planeGeometry,
modelMatrix: planeModelMatrix,
});
var material = new Cesium.Material({
fabric: {
type: "DiffuseMap",
uniforms: {
image: url,
},
},
});
var model = viewer.scene.primitives.add(new Cesium.Primitive({
geometryInstances: planeGeometryInstance,
appearance: new Cesium.MaterialAppearance({
closed: false,
//translucent: false,
material: material
})
}));
}
}
通過座標系拾取模型對象進行座標變換。
function rotateTranslation(viewer) {
//handler && handler.destroy();
var timeoutID = null;
if (!window.roate_handler) {
window.roate_handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
}
//var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
var tooltip;
window.roate_handler.setInputAction(function(movement) {
tooltip = document.getElementById("toolTip");
tooltip.innerHTML = '<p style="color:red;font-size:16px;">單擊選擇單體模型</p>';
tooltip.style.display = "block";
tooltip.style.left = movement.endPosition.x + 3 + "px";
tooltip.style.top = movement.endPosition.y - 25 + "px";
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
//鼠標左擊
window.roate_handler.setInputAction(function(movement) {
if (timeoutID != null) {
clearTimeout(timeoutID);
}
var picked = viewer.scene.pick(movement.position);
if (Cesium.defined(picked)) {
if (picked.primitive) {
var model = picked.primitive;
var scale = model.boundingSphere.radius;
timeoutID = window.setTimeout(function() {
if (window.axisModel) {
viewer.scene.primitives.remove(window.axisModel);
}
var axisModel = viewer.scene.primitives.add(Cesium.Model.fromGltf({
url: '../../Build/DECore/models/TransformGizmo_Tex12.gltf',
modelMatrix: model.modelMatrix,
scale: 2,
colorBlendMode: Cesium.ColorBlendMode.HIGHLIGHT
}));
if (axisModel) {
window.axisModel = axisModel;
tooltip.style.display = "none";
//旋轉平移
rotateAndTranslation(viewer, model, axisModel);
}
}, 250);
}
}
clearAxisHandler = function(e) {
clearTimeout(timeoutID);
window.roate_handler = window.roate_handler && window.roate_handler.destroy();
// downHandler = downHandler && downHandler.destroy();
if (window.axisModel) {
viewer.scene.primitives.remove(window.axisModel);
}
window.axisModel = undefined;
tooltip.style.display = "none";
};
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
window.roate_handler.setInputAction(function(movement) {
clearTimeout(timeoutID);
window.roate_handler = window.roate_handler && window.roate_handler.destroy();
// downHandler = downHandler && downHandler.destroy();
if (window.axisModel) {
viewer.scene.primitives.remove(window.axisModel);
}
window.axisModel = undefined;
tooltip.style.display = "none";
}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
}
function rotateAndTranslation(viewer, model, axisModel) {
// 事件監控
if (!window.roate_handler) {
window.roate_handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
}
// 判斷當前是否點擊在座標軸上進行拖動和旋轉
var isAxis = false;
var zhou = undefined; // 當前拖拽的是哪個軸
window.roate_handler.setInputAction(function(movement) {
var cartesian = viewer.scene.pickPosition(movement.position);
var pickedObject = viewer.scene.pick(movement.position);
if (!Cesium.defined(pickedObject)) {
return;
}
if (!Cesium.defined(pickedObject.mesh)) {
return;
}
if (Cesium.defined(pickedObject)) {
zhou = pickedObject.mesh.name;
isAxis = true;
}
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
window.roate_handler.setInputAction(function(movement) {
var pickedObject = viewer.scene.pick(movement.endPosition);
var startCartesian3 = viewer.scene.pickPosition(movement.startPosition);
var endCartesian3 = viewer.scene.pickPosition(movement.endPosition);
var m = model.modelMatrix;
// 旋轉和平移函數得到射線和麪交點
var axisTransForm = function(surface) {
var matrix = Cesium.Matrix4.inverseTransformation(m, new Cesium.Matrix4());
// 獲取相機座標
var camera1 = viewer.camera.position;
// 轉 模型座標
var camera = Cesium.Matrix4.multiplyByPoint(matrix, camera1, new Cesium.Cartesian3());
var startM = Cesium.Matrix4.multiplyByPoint(matrix, startCartesian3, new Cesium.Cartesian3());
var endM = Cesium.Matrix4.multiplyByPoint(matrix, endCartesian3, new Cesium.Cartesian3());
// 從相機看模型的方向
var startDirection = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(startM, camera, new Cesium.Cartesian3()), new Cesium.Cartesian3());
var endDirection = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(endM, camera, new Cesium.Cartesian3()), new Cesium.Cartesian3())
// 面
var plane = Cesium.Plane.fromPointNormal(Cesium.Cartesian3.ZERO, surface);
// 射線
var startRay = new Cesium.Ray(camera, startDirection);
var endRay = new Cesium.Ray(camera, endDirection);
// 射線和麪交點
var start = Cesium.IntersectionTests.rayPlane(startRay, plane);
var end = Cesium.IntersectionTests.rayPlane(endRay, plane);
return { start: start, end: end };
}
// 平移函數
var axisMove = function(surface, zeroAxis1, zeroAxis2) {
var point = axisTransForm(surface);
// 兩點差值
var sub = Cesium.Cartesian3.subtract(point.end, point.start, new Cesium.Cartesian3());
sub[zeroAxis1] = 0;
sub[zeroAxis2] = 0;
// var sub2 = Cesium.Matrix4.multiplyByPoint(m, sub, new Cesium.Cartesian3());
var mm = Cesium.Matrix4.multiplyByTranslation(m, sub, new Cesium.Matrix4());
model.modelMatrix = mm;
// 將座標軸模型移到和模型相同的位置
axisModel.modelMatrix = model.modelMatrix;
}
// 旋轉函數
var axisRotate = function(surface, tant1, tant2) {
var point = axisTransForm(surface);
// 兩點角度
var tant = (point.start[tant1] * point.end[tant2] - point.start[tant2] * point.end[tant1]) / (point.start[tant1] * point.end[tant1] + point.start[tant2] * point.end[tant2]);
var quat = Cesium.Quaternion.fromAxisAngle(surface, Math.atan(tant)); //quat爲圍繞這個surface軸旋轉d度的四元數
var rot_mat3 = Cesium.Matrix3.fromQuaternion(quat);
var m2 = Cesium.Matrix4.multiplyByMatrix3(m, rot_mat3, new Cesium.Matrix4());
// 移動模型
model.modelMatrix = m2;
// 將座標軸模型移到和模型相同的位置
axisModel.modelMatrix = model.modelMatrix;
}
if (isAxis && startCartesian3 && endCartesian3) {
cameraControl(false); // 禁止球轉動和拖動
switch (zhou) {
case 'YArrow_1':
axisMove(Cesium.Cartesian3.UNIT_Z, 'y', 'z');
break;
case 'XArrow_1':
axisMove(Cesium.Cartesian3.UNIT_X, 'x', 'z');
break;
case 'ZArrow_1':
axisMove(Cesium.Cartesian3.UNIT_Y, 'x', 'y');
break;
case 'YAxis_1':
axisRotate(Cesium.Cartesian3.UNIT_X, 'y', 'z');
break;
case 'XAxis_1':
axisRotate(Cesium.Cartesian3.UNIT_Y, 'z', 'x');
break;
case 'ZAxis_1':
axisRotate(Cesium.Cartesian3.UNIT_Z, 'x', 'y');
break;
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
window.roate_handler.setInputAction(function(movement) {
isAxis = false;
cameraControl(true);
}, Cesium.ScreenSpaceEventType.LEFT_UP);
// 球轉動事件
var cameraControl = function(isCamera) {
viewer.scene.screenSpaceCameraController.enableRotate = isCamera;
viewer.scene.screenSpaceCameraController.enableTranslate = isCamera;
viewer.scene.screenSpaceCameraController.enableZoom = isCamera;
viewer.scene.screenSpaceCameraController.enableTilt = isCamera;
viewer.scene.screenSpaceCameraController.enableLook = isCamera;
}
}
最後結合一下,把圖片貼在透明的glb模型上,按glb模型的方式統一加載,效果可以。貼一張效果圖。