Skip to content

3dtiles 剖切

通过一个裁切平面进行 dtiles 的剖切,实现 3dtiles 的局部显示/隐藏,可以通过鼠标上下移动实现裁切平面位置的改变。

注册鼠标事件

实现移动平面实现裁切

注册鼠标按下事件

js
let _this = this
let selectedPlane
//鼠标按下时事件
const downHandler = new LSGlobe.ScreenSpaceEventHandler(
  LSGlobe.Viewer.scene.canvas
)
downHandler.setInputAction(function (movement) {
  const pickedObject = LSGlobe.Viewer.scene.pick(movement.position)
  if (
    LSGlobe.defined(pickedObject) &&
    LSGlobe.defined(pickedObject.id) &&
    LSGlobe.defined(pickedObject.id.plane)
  ) {
    selectedPlane = pickedObject.id.plane //设置选中平面
    selectedPlane.material = LSGlobe.Color.WHITE.withAlpha(0.05) //设置样式
    selectedPlane.outlineColor = LSGlobe.Color.WHITE //设置样式
    LSGlobe.Viewer.scene.screenSpaceCameraController.enableInputs = false //禁止相机活动
  }
}, LSGlobe.ScreenSpaceEventType.LEFT_DOWN)

注册鼠标抬起事件

js
// 鼠标抬起事件
const upHandler = new LSGlobe.ScreenSpaceEventHandler(
  LSGlobe.Viewer.scene.canvas
)
upHandler.setInputAction(function () {
  if (LSGlobe.defined(selectedPlane)) {
    selectedPlane.material = LSGlobe.Color.WHITE.withAlpha(0.1) //设置样式
    selectedPlane.outlineColor = LSGlobe.Color.WHITE //设置样式
    selectedPlane = undefined
  }
  LSGlobe.Viewer.scene.screenSpaceCameraController.enableInputs = true //启用相机活动
}, LSGlobe.ScreenSpaceEventType.LEFT_UP)

注册鼠标移动事件

js
// 鼠标移动事件
window.targetY = 0
const moveHandler = new LSGlobe.ScreenSpaceEventHandler(
  LSGlobe.Viewer.scene.canvas
)
moveHandler.setInputAction(function (movement) {
  if (LSGlobe.defined(selectedPlane)) {
    const deltaY = movement.startPosition.y - movement.endPosition.y
    window.targetY += deltaY //设置平面的偏移量
  }
}, LSGlobe.ScreenSpaceEventType.MOUSE_MOVE)

加载模型

js
LSGlobe.Viewer.scene.globe.depthTestAgainstTerrain = true //启用深度检测
//加载3dtiles
const tileset = LSGlobe.Viewer.scene.primitives.add(
  new LSGlobe.Cesium3DTileset({
    url: ''
  })
)

设置调整切面

对于 3dtiles,root tile 的 transform 被用来定位 clippingPlanes。

对于裁切平面,一般来说,剪裁平面的坐标是相对于它们所连接的对象而言的,所以一个距离设置为 0 的平面将通过对象的中心进行剪裁。

如果 3d tiles 没有定义 transform(没有定义时 root tile 的 transform 为单位矩阵即 LSGlobe.Matrix4.IDENTITY),则使用 root tile 的 Cesium3DTile#boundingSphere 代替。

js
tileset.readyPromise.then(function () {
  //创建裁切平面
  let clippingPlanes = new LSGlobe.ClippingPlaneCollection({
    planes: [
      new LSGlobe.ClippingPlane(new LSGlobe.Cartesian3(0.0, 0.0, -1.0), 0.0)
    ],
    edgeWidth: 1.0
  })
  //设置倾斜模型的裁切平面
  tileset.clippingPlanes = clippingPlanes

  const { boundingSphere } = tileset
  const { radius } = boundingSphere
  //视野调整至倾斜模型处
  LSGlobe.Viewer.zoomTo(
    tileset,
    new LSGlobe.HeadingPitchRange(0.5, -0.2, radius * 4.0)
  )
  // 强制模型贴地
  const cartographic = LSGlobe.Cartographic.fromCartesian(
    tileset.boundingSphere.center
  )
  //
  if (
    !LSGlobe.Matrix4.equals(tileset.root.transform, LSGlobe.Matrix4.IDENTITY)
  ) {
    /* For 3D Tiles, the root tile's transform is used to position the clipping planes.
    If a transform is not defined, the root tile's Cesium3DTile#boundingSphere is used instead.
    The clipping plane is initially positioned at the tileset's root transform.
    Apply an additional matrix to center the clipping plane on the bounding sphere center. */

    //转换matrix4至Cartesian3,获取3dtile transform的世界坐标
    const transformCenter = LSGlobe.Matrix4.getTranslation(
      tileset.root.transform,
      new LSGlobe.Cartesian3()
    )
    //3dtile transform的世界坐标转换为wgs84坐标
    const transformCartographic =
      LSGlobe.Cartographic.fromCartesian(transformCenter)
    //3dtile boundingSphere的中心的世界坐标转换为wgs84坐标
    const boundingSphereCartographic = LSGlobe.Cartographic.fromCartesian(
      tileset.boundingSphere.center
    )
    //clippingplane偏移高度
    const height =
      boundingSphereCartographic.height - transformCartographic.height
    // 将裁剪平面居中在模型的中心
    clippingPlanes.modelMatrix = LSGlobe.Matrix4.fromTranslation(
      new LSGlobe.Cartesian3(0.0, 0.0, height)
    )
  }

  // 创建辅助切面,使得clipping plane可见
  for (let i = 0; i < clippingPlanes.length; ++i) {
    const plane = clippingPlanes.get(i)
    LSGlobe.Viewer.entities.add({
      position: boundingSphere.center,
      plane: {
        dimensions: new LSGlobe.Cartesian2(radius * 1.5, radius * 1.5),
        material: LSGlobe.Color.WHITE.withAlpha(0.1),
        plane: new LSGlobe.CallbackProperty(
          _this.createPlaneUpdateFunction(plane),
          false
        ),
        outline: true,
        outlineColor: LSGlobe.Color.WHITE
      },
      name: 'plane',
      show: true
    })
  }
  return tileset
})

Released under the MIT License.