前言
前段时间浅学了一下 threejs,用到一个 dat.gui 的库,可以实现对视图的控制。思考可以尝试用来做 Cesium 中 3dtiles或是 gltf 等模型的位置变换操作。
预览
环境
vue3 + js + cesium1.112 + dat.gui
dat.gui的使用
通过 npm 等方式下载:
npm i dat.gui -save
引入项目:
import * as DatGUI from 'dat.gui'
创建 gui 实例:
const datGui = new DatGUI.GUI();
使用:通过 add()添加对某个属性的控制,min()设置该属性的最小值,max()设置该属性最大值,onChange()实现每次值发生变化后的操作
平移变换的思路
提供两种思路,但是根本都是求一个平移向量,再通过tileset.modelMatrix
进行坐标变换
思路一
在 Cesium 官方沙盒有个通过 knockout 去控制模型高度的示例,该示例中变换思路其实就是给定两个向量 a、b,b-a 就得到了一个从 a 的终点到 b 的终点的平移向量c,将 c 再通过Cesium.Matrix4.fromTranslation
方法就可以转换成相应的变换矩阵
Cesium.knockout
.getObservable(viewModel, "height")
.subscribe(function (height) {
height = Number(height);
if (isNaN(height) || !Cesium.defined(tileset)) {
return;
}
const cartographic = Cesium.Cartographic.fromCartesian(
tileset.boundingSphere.center
);
const surface = Cesium.Cartesian3.fromRadians( // 向量 a
cartographic.longitude,
cartographic.latitude,
0.0
);
const offset = Cesium.Cartesian3.fromRadians( // 向量 b
cartographic.longitude,
cartographic.latitude,
height
);
const translation = Cesium.Cartesian3.subtract( // 向量 b - 向量 a
offset,
surface,
new Cesium.Cartesian3()
);
tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
});
思路二
参照 Cesium 中的图形变换:局部平移、缩放、旋转思路及代码实现 - 岭南灯火 - 博客园 (cnblogs.com)这篇文章,可以尝试以下思路,以下代码中将原文的向量相减方式作了修改,Cesium 中提供了向量相减的方法Cesium.Cartesian3.subtract(left, right, result)
,传入的三个参数在方法中,通过计算 left-right=result
得到此次变换的平移向量
const fromMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(tileset.boundingSphere.center);
const transformVector = new Cesium.Cartesian3(transDistance.x, transDistance.y, transDistance.z); // transDistance xyz各轴平移距离
let toVector = new Cesium.Cartesian3();
Cesium.Matrix4.multiplyByPoint(fromMatrix, transformVector, toVector);
const translation = new Cesium.Cartesian3.subtract(toVector, tileset.boundingSphere.center, new Cesium.Cartesian3());
tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
完整代码
<script setup>
import { ref, onMounted } from 'vue'
import * as Cesium from 'cesium'
import * as DatGUI from 'dat.gui'
onMounted(async () => {
Cesium.Ion.defaultAccessToken = "{你的 token}";
window.Cesium = Cesium;
window.viewer = new Cesium.Viewer("cesiumContainer", {
infoBox: false,
});
let tileset = await Cesium.Cesium3DTileset.fromUrl("{3dtiles 模型地址}");
viewer.scene.primitives.add(tileset);
viewer.scene.globe.depthTestAgainstTerrain = true;
viewer.zoomTo(
tileset,
new Cesium.HeadingPitchRange(
0.0,
-0.5,
tileset.boundingSphere.radius * 2.0
)
);
const transDistance = { x: 0, y: 0, z: 0 }
const datGui = new DatGUI.GUI();
datGui.add(transDistance, "x").name("x轴").min(-1000).max(1000).step(10).onChange((value) => {
translationTransform(tileset, transDistance)
})
datGui.add(transDistance, "y").name("y轴").min(-1000).max(1000).step(10).onChange((value) => {
translationTransform(tileset, transDistance)
})
datGui.add(transDistance, "z").name("z轴").min(-1000).max(1000).step(10).onChange((value) => {
translationTransform(tileset, transDistance)
})
});
/**
* 平移变换
* @param {Cesium.Cesium3DTileset} tileset
* @param {{ x: number, y: number, z: number }} transDistance 各轴平移距离
*/
const translationTransform = (tileset, transDistance) => {
const fromMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(tileset.boundingSphere.center);
const transformVector = new Cesium.Cartesian3(transDistance.x, transDistance.y, transDistance.z);
let toVector = new Cesium.Cartesian3();
Cesium.Matrix4.multiplyByPoint(fromMatrix, transformVector, toVector);
const translation = new Cesium.Cartesian3.subtract(toVector, tileset.boundingSphere.center, new Cesium.Cartesian3());
tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
}
</script>
<template>
<div id="cesiumContainer" class="cesiumContainer"></div>
</template>
<style scoped lang="scss"></style>
评论区