1.cesium裁剪重要使用如下api
new Cesium.ClippingPlaneCollection(options)
这是一个裁剪平面集合,里面主要参数是多个裁剪面
Cesium.ClippingPlane
裁剪面是如何确定的呢?
cesium中要确定一个裁剪面需要一个法向量normal,和一个到原点的距离distance确定。 首先是法向量,法向量是垂直于裁剪面,只要确定了法向量,裁剪面的方向就定下来了。但是垂直于法向量的面有无数个,如下图
红色箭头线就是一个法量,下边的四边形就垂直于该法向量。有无数个和四边形平行的平面,都垂直于这个法向量,只是他们距离法向量起点的距离不同。
如果红色箭头的底部是原点,那么1.法向量为红色箭头 2.距离原点距离为0的平面就是一个确定的平面。
反过来,如果要确定一个平面需要知道1.法向量和2.距离坐标原点的距离。
法向量求解:
还是参考上边的图,法向量可以由两个向量叉乘得到(线性代数),平面上不共线的三个点,就可以确定两个向量。 distance翻译意思如下:从原点到平面的最短距离。距离的符号决定原点位于平面的哪一侧。如果距离为正,则原点位于法线方向的半空间内;如果为负,则原点位于与法线相反的半空间中;如果为零,则平面通过原点。
在cesium中的裁剪面api使用如下
// This clipping plane's distance is positive, which means its normal
// is facing the origin. This will clip everything that is behind
// the plane, which is anything with y coordinate < -5.
const clippingPlanes = new Cesium.ClippingPlaneCollection({
planes : [
new Cesium.ClippingPlane(new Cesium.Cartesian3(1.0, 1.0, 0.0), 0.0)
],
});
// Create an entity and attach the ClippingPlaneCollection to the model.
const entity = viewer.entities.add({
position : Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, 10000),
model : {
uri : 'model.gltf',
minimumPixelSize : 128,
maximumScale : 20000,
clippingPlanes : clippingPlanes
}
});
viewer.zoomTo(entity);
这里直接写死了法向量为
new Cesium.Cartesian3(1.0, 0.0, 0.0)
距离原点距离为0.
以我自己的理解,new Cesium.ClippingPlane(new Cesium.Cartesian3(1.0, 0.0, 0.0), 0.0)可以做如下解释,1.裁剪平面的法向量就是y轴正方向(距离原点为0,法向量是y轴的平面,以下我称为y0平面)。2.将y0平面沿着y轴平移0个单位,平移方向和法向量指向相反。(原理还不清楚)
修改距离为700
修改距离为-700
distance从-700到0,再到700,如果法向量为正,裁剪面可视范围在变大,地形看起来是往左边在扩张
反着法向量方向走
2.挖地形
可以利用以上api进行地形开挖,官方例子如下
planes: [
new Cesium.ClippingPlane(
new Cesium.Cartesian3(1.0, 0.0, 0.0),
-700.0
),
new Cesium.ClippingPlane(
new Cesium.Cartesian3(-1.0, 0.0, 0.0),
-700.0
),
new Cesium.ClippingPlane(
new Cesium.Cartesian3(0.0, 1.0, 0.0),
-700.0
),
new Cesium.ClippingPlane(
new Cesium.Cartesian3(0.0, -1.0, 0.0),
-700.0
),
],
地形分割例2
var terrainModels = Cesium.createWorldTerrain();
var viewer = new Cesium.Viewer("cesiumContainer", {
terrainProvider: terrainModels,
animation: false, //是否显示动画工具
timeline: false, //是否显示时间轴工具
fullscreenButton: false, //是否显示全屏按钮工具
});
//#endregion
//开启深度检测
viewer.scene.globe.depthTestAgainstTerrain = true;
//调整相机视角
viewer.scene.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(114.39564, 30.52214, 2000),
});
//实例化ScreenSpaceEventHandler对象
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
DrawClippingPlane(
[
new Cesium.Cartesian3(
-2271462.4715688457,
5008132.491340798,
3220219.1648368714
),
new Cesium.Cartesian3(
-2271809.8402533564,
5008216.286909559,
3219846.2909253053
),
new Cesium.Cartesian3(
-2271940.7657159385,
5008006.534266515,
3220078.5847187885
)
]
)
//封装挖地形函数
function DrawClippingPlane(points) {
var pointsLength = points.length;
var clippingPlanes = []; // 存储ClippingPlane集合
//计算裁剪面
for (var i = 0; i < pointsLength; ++i) {
var nextIndex = (i + 1) % pointsLength;
//计算两个笛卡尔的按分量求和
var midpoint = Cesium.Cartesian3.add(points[i], points[nextIndex], new Cesium.Cartesian3());
//缩放笛卡尔坐标
midpoint = Cesium.Cartesian3.multiplyByScalar(midpoint, 0.5, midpoint);
//计算提供的笛卡尔坐标系的标准化形式
var up = Cesium.Cartesian3.normalize(midpoint, new Cesium.Cartesian3());
//计算两个笛卡尔的分量差异
var right = Cesium.Cartesian3.subtract(points[nextIndex], midpoint, new Cesium.Cartesian3());
//计算提供的笛卡尔坐标系的标准化形式
right = Cesium.Cartesian3.normalize(right, right);
//叉乘求法向量
var normal = Cesium.Cartesian3.cross(right, up, new Cesium.Cartesian3());
//计算提供的笛卡尔坐标系的标准化形式
normal = Cesium.Cartesian3.normalize(normal, normal);
//原始中心平面
var originCenteredPlane = new Cesium.Plane(normal, 0.0);
//计算点到平面的有符号最短距离
var distance = Cesium.Plane.getPointDistance(originCenteredPlane, midpoint);
clippingPlanes.push(new Cesium.ClippingPlane(normal, distance));
}
//创建ClippingPlaneCollection对象
var ClippingPlaneCollectionObj = new Cesium.ClippingPlaneCollection({
planes: clippingPlanes,
edgeWidth: 1.0,
edgeColor: Cesium.Color.RED
});
//赋值给globe的clippingPlanes
viewer.scene.globe.clippingPlanes = ClippingPlaneCollectionObj;
}
接着上边,给挖开的地方四周加墙
var maximumHeights = [];
for (var i = 0; i < points.length+1; i++) {
maximumHeights.push(22);
}
const points2=[...points,points[0]];
viewer.entities.add({
wall: {
positions:points2,
material: new Cesium.ImageMaterialProperty({
image: "./ce.jpg",
repeat: new Cesium.Cartesian2(points2.length, 1.0)
}),
maximumHeights: maximumHeights,
minimumHeights: new Cesium.CallbackProperty(function () {
var minimumHeights = [];
for (var i = 0; i < points2.length+1; i++) {
minimumHeights.push(-50);
}
return minimumHeights;
}, false),
}
});
在填充底面
viewer.entities.add({
polygon: {
hierarchy: new Cesium.PolygonHierarchy(points2),
material: new Cesium.ImageMaterialProperty({
image: "./di.jpg",
repeat: new Cesium.Cartesian2(points2.length / 2, points2.length / 2)
}),
closeTop: false,
height: new Cesium.CallbackProperty(function () {
return -50;
}, false)
}
})