实际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模型的方式统一加载,效果可以。贴一张效果图。