点击查看:最新Cesium可视化系统实战视频课程

2025020618231161683103f1f88b5b5876e03fbb0897ec461在3D可视化中,裁剪技术是非常重要的,尤其是在处理复杂的三维模型时。通过裁剪,可以有效地剖切掉某些不需要显示的部分,帮助提高渲染性能,同时让用户能够专注于场景中的特定区域。Cesium提供了强大的裁剪平面(Clipping Plane)功能,支持裁剪3D Tiles、3D模型等对象。

本文将详细讲解如何在Cesium中创建裁剪平面,并通过同步显示平面来可视化裁剪效果。

1. 创建裁剪平面

裁剪平面的定义

裁剪平面是一个无限的平面,通过一个法向量(normal)和一个偏移量(distance)来定义。该平面会将空间划分为两部分:一个是裁剪平面的一侧,另一个是裁剪平面的另一侧。根据这个平面,开发者可以选择显示或隐藏场景中的物体。

在Cesium中,ClippingPlane对象通过以下方式创建:


const clipingPlanes = new Cesium.ClippingPlaneCollection({
  planes: [
    new Cesium.ClippingPlane(
      new Cesium.Cartesian3(0, 0, -1), // 法向量 (裁剪平面朝向Z轴负方向)
      0                                 // 距离原点的偏移量
    )
  ],
  edgeWidth: 1, // 裁剪平面边缘的宽度
  edgeColor: Cesium.Color.RED // 裁剪平面边缘的颜色
});


解释:

  • new Cesium.Cartesian3(0, 0, -1):法向量(0, 0, -1)表示裁剪平面朝向Z轴负方向,通常用于裁剪掉模型的上部分(假设裁剪平面位于模型下方)。
  • 0:偏移量为0,表示裁剪平面正好位于原点。

裁剪平面集合(ClippingPlaneCollection)是多个裁剪平面的集合,可以根据需求增加多个平面,以定义复杂的裁剪区域。

2. 添加裁剪平面到模型

接下来,我们将裁剪平面应用到3D模型中,实现场景物体的裁剪效果。以下代码演示了如何将裁剪平面应用到一个3D模型:


let position = Cesium.Cartesian3.fromDegrees(114.4, 31.4, 0);
let heading = Cesium.Math.toRadians(0);
let pitch = Cesium.Math.toRadians(0);
let roll = Cesium.Math.toRadians(0);
const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
const orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr);

const entity = viewer.entities.add({
  name: "工厂",
  position: position,
  orientation: orientation,
  model: {
    uri: "model/generic_factory_with_smoke_towers.glb", // 3D模型路径
    clippingPlanes: clipingPlanes, // 将裁剪平面应用到模型
  }
});


解释:

  • model.uri:这是3D模型的URI,指向存储在服务器上的.glb格式文件。
  • clippingPlanes: clipingPlanes:通过将裁剪平面传递给modelclippingPlanes属性,实现对该3D模型的裁剪。该模型将在加载时应用定义好的裁剪平面,剖切掉裁剪平面一侧的部分。

3. 动态调整裁剪平面的位置

为了增强交互性,我们可以通过UI组件来动态调整裁剪平面的位置。例如,通过dat.GUI滑动条控制裁剪平面在Z轴上的移动,进而改变裁剪效果。


let options = {
  height: 0, // 默认高度
};

gui.add(options, "height", 0, 50).onChange((value) => {
  clipingPlanes.modelMatrix = Cesium.Matrix4.fromTranslation(
    new Cesium.Cartesian3(0, 0, value) // 根据用户输入的高度调整裁剪平面
  );
});

解释:

  • options.height:GUI中的高度控制项,用户可以通过滑动条调整该值。
  • clipingPlanes.modelMatrix:每次滑动条值改变时,裁剪平面的位置也会随之变化。通过Cesium.Matrix4.fromTranslation创建一个新的矩阵,将裁剪平面沿Z轴平移。

4. 同步显示裁剪平面

为了帮助用户更直观地理解裁剪效果,我们可以在场景中显示裁剪平面。使用Cesium.PlaneCesium.Entity来实现这一功能。


let planeEntities = [];
for (let i = 0; i < clipingPlanes.length; i++) {
  const plane = clipingPlanes.get(i);
  const planeEntity = viewer.entities.add({
    name: "plane" + i,
    position: position, // 设置平面的显示位置
    plane: {
      dimensions: new Cesium.Cartesian2(100, 100), // 设置平面的大小
      material: Cesium.Color.RED.withAlpha(0.1),   // 设置平面的透明度和颜色
      outline: true,                               // 显示边框
      outlineColor: Cesium.Color.RED,              // 设置边框颜色
      plane: new Cesium.CallbackProperty(() => {
        return new Cesium.Plane(
          new Cesium.Cartesian3(0, 0, -1), // 裁剪平面的方向
          options.height // 当前裁剪平面的高度
        );
      }, false)
    }
  });
  planeEntities.push(planeEntity); // 添加到显示的平面实体列表中
}

  • Cesium.Plane:用于定义一个平面,该平面包含一个法向量和一个偏移量。在这里,平面法向量设置为(0, 0, -1),代表裁剪平面朝向Z轴负方向。
  • Cesium.CallbackProperty:这里使用了CallbackProperty,使得平面的位置能够动态更新,实时同步裁剪平面的高度。
  • planeEntity:每个平面都作为一个Cesium.Entity对象添加到场景中,从而实现平面的可视化显示。

5. 完整代码总结

通过上述步骤,我们可以在Cesium中实现动态裁剪3D模型的效果,并通过显示裁剪平面使其更具交互性。用户可以通过调整滑动条动态控制裁剪平面的位置,从而实时观察裁剪效果的变化。

完整的代码如下:


// 创建裁剪平面
const clipingPlanes = new Cesium.ClippingPlaneCollection({
  planes: [
    new Cesium.ClippingPlane(
      new Cesium.Cartesian3(0, 0, -1), // 裁剪平面的法向量
      0 // 裁剪平面距离原点的偏移量
    )
  ],
  edgeWidth: 1, // 边缘宽度
  edgeColor: Cesium.Color.RED // 边缘颜色
});

// 创建模型位置和方向
let position = Cesium.Cartesian3.fromDegrees(114.4, 31.4, 0);
let heading = Cesium.Math.toRadians(0);
let pitch = Cesium.Math.toRadians(0);
let roll = Cesium.Math.toRadians(0);
const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
const orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr);

// 添加模型并应用裁剪平面
const entity = viewer.entities.add({
  name: "工厂",
  position: position,
  orientation: orientation,
  model: {
    uri: "model/generic_factory_with_smoke_towers.glb",
    clippingPlanes: clipingPlanes
  }
});

// 创建GUI控制裁剪平面高度
let options = { height: 0 };
gui.add(options, "height", 0, 50).onChange((value) => {
  clipingPlanes.modelMatrix = Cesium.Matrix4.fromTranslation(new Cesium.Cartesian3(0, 0, value));
});

// 显示裁剪平面
let planeEntities = [];
for (let i = 0; i < clipingPlanes.length; i++) {
  const plane = clipingPlanes.get(i);
  const planeEntity = viewer.entities.add({
    name: "plane" + i,
    position: position,
    plane: {
      dimensions: new Cesium.Cartesian2(100, 100),
      material: Cesium.Color.RED.withAlpha(0.1),
      outline: true,
      outlineColor: Cesium.Color.RED,
      plane: new Cesium.CallbackProperty(() => {
        return new Cesium.Plane(
          new Cesium.Cartesian3(0, 0, -1),
          options.height
        );
      }, false)
    }
  });
  planeEntities.push(planeEntity);
}

viewer.zoomTo(viewer.entities); // 缩

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注