Skip to content

3dtiles 裁剪

裁剪 3dtiles 的一部分,使其不显示

加载模型

js
LSGlobe.Viewer.scene.globe.depthTestAgainstTerrain = true
const tileset = LSGlobe.Viewer.scene.primitives.add(
  new LSGlobe.Cesium3DTileset({
    url: ''
  })
)

裁剪 3dtile

js
return tileset.readyPromise.then(() => {
  //获取逆变换矩阵
  function getInverseTransform(tileSet) {
    let transform
    let tmp = tileSet.root.transform
    if ((tmp && tmp.equals(LSGlobe.Matrix4.IDENTITY)) || !tmp) {
      // 如果root.transform不存在,则3DTiles的原点变成了boundingSphere.center
      transform = LSGlobe.Transforms.eastNorthUpToFixedFrame(
        tileSet.boundingSphere.center
      )
    } else {
      transform = LSGlobe.Matrix4.fromArray(tileSet.root.transform)
    }
    // return LSGlobe.Matrix4.inverse(
    //   transform,
    //   new LSGlobe.Matrix4()
    // )
    return LSGlobe.Matrix4.inverseTransformation(
      transform,
      new LSGlobe.Matrix4()
    )
  }

  //获取逆变换矩阵
  let inverseTransform = getInverseTransform(tileset)

  let planes = []
  //要裁剪的区域每个点的坐标,其中起点要在数组末端再出现一次
  let points = LSGlobe.Cartesian3.fromDegreesArrayHeights([
    102.24015312195303,
    38.548924823370974,
    1437.6399169392878, //起点
    102.24015336017237,
    38.54832642138077,
    1438.068924491933,
    102.24137204709595,
    38.548310330480355,
    1437.5701734404097,
    102.24135488402865,
    38.54894734689907,
    1437.1842877571341,
    102.24015312195303,
    38.548924823370974,
    1437.6399169392878 //起点再出现一次
  ])

  for (let i = 0; i < points.length; i++) {
    if (i + 1 > points.length - 1) {
      break
    }
    //转换点坐标为3dtile本地坐标系
    let p1C3 = LSGlobe.Matrix4.multiplyByPoint(
      inverseTransform,
      points[i],
      new LSGlobe.Cartesian3(0, 0, 0)
    )
    //转换点坐标为3dtile本地坐标系
    let p2C3 = LSGlobe.Matrix4.multiplyByPoint(
      inverseTransform,
      points[i + 1],
      new LSGlobe.Cartesian3(0, 0, 0)
    )
    //获取一个p2 -> p1 的方向向量
    let right = LSGlobe.Cartesian3.subtract(
      p2C3,
      p1C3,
      new LSGlobe.Cartesian3()
    )
    //求p2p1和up的法向量
    let up = new LSGlobe.Cartesian3(0, 0, 10)
    let normal = LSGlobe.Cartesian3.cross(right, up, new LSGlobe.Cartesian3())
    //归一化
    normal = LSGlobe.Cartesian3.normalize(normal, normal)
    //创建平面
    let planeTmp = LSGlobe.Plane.fromPointNormal(p1C3, normal)
    planes.push(LSGlobe.ClippingPlane.fromPlane(planeTmp))
  }
  //创建裁切平面
  //unionClippingRegions如果为真,如果一个区域在集合中的任何平面的外面,它将被剪切。
  //否则,一个区域只有在每个平面的外面才会被剪掉。
  let clippingPlanes = new LSGlobe.ClippingPlaneCollection({
    planes: planes,
    unionClippingRegions: false,
    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)
  )

  return tileset
})
js
return tileset.readyPromise.then(() => {
  //获取逆变换矩阵
  function getInverseTransform(tileSet) {
    let transform
    let tmp = tileSet.root.transform
    if ((tmp && tmp.equals(LSGlobe.Matrix4.IDENTITY)) || !tmp) {
      // 如果root.transform不存在,则3DTiles的原点变成了boundingSphere.center
      transform = LSGlobe.Transforms.eastNorthUpToFixedFrame(
        tileSet.boundingSphere.center
      )
    } else {
      transform = LSGlobe.Matrix4.fromArray(tileSet.root.transform)
    }
    // return LSGlobe.Matrix4.inverse(
    //   transform,
    //   new LSGlobe.Matrix4()
    // )
    return LSGlobe.Matrix4.inverseTransformation(
      transform,
      new LSGlobe.Matrix4()
    )
  }

  //获取逆变换矩阵
  let inverseTransform = getInverseTransform(tileset)

  let planes = []
  //要裁剪的区域每个点的坐标,其中起点要在数组末端再出现一次
  let points = LSGlobe.Cartesian3.fromDegreesArrayHeights([
    102.24015312195303,
    38.548924823370974,
    1437.6399169392878, //起点
    102.24015336017237,
    38.54832642138077,
    1438.068924491933,
    102.24137204709595,
    38.548310330480355,
    1437.5701734404097,
    102.24135488402865,
    38.54894734689907,
    1437.1842877571341,
    102.24015312195303,
    38.548924823370974,
    1437.6399169392878 //起点再出现一次
  ])

  for (let i = 0; i < points.length; i++) {
    if (i + 1 > points.length - 1) {
      break
    }
    //转换点坐标为3dtile本地坐标系
    let p1C3 = LSGlobe.Matrix4.multiplyByPoint(
      inverseTransform,
      points[i],
      new LSGlobe.Cartesian3(0, 0, 0)
    )
    //转换点坐标为3dtile本地坐标系
    let p2C3 = LSGlobe.Matrix4.multiplyByPoint(
      inverseTransform,
      points[i + 1],
      new LSGlobe.Cartesian3(0, 0, 0)
    )
    //获取一个p2 -> p1 的方向向量
    let right = LSGlobe.Cartesian3.subtract(
      p2C3,
      p1C3,
      new LSGlobe.Cartesian3()
    )
    //求p2p1和up的法向量
    let up = new LSGlobe.Cartesian3(0, 0, 10)
    //和裁剪区域内的不一样,这次计算的法线与裁剪区域内的相反
    let normal = LSGlobe.Cartesian3.cross(up, right, new LSGlobe.Cartesian3()) 
    //归一化
    normal = LSGlobe.Cartesian3.normalize(normal, normal)
    //创建平面
    let planeTmp = LSGlobe.Plane.fromPointNormal(p1C3, normal)
    planes.push(LSGlobe.ClippingPlane.fromPlane(planeTmp))
  }
  //创建裁切平面
  //unionClippingRegions如果为真,如果一个区域在集合中的任何平面的外面,它将被剪切。
  //否则,一个区域只有在每个平面的外面才会被剪掉。
  let clippingPlanes = new LSGlobe.ClippingPlaneCollection({
    planes: planes,
    unionClippingRegions: true, 
    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)
  )

  return tileset
})

Released under the MIT License.