meface/docs/article/gis/cesiumjs/clipping.md

157 lines
7.6 KiB
Markdown
Raw Normal View History

2023-11-17 10:54:23 +08:00
## Cesium 平面裁切
> 转自:[https://blog.csdn.net/Yel_Liu/article/details/86303145](https://blog.csdn.net/Yel_Liu/article/details/86303145)
关于平面裁切的例子官网有两个3D Tiles裁切和地形裁切。
### 1、ClippingPlaneCollection
要实现平面裁切首先需要创建裁切平面集合根据官网的例子我们创建一个裁切平面。我们在api文档中找到ClippingPlaneCollection创建Cesium.ClippingPlaneCollection的options如下
```javascript
new Cesium.ClippingPlaneCollection(options)
```
| 名称 | 默认值 | 描述 |
| -------------------- | ----------- | ------------------------------------------------------------ |
| planes | | ClippingPlane用于在每个平面的外部选择性地禁用渲染 的对象数组。 |
| enabled | true | 确定剪切平面是否处于活动状态。 |
| modelMatrix | | 4x4变换矩阵指定相对于剪裁平面原始坐标系的附加变换。 |
| unionClippingRegions | false | 如果为true则位于任何平面外部的区域将被剪裁即取并集。否则位于每个平面的外部区域才会被剪裁即取交集。 |
| edgeColor | Color.WHITE | 用于突出显示裁剪对象的边缘的颜色。 |
| edgeWidth | 0 | 剪裁对象的边缘的高光的宽度(以像素为单位)。 |
关于unionClippingRegions中“外部”的含义是指平面法向**反方向**的区域。那么平面的法向怎么定义呢我们需要在planes中定义所需裁切平面我们在api文档中找到ClippingPlane
![外部区域](./images/faxian.png)
### 2、ClippingPlane
```javascript
new Cesium.ClippingPlane(normal, distance)
```
| 名称 | 默认值 |
| -------- | ------------------------------------------------------------ |
| normal | 平面的法线方向。平面的法线方向。 |
| distance | 原点到平面的最短距离。距离符号决定了原点在平面的哪一侧。如果距离为正,则原点在法向的半空间中;如果距离为负,则原点在法向反方向的半空间中;如果距离为零,则平面通过原点。 |
平面法向所在坐标系是以正东方为x轴正方向正北方为y轴正方向正上面为z轴正方向的坐标系
### 3、创建裁切平面
创建裁切平面的代码如下,我们先以一个平面为例来说明
```javascript
var clippingPlanes = new Cesium.ClippingPlaneCollection({
planes : [
new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 0.0, -1.0), 0.0)
],
edgeColor : Cesium.Color.RED,
edgeWidth : 1
});
```
代码的意思为创建了一个法向为正下方、且经过原点的裁切平面平面与裁切对象相交边缘显示为1像素的红色。
下面我们通过两个例子来看一下如何对裁切对象进行裁切
#### 1、模型裁切
使用上面创建的平面对模型进行裁切。在球上添加一个模型并设置其属性clippingPlanes的值为上面创建的平面代码如下
```javascript
var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, 100.0);
var heading = Cesium.Math.toRadians(135.0);
var pitch = 0.0;
var roll = 0.0;
var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr);
var entity = viewer.entities.add({
name : url,
position : position,
orientation : orientation,
model : {
uri : '../../../../Apps/SampleData/models/CesiumAir/Cesium_Air.glb',
scale : 8,
minimumPixelSize : 100.0,
clippingPlanes : clippingPlanes // 设置模型的裁切平面
}
});
```
因为裁切平面的法向是向下的平面以上为外部区域所以会将模型相应的上部门切除效果图如下我们可以看到边界处有1px的红色。
![在这里插入图片描述](./images/clipping1.png)
假如改变平面法向的方向即将上面的new Cesium.Cartesian3(0.0, 0.0, -1.0)改为new Cesium.Cartesian3(0.0, 0.0, 1.0),那么裁切平面的法向是向上的,平面以下为外部区域,所以会将模型相应的下部门切除
```javascript
var clippingPlanes = new Cesium.ClippingPlaneCollection({
planes : [
new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 0.0, 1.0), 0.0)
],
edgeColor : Cesium.Color.RED,
edgeWidth : 1
});
```
![img](./images/clipping2.png)
#### 2、裁切地形
首先,初始化的时候我们先为地球加上地形。接下来是裁切地形,与上面类似,同样是先创建裁切平面集合。
比如我们想要在地形上切出一个方形的洞。那么必然要创建四个裁切平面四面的法向如下图所示那么中心区域即是四个平面外部的交集如要将平面相交的中间区域裁掉unionClippingRegions的值应设置为false。
![img](./images/clipping3.png)
原点在法向相反的方向unionClippingRegions为false所以distance应该设置为**负值**-700。
```javascript
var position = Cesium.Cartographic.toCartesian(new Cesium.Cartographic.fromDegrees(116.39, 39.9, 0));
var distance = -700
var clippingPlanes = new Cesium.ClippingPlaneCollection({
modelMatrix : Cesium.Transforms.eastNorthUpToFixedFrame(position),
planes : [
new Cesium.ClippingPlane(new Cesium.Cartesian3( 1.0, 0.0, 0.0), distance),
new Cesium.ClippingPlane(new Cesium.Cartesian3(-1.0, 0.0, 0.0), distance),
new Cesium.ClippingPlane(new Cesium.Cartesian3( 0.0, 1.0, 0.0), distance),
new Cesium.ClippingPlane(new Cesium.Cartesian3( 0.0, -1.0, 0.0), distance)
],
unionClippingRegions: false
});
viewer.scene.globe.clippingPlanes = clippingPlanes
```
这段代码我们创建了右、左、前、后四个裁切平面。因为每个平面到原点的距离均为700那么最终得到的是一个挖去1400m*1400地形的地球。
![在这里插入图片描述](./images/clipping4.png)
如果只保留中心区域平面的法向必然如下图所示并且需要将四个平面所有外部区域全部裁掉unionClippingRegions的值设置为true即取并集
![在这里插入图片描述](./images/clipping5.png)
原点在法向的方向所以distance应该设置为**正值**700
```javascript
var position = Cesium.Cartographic.toCartesian(new Cesium.Cartographic.fromDegrees(116.39, 39.9, 0));
var distance = 700
var clippingPlanes = new Cesium.ClippingPlaneCollection({
modelMatrix : Cesium.Transforms.eastNorthUpToFixedFrame(position),
planes : [
new Cesium.ClippingPlane(new Cesium.Cartesian3( 1.0, 0.0, 0.0), distance),
new Cesium.ClippingPlane(new Cesium.Cartesian3(-1.0, 0.0, 0.0), distance),
new Cesium.ClippingPlane(new Cesium.Cartesian3( 0.0, 1.0, 0.0), distance),
new Cesium.ClippingPlane(new Cesium.Cartesian3( 0.0, -1.0, 0.0), distance)
],
unionClippingRegions: true
});
viewer.scene.globe.clippingPlanes = clippingPlanes
```
这段代码我们创建了左、右、后、前四个裁切平面。因为每个平面到原点的距离均为700那么最终得到的是一个1400m*1400m的区域。
![在这里插入图片描述](./images/clipping6.png)
### 总结
关于这个功能难点在于平面和unionClippingRegions的设置只要掌握了各个参数的含义使用起来就会得心应手官网的两个例子还是很详细的可以作为参考。