Cesium 实战教程 - 调整 3dtiles 倾斜摄影大小
- 核心代码
- 完整代码
- 在线示例
之前由于误解遇到一个特殊的需求:想要把三维球上叠加倾斜摄影进行自由放大缩小,跟随地图的缩放进行缩放。
后来经过搜索、尝试,终于实现了需求。
但是,后来发现是误解需求了,甲方只是需要放大缩小地图,不需要改变倾斜摄影的比例。
不过也算是学习了一个功能,这里记录一下。
本文主要包括核心代码、完整代码、在线示例三部分。
核心代码
这里介绍一下修改倾斜摄影比例缩放的方法。
由于 Cesium 近期版本变动,本文介绍的内容包含 Cesium 1.107.0 之前的版本以及之后的版本。
两个版本最主要的区别是改变了 3dtile 的加载方式以及异步解析方式。
1. 1.107.0 以及之后的版本核心代码:
注意:await
关键字,需要在异步方法内使用!
比如:
async function addCesium3DTileset() {
try {
const tileset = await Cesium.Cesium3DTileset.fromUrl(url, options);
viewer.scene.primitives.add(tileSet);
} catch (error) {
console.log(`Failed to load tileset: ${error}`);
}
}
异步加载倾斜摄影核心代码:
这里注意:Cesium 沙盒中应该本身就是异步方法,因此可以直接使用。
// 获取倾斜摄影
// 注意,Cesium 1.107.0 及以后版本需要通过异步方式加载倾斜摄影
const tileSet = await Cesium.Cesium3DTileset.fromUrl("https://earthsdk.com/v/last/Apps/assets/dayanta/tileset.json");
// 创建倾斜摄影
viewer.scene.primitives.add(tileSet);
// 定位至倾斜摄影
viewer.zoomTo(tileSet, new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-90), 0));
// 设置瓦片加载完成监听事件
tileSet.initialTilesLoaded.addEventListener(function () {
// 获取倾斜摄影中心点
const cartographic = Cesium.Cartographic.fromCartesian(tileSet.boundingSphere.center);
// 获取表面坐标
const surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, cartographic.height);
// 记录局部坐标系
scaleFrame = Cesium.Transforms.eastNorthUpToFixedFrame(surface);
// 缩放
if (scale) {
// 获取比例四元数
const _scale = Cesium.Matrix4.fromUniformScale(scale);
// 记录比例四元数
scaleMatrix4 = _scale.clone();
Cesium.Matrix4.multiply(scaleFrame, _scale, scaleFrame);
}
// 倾斜摄影重新设置比例
tileSet._root.transform = scaleFrame;
// 添加参照点
const entity = {
point: new Cesium.PointGraphics({
// 设置贴地
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
// 设置颜色
color: Cesium.Color.fromCssColorString("#ff0033"),
// 设置大小
pixelSize: 30,
// 设置外边框
outlineColor: Cesium.Color.fromCssColorString("#ff0033"),
// 外边框宽度
outlineWidth: 1,
}),
position: surface
};
viewer.entities.add(entity);
});
2. 1.107.0 之前的版本核心代码:
// 初始化倾斜摄影
const tileSet = new Cesium.Cesium3DTileset({
url: "https://earthsdk.com/v/last/Apps/assets/dayanta/tileset.json"
});
// 异步读取倾斜摄影数据,并进行修改
tileSet.readyPromise.then(function () {
// 添加倾斜摄影到地球中
viewer.scene.primitives.add(tileSet);
// 定位
viewer.flyTo(tileSet);
// 获取倾斜摄影中心点
const cartographic = Cesium.Cartographic.fromCartesian(tileSet.boundingSphere.center);
const surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, cartographic.height);
// 记录局部坐标系
const m = Cesium.Transforms.eastNorthUpToFixedFrame(surface);
// 缩放
if (scale) {
const _scale = Cesium.Matrix4.fromUniformScale(scale);
Cesium.Matrix4.multiply(m, _scale, m);
}
tileSet._root.transform = m;
//参照点
const entity = {
id: "test",
point: new Cesium.PointGraphics({
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
color: Cesium.Color.fromCssColorString("#ff0033"),
pixelSize: 30,
outlineColor: Cesium.Color.fromCssColorString("#ff0033"),
outlineWidth: 1,
}),
position: surface
};
viewer.entities.add(entity);
});
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Use correct character set. -->
<meta charset="utf-8"/>
<!-- Tell IE to use the latest, best version. -->
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<!-- Make the application on mobile take up the full browser screen and disable user scaling. -->
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
/>
<title>Cesium model video</title>
<link rel="stylesheet" href="./popup.css" type="text/css">
<script src="http://openlayers.vip/examples/csdn/Cesium.js"></script>
<script src="./cesium_init.js"></script>
<script src="http://www.openlayers.vip/examples/resources/jquery-3.5.1.min.js"></script>
<script src="./CesiumPopup.js"></script>
<style>
@import url(./Widgets/widgets.css);
html,
body,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?f80a36f14f8a73bb0f82e0fdbcee3058";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</head>
<body>
<div id="cesiumContainer"></div>
<script>
// 创建三维球
const viewer = init();
// 初始化地球
const viewer = new Cesium.Viewer('cesiumContainer');
// 获取倾斜摄影
const tileSet = await Cesium.Cesium3DTileset.fromUrl("https://earthsdk.com/v/last/Apps/assets/dayanta/tileset.json");
// 创建倾斜摄影
viewer.scene.primitives.add(tileSet);
// 定位至倾斜摄影
viewer.zoomTo(tileSet, new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-90), 0));
// 初始偏移参数
// 平移参数
const tx = 200;
const ty = 0;
const tz = -430;
// 旋转参数
const rx = 0;
const ry = 0;
const rz = 0;
// 初始比例
const scale = 1;
// 局部坐标系
let scaleFrame;
// 比例四元数
let scaleMatrix4;
// 设置瓦片加载完成监听事件
tileSet.initialTilesLoaded.addEventListener(function () {
// 获取倾斜摄影中心点
const cartographic = Cesium.Cartographic.fromCartesian(tileSet.boundingSphere.center);
const surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, cartographic.height);
// 记录局部坐标系
scaleFrame = Cesium.Transforms.eastNorthUpToFixedFrame(surface);
//平移
const _tx = tx ? tx : 0;
const _ty = ty ? ty : 0;
const _tz = tz ? tz : 0;
const tempTranslation = new Cesium.Cartesian3(_tx, _ty, _tz);
const offset = Cesium.Matrix4.multiplyByPoint(scaleFrame, tempTranslation, new Cesium.Cartesian3(0, 0, 0));
const translation = Cesium.Cartesian3.subtract(offset, surface, new Cesium.Cartesian3());
tileSet.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
//旋转
if (rx) {
const mx = Cesium.Matrix3.fromRotationX(Cesium.Math.toRadians(rx));
const rotate = Cesium.Matrix4.fromRotationTranslation(mx);
Cesium.Matrix4.multiply(scaleFrame, rotate, scaleFrame);
}
if (ry) {
const my = Cesium.Matrix3.fromRotationY(Cesium.Math.toRadians(ry));
const rotate = Cesium.Matrix4.fromRotationTranslation(my);
Cesium.Matrix4.multiply(scaleFrame, rotate, scaleFrame);
}
if (rz) {
const mz = Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(rz));
const rotate = Cesium.Matrix4.fromRotationTranslation(mz);
Cesium.Matrix4.multiply(scaleFrame, rotate, scaleFrame);
}
// 缩放
if (scale) {
const _scale = Cesium.Matrix4.fromUniformScale(scale);
// 记录比例四元数
scaleMatrix4 = _scale.clone();
Cesium.Matrix4.multiply(scaleFrame, _scale, scaleFrame);
}
tileSet._root.transform = scaleFrame;
// 参照点
const entity = {
point: new Cesium.PointGraphics({
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
color: Cesium.Color.fromCssColorString("#ff0033"),
pixelSize: 30,
outlineColor: Cesium.Color.fromCssColorString("#ff0033"),
outlineWidth: 1,
}),
position: surface
};
viewer.entities.add(entity);
});
// 还原比例
function revertTransform(mtx4) {
let inverse = Cesium.Matrix4.inverse(mtx4.clone(), new Cesium.Matrix4());
Cesium.Matrix4.multiply(scaleFrame, inverse.clone(), scaleFrame);
}
// 默认缩放
const viewModel = {
tileScale: 50,
};
// cesium 沙盒内置组件
Cesium.knockout.track(viewModel);
const toolbar = document.getElementById("toolbar");
Cesium.knockout.applyBindings(viewModel, toolbar);
Cesium.knockout
.getObservable(viewModel, "tileScale")
.subscribe(function (newValue) {
console.log(newValue);
// 缩放
if (newValue) {
// 修改后的比例
const _scale = Cesium.Matrix4.fromUniformScale(parseFloat(newValue) / 50);
// 还原模型比例
revertTransform(scaleMatrix4);
scaleMatrix4 = _scale.clone();
// 设置模型比例
Cesium.Matrix4.multiply(scaleFrame, _scale, scaleFrame);
}
tileSet._root.transform = scaleFrame;
});
</script>
</body>
</html>
在线示例
Cesium 1.107.0 及以上版本调整模型大小(可手动调整模型大小)
Cesium 1.106.1 调整模型大小