cesium 3dtile ClippingPlanes 多边形挖洞ClippingPlaneCollection

发布于:2024-11-29 ⋅ 阅读:(29) ⋅ 点赞:(0)

原理就是3dtiles里面的属性clippingPlanes

采用ClippingPlaneCollection,构成多边形来挖洞。

其次就是xyz法向量挖洞

clippingPlanes: new this.ffCesium.Cesium.ClippingPlaneCollection({
  unionClippingRegions: true, // true 表示多个切割面能合并为一个有效的切割区域
  planes: [
    new this.ffCesium.Cesium.ClippingPlane(
      new this.ffCesium.Cesium.Cartesian3(0.0, 0.0, -1.0), // 法向量
      23.0 // 切割平面到原点的距离(高度)
    )
  ]
})

以下是多边形裁剪

import * as Cesium from 'cesium'
class tileSetClipByPolygon {
  constructor(options) {
    this.tileSet = options.tileSet || null  //3dtiles 
    this.originPositions = options.originPositions || []  //点
    this.unionClippingRegions = !options.unionClippingRegions ? options.unionClippingRegions : true
    this.enabled = !options.enabled ? options.enabled : true
    this.edgeColor = options.edgeColor || Cesium.Color.WHITE
    this.edgeWidth = options.edgeWidth || 0.0
  }
  isClockwise(polygon) {
    var area = 0
    var length = polygon.length
    for (var i = 0; i < length; i++) {
      var j = (i + 1) % length
      area += polygon[i][0] * polygon[j][1] - polygon[j][0] * polygon[i][1]
    }
    return area < 0
  }
  getInverseTransform() {
    let transform
    let tmp = this.tileSet.root.transform
    if ((tmp && tmp.equals(Cesium.Matrix4.IDENTITY)) || !tmp) {
      // 如果root.transform不存在,则3DTiles的原点变成了boundingSphere.center
      transform = Cesium.Transforms.eastNorthUpToFixedFrame(this.tileSet.boundingSphere.center)
    } else {
      transform = Cesium.Matrix4.fromArray(this.tileSet.root.transform)
    }
    return Cesium.Matrix4.inverseTransformation(transform, new Cesium.Matrix4())
  }
  clippingByPositions(clipping) {
    // debugger
    console.log('this.tileSet', this.tileSet)
    this.tileSet.clippingPlanes = null
    const Cartesian3 = Cesium.Cartesian3
    const pointsLength = clipping.length
    const clockwise = this.isClockwise(clipping)
    //所有的裁切面
    const clippingPlanes = []
    let positions
    if (clockwise) {
      //如果为逆,则需要对数组取反
      positions = clipping.reverse()
    } else {
      positions = clipping
    }
    positions = clipping
    const inverseTransform = this.getInverseTransform()
    for (let i = 0; i < pointsLength; ++i) {
      const nextIndex = (i + 1) % pointsLength
      const next = Cesium.Matrix4.multiplyByPoint(inverseTransform, Cesium.Cartesian3.fromDegrees(positions[nextIndex][0], positions[nextIndex][1]), new Cesium.Cartesian3())
      const now = Cesium.Matrix4.multiplyByPoint(inverseTransform, Cesium.Cartesian3.fromDegrees(positions[i][0], positions[i][1]), new Cesium.Cartesian3())
      // 定义一个垂直向上的向量up
      let up = new Cesium.Cartesian3(0, 0, 10)
      //得到指向下一个点的向量
      let right = Cartesian3.subtract(next, now, new Cartesian3())
      right = Cartesian3.normalize(right, right)

      let normal = Cartesian3.cross(right, up, new Cartesian3())
      Cartesian3.normalize(normal, normal)
      //将法向量进行反向
      if (this.unionClippingRegions) {
        Cartesian3.negate(normal, normal)
      }

      //由于已经获得了法向量和过平面的一点,因此可以直接构造Plane,并进一步构造ClippingPlane
      let planeTmp = Cesium.Plane.fromPointNormal(now, normal)
      const clipPlane = Cesium.ClippingPlane.fromPlane(planeTmp)
      clippingPlanes.push(clipPlane)
    }
    let the = this
    const clipPlanes = new Cesium.ClippingPlaneCollection({
      planes: clippingPlanes,
      edgeWidth: the.edgeColor,
      edgeColor: the.edgeColor,
      enabled: the.enabled,
      unionClippingRegions: the.unionClippingRegions
    })
    console.log('clipPlanes', clipPlanes)
    this.tileSet.clippingPlanes = clipPlanes
  }
  removeTilesetClip() {
    this.tileSet.clippingPlanes.enabled = false
  }
}
export default tileSetClipByPolygon

使用

this.CeiumPolygonClipA = new CeiumPolygonClip({
          tileSet: photographyTileset.value,
          originPositions: clipping,
          unionClippingRegions: false
        })
        this.CeiumPolygonClipA.clippingByPositions(clipping)

CesiumJS 中,ClippingPlaneClippingPlaneCollection 通常用于控制哪些部分的场景或模型是可见的。通过切割面(ClippingPlanes),你可以裁剪或隐藏指定区域的内容。clippingPlanes 主要应用于以下几种对象:

1. 3D Tiles

3D Tiles 是一种用于存储和传输大规模 3D 场景的格式,它可以通过 clippingPlanes 进行裁剪。这是一个非常常见的应用,尤其是在城市建模和大规模场景可视化中。

  • clippingPlanes 可以直接应用于 Cesium3DTileset 对象,以裁剪掉 3D Tiles 模型的一部分。

示例:

const tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
  url: 'path/to/your/3dtiles/tileset.json',
  clippingPlanes: new Cesium.ClippingPlaneCollection({
    planes: [
      new Cesium.ClippingPlane(Cesium.Cartesian3.UNIT_Z, 100.0)
    ]
  })
}));

在这个例子中,Cesium3DTileset 会被切割,只显示离 Z 轴 100 单位以内的区域。

2. Primitive(原始几何体)

clippingPlanes 也可以用于 Primitive 对象(如几何体、模型等),这是最基础的 3D 对象类型。通过将 ClippingPlaneCollection 赋值给 Primitive,可以在渲染时裁剪它的几何体。

  • 这种方法适用于自定义的几何体或其他静态几何体,例如:球体、立方体等。

示例:

const sphereGeometry = new Cesium.SphereGeometry({
  radius: 100.0
});

const sphere = new Cesium.Primitive({
  geometryInstances: new Cesium.GeometryInstance({
    geometry: sphereGeometry,
    modelMatrix: Cesium.Matrix4.fromTranslation(new Cesium.Cartesian3(0.0, 0.0, 0.0)),
  }),
  appearance: new Cesium.MaterialAppearance({
    material: Cesium.Material.fromType('Color', {
      color: Cesium.Color.RED
    })
  }),
  clippingPlanes: new Cesium.ClippingPlaneCollection({
    planes: [
      new Cesium.ClippingPlane(Cesium.Cartesian3.UNIT_Z, 50.0) // 裁剪半径为 50 的球体
    ]
  })
});

viewer.scene.primitives.add(sphere);

在这个例子中,创建了一个球体并将其裁剪,裁剪面距离原点 50 单位,隐藏球体超过该高度的部分。

3. Models(3D 模型)

ClippingPlanes 也可以应用于 3D 模型(如 glTF 模型)。在 Cesium.Model 中,clippingPlanes 可以用来裁剪模型的一部分。

示例:

const model = viewer.scene.primitives.add(Cesium.Model.fromGltf({
  url: 'path/to/your/model.glb',
  clippingPlanes: new Cesium.ClippingPlaneCollection({
    planes: [
      new Cesium.ClippingPlane(Cesium.Cartesian3.UNIT_Z, 50.0)
    ]
  })
}));

这段代码将对加载的 glTF 模型应用切割面,裁剪掉离 Z 轴 50 单位以上的部分。

4. Terrain(地形)

对于 Cesium 中的地形数据(例如使用 3D Tiles 数据源的地形),可以通过切割面进行裁剪。地形通常是通过 Cesium.CesiumTerrainProvider 加载的,而切割面可以用来限制地形的显示。

这种应用场景通常适用于大规模的地形可视化,用户可以通过切割面查看地形的特定部分,或从不同的切割角度进行分析。

5. Imagery(影像图层)

clippingPlanes 还可以用于影像图层,特别是当你想要切割或限制影像图层的显示时。通过使用 clippingPlanes,你可以将某些区域的影像数据裁剪掉,以使其他数据更加突出。

示例:

const imageryLayer = viewer.imageryLayers.addImageryProvider(new Cesium.UrlTemplateImageryProvider({
  url : 'https://your-imagery-url/{z}/{x}/{y}.png'
}));

imageryLayer.clippingPlanes = new Cesium.ClippingPlaneCollection({
  planes: [
    new Cesium.ClippingPlane(Cesium.Cartesian3.UNIT_Z, 100.0)
  ]
});

在这个例子中,影像图层会被切割,只显示离 Z 轴 100 单位以内的部分。


其他可能的应用场景:

  1. Skybox(天空盒) clippingPlanes 也可用于裁剪 天空盒,这在某些需要动态裁剪天空内容的应用中有用。

  2. Custom Primitives(自定义原始几何体) 如果你自己创建了自定义几何体,可以通过 clippingPlanes 使其进行裁剪,减少计算负担或者实现特定的可视化效果。

  3. Ground Clipping (地面裁剪) 对于需要动态控制地面显示的场景,clippingPlanes 可以用来裁剪地面,或者将其与其他场景元素进行交互。


总结

ClippingPlanesCesium 中是一个非常灵活的工具,可以应用于以下对象:

  • 3D Tiles(如城市模型)
  • Primitives(如几何体)
  • Models(如 glTF 模型)
  • Terrain(地形)
  • Imagery(影像图层)
  • Skybox(天空盒)
  • Custom Primitives(自定义几何体)

这些对象可以通过 ClippingPlaneCollection 结合多个切割面来实现不同的裁剪效果,从而动态地控制场景中的可见部分。