侧边栏壁纸
  • 累计撰写 21 篇文章
  • 累计创建 6 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Cesium 结合 dat.gui 实现模型的平移变换

南风过境
2023-12-21 / 0 评论 / 0 点赞 / 19 阅读 / 5255 字 / 正在检测是否收录...

前言

前段时间浅学了一下 threejs,用到一个 dat.gui 的库,可以实现对视图的控制。思考可以尝试用来做 Cesium 中 3dtiles或是 gltf 等模型的位置变换操作。

预览

环境

vue3 + js + cesium1.112 + dat.gui

dat.gui的使用

  1. 通过 npm 等方式下载:npm i dat.gui -save

  2. 引入项目:import * as DatGUI from 'dat.gui'

  3. 创建 gui 实例:const datGui = new DatGUI.GUI();

  4. 使用:通过 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>

0

评论区