cesium ClippingPolygon多边形裁切

1.多边形裁切

1.1 基本流程

        cesium117版本添加了多边形裁切功能,本文分析源码,看看是如何处理的。多边形裁切的大概流程分为4部分:

  1. 通过经纬度坐标传入多个闭合的边界;
  2. 将多个边界打包成两张纹理,一张是每个多边形的坐标,另一张是每个多边形的边界;
  3. 将两张多边形纹理通过一个计算着色器(屏幕空间着色器模拟计算着色器)生成一张符号距离场纹理;
  4. 将这两张图传入地球瓦片和3DTiles的着色器中进行多边形裁切.

1.2 多边形纹理打包

        这是在js代码中处理的,使用了ClippingPolygon和ClippingPolygonCollection两个类,ClippingPolygon类负责每个多边形的坐标收集以及每个多边形的范围计算。

            以下是ClippingPolygon类的主要代码,过程比较简单。

/**
 * Computes a rectangle with the spherical extents that encloses the polygon defined by the list of positions, including cases over the international date line and the poles.
 * 根据给定的位置列表计算球上的坐标区域(使用弧度表示),包括越过国际日期线和极点的情况
 * @private
 *
 * @param {Rectangle} [result] An object in which to store the result.
 * @returns {Rectangle} The result rectangle with spherical extents.
 */
ClippingPolygon.prototype.computeSphericalExtents = function (result) {
  if (!defined(result)) {
    result = new Rectangle();
  }

  // 经纬度范围
  const rectangle = this.computeRectangle(scratchRectangle);

  // 计算出球面点笛卡尔
  let spherePoint = Cartographic.toCartesian(
    Rectangle.southwest(rectangle),
    this.ellipsoid,
    spherePointScratch
  );

  // Project into plane with vertical for latitude
  // 投影到具有垂直纬度的平面中
  let magXY = Math.sqrt(
    spherePoint.x * spherePoint.x + spherePoint.y * spherePoint.y
  );

  // Use fastApproximateAtan2 for alignment with shader
  // 球面纬度
  let sphereLatitude = CesiumMath.fastApproximateAtan2(magXY, spherePoint.z);
  // 球面经度
  let sphereLongitude = CesiumMath.fastApproximateAtan2(
    spherePoint.x,
    spherePoint.y
  );

  // 西南的经纬度
  result.south = sphereLatitude;
  result.west = sphereLongitude;

  // 计算东北点位
  spherePoint = Cartographic.toCartesian(
    Rectangle.northeast(rectangle),
    this.ellipsoid,
    spherePointScratch
  );

  // Project into plane with vertical for latitude
  magXY = Math.sqrt(
    spherePoint.x * spherePoint.x + spherePoint.y * spherePoint.y
  );

  // Use fastApproximateAtan2 for alignment with shader
  sphereLatitude = CesiumMath.fastApproximateAtan2(magXY, spherePoint.z);
  sphereLongitude = CesiumMath.fastApproximateAtan2(
    spherePoint.x,
    spherePoint.y
  );

  // 计算东北经纬度
  result.north = sphereLatitude;
  result.east = sphereLongitude;

  return result;
};

        ClippingPolygonCollection类的过程主要在update函数中,函数过程如下

ClippingPolygonCollection.prototype.update = function (frameState) {
  const context = frameState.context;

  // 是否支持
  if (!ClippingPolygonCollection.isSupported(frameState)) {
    throw new RuntimeError(
      "ClippingPolygonCollections are only supported for WebGL 2."
    );
  }

  // It'd be expensive to validate any individual position has changed. Instead verify if the list of polygon positions has had elements added or removed, which should be good enough for most cases.
  // 验证任何个人立场的改变都是昂贵的。相反,请验证多边形位置列表中是否添加或删除了元素,这在大多数情况下应该足够好。

  // 总共的顶点数量
  const totalPositions = this._polygons.reduce(
    (totalPositions, polygon) => totalPositions + polygon.length,
    0
  );

  // 总共的顶点数量不变
  if (totalPositions === this.totalPositions) {
    return;
  }

  this._totalPositions = totalPositions;

  // If there are no clipping polygons, there's nothing to update.
  if (this.length === 0) {
    return;
  }

  // 符号距离计算命令,命令存在就取消
  if (defined(this._signedDistanceComputeCommand)) {
    // 如果正在计算就取消
    this._signedDistanceComputeCommand.canceled = true;
    this._signedDistanceComputeCommand = undefined;
  }

  // 多边形纹理
  let polygonsTexture = this._polygonsTexture;
  // 范围纹理
  let extentsTexture = this._extentsTexture;
  // 符号距离纹理
  let signedDistanceTexture = this._signedDistanceTexture;


  if (defined(polygonsTexture)) {
    // 当前像素数量
    
<think>好的,我现在需要帮助用户解答在Cesium中实现范围裁剪的问题。用户提到了Cesium.ClippingPlaneCollection,我需要先确认这个类的作用和使用方法。 首先,我记得ClippingPlaneCollection是用于创建裁剪平面的集合,每个平面可以定义裁剪区域的边界。用户可能想通过多个平面来限制3D模型的显示范围。比如,用六个平面围成一个立方体,这样模型只在立方体内可见。 接下来,我需要考虑如何具体实现。可能需要创建一个Entity,然后为其添加clippingPlanes属性。每个ClippingPlane需要指定法线方向和距离。法线方向决定了平面的朝向,而距离则是从原点到平面的距离。例如,要创建一个向右裁剪的平面,法线应该是(1,0,0),距离为某个正值。 然后,示例代码的结构应该是怎样的呢?首先,创建viewer,然后定义裁剪平面数组。每个平面用new Cesium.ClippingPlane(normal, distance)创建。接着,将这些平面放入ClippingPlaneCollection中,并设置其他属性如enabled和edgeColor。最后,创建一个实体,比如多边形,并应用裁剪平面集合。 用户可能需要知道如何调整平面的参数来改变裁剪范围。比如,调整法线方向可以改变裁剪的方向,调整距离可以控制裁剪的位置。此外,开启边缘颜色可以更直观地看到裁剪的边界。 可能还需要提到优化方法,比如使用更少的平面来减少性能消耗,或者根据相机位置动态调整平面。应用场景方面,裁剪常用于建筑内部查看、地形局部展示或模型分块加载。 最后,生成相关问题需要考虑用户可能进一步的问题,比如性能优化、动态调整平面的方法,以及实际应用案例。确保回答结构清晰,步骤明确,并包含可运行的代码示例,这样用户可以直接复制并测试效果。</think>在Cesium中实现范围裁剪主要通过`ClippingPlaneCollection`实现,以下为具体步骤和示例: ### 一、核心实现原理 裁剪平面通过定义法向量和距离确定空间切割区域,使用六个正交平面可构成立方体裁剪范围。每个平面方程满足:$ax + by + cz + d = 0$,其中$(a,b,c)$为平面法向量,$d$为到原点的距离[^1]。 ### 二、实现步骤 1. **创建裁剪平面集合** ```javascript const planes = [ new Cesium.ClippingPlane(new Cesium.Cartesian3(1, 0, 0), 1000), // 右平面 new Cesium.ClippingPlane(new Cesium.Cartesian3(-1, 0, 0), 1000), // 左平面 new Cesium.ClippingPlane(new Cesium.Cartesian3(0, 1, 0), 1000), // 上平面 new Cesium.ClippingPlane(new Cesium.Cartesian3(0, -1, 0), 1000), // 下平面 new Cesium.ClippingPlane(new Cesium.Cartesian3(0, 0, 1), 1000), // 前平面 new Cesium.ClippingPlane(new Cesium.Cartesian3(0, 0, -1), 1000) // 后平面 ]; const clippingPlanes = new Cesium.ClippingPlaneCollection({ planes: planes, enabled: true, edgeW
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值