初學者,原理可能沒這么深入,不過基本了解實現的步驟的邏輯
基本的原理就是切面發法線方向為顯示的部分,法線的反方向為裁切掉的部分
動態的改變distance來實現模型的裁切
實現主要用到的api有,ClippingPlaneCollection,ClippingPlane
以下奉上具體實現步驟
1.定義裁切平面數組
var planesDistance = [];//用於存放多個裁切面距離模型原點的距離
var clippingPlanesArray = [
new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 0.0, -1.0), 0.0),//往下為裁切
new Cesium.ClippingPlane(new Cesium.Cartesian3(-1.0, 0.0, 0.0), 0.0),//側面裁切
];
2.定義裁切平面集合
//debugger;
//定義裁切平面集合
clippingPlanes = new Cesium.ClippingPlaneCollection({
planes: clippingPlanesArray,//定義的切面數組//變成undid
edgeColor: Cesium.Color.WHITE, // 平面切割時模型的邊緣顏色
edgeWidth: viewModel.edgeStylingEnabled ? 1.0 : 0.0,//邊緣的寬度y
unionClippingRegions: true, //true 才能多個切割
enabled: true,//裁切平面是否處於活動
clippingPlanes
});
3.加載模型並制定裁切平面
var tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
url: url,
luminanceAtZenith: 0.2,
lightColor: new Cesium.Cartesian3(0.3, 0.3, 0.3),
clippingPlanes:clippingPlanes
}));
4.創建可視化裁切平面
tileset.debugShowBoundingVolume = viewModel.debugBoundingVolumesEnabled;
boundingSphere = tileset.boundingSphere;//3d模型的中心和半徑
var radius = boundingSphere.radius;//
viewer.zoomTo(tileset, new Cesium.HeadingPitchRange(0.5, -0.2, radius * 4.0));
//加載plane可視化裁切平面
if (!Cesium.Matrix4.equals(tileset.root.transform, Cesium.Matrix4.IDENTITY)) {
// 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.
var transformCenter = Cesium.Matrix4.getTranslation(tileset.root.transform, new Cesium.Cartesian3());//獲取矩陣的平移部分
var transformCartographic = Cesium.Cartographic.fromCartesian(transformCenter);//結果對象中的值將以弧度表示。
var boundingSphereCartographic = Cesium.Cartographic.fromCartesian(tileset.boundingSphere.center);
var boundingSphereCartographicradius = Cesium.Cartographic.fromCartesian(radius);
var height = boundingSphereCartographic.height - transformCartographic.height;
console.log(boundingSphereCartographicradius);
var longitude = boundingSphereCartographic.longitude - transformCartographic.longitude;//經度
console.log(longitude * 111000);
var latitude = boundingSphereCartographic.latitude - transformCartographic.latitude;//維度
//下面決定了是否在中心點
clippingPlanes.modelMatrix = Cesium.Matrix4.fromTranslation(new Cesium.Cartesian3(40, 50, height));
}
//創建可視化對象
for (var i = 0; i < clippingPlanes.length; ++i) {
var plane = clippingPlanes.get(i);
viewer.entities.add({
name: i,
position: boundingSphere.center,//設置裁切面的位置,offset, 根據3dtiles同步調整裁切面高度
//PlaneGraphics.html
plane: {//每個裁切對象(distance為裁切面距離遠點的高度)
dimensions: new Cesium.Cartesian2(radius, radius),//調整裁切面的長和寬
material: Cesium.Color.WHITE.withAlpha(0.1),//裁切面的顏色和透明度
plane: new Cesium.CallbackProperty(createPlaneUpdateFunction(plane, radius, i), false),
outline: true,//是否顯示邊框
outlineColor: Cesium.Color.WHITE,//邊框顏色
}
});//add
}
}
5.寫一個方法動態改變ClippingPlane距離原點的距離
function createPlaneUpdateFunction(plane, radius, name) {
return function () {
plane.distance = planesDistance[name] + (radius * 0.5);//切面距離原點的距離就等於移動的距離+模型的半徑的一半
return plane;
};
}
6.定義鼠標事件
var ellipsoid = viewer.scene.globe.ellipsoid;
// 注冊鼠標事件
var downHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);//鼠標點擊事件
downHandler.setInputAction(function (movement) {
var position = viewer.scene.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid);
//console.log(position);
var pickObject = scene.pick(movement.position);
//debugger;
if (Cesium.defined(pickObject) && Cesium.defined(pickObject.id) && Cesium.defined(pickObject.id.plane)) {
selectedPlane = pickObject.id.plane;//將entities
selectedPlane.name = pickObject.id.name//將name賦予selectedPlane
selectedPlane.material = Cesium.Color.WHITE.withAlpha(0.05);
selectedPlane.outlineColor = Cesium.Color.WHITE;//更換切面的顏色
selectedPlane.startPosition = movement.position;//
selectedPlane.startPosition1 = Cesium.Math.toDegrees((ellipsoid.cartesianToCartographic(position).longitude));//初始位置維度
scene.screenSpaceCameraController.enableInputs = false; // 取消默認的鼠標一切輸入事件
}
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
// 注冊鼠標松開事件
var upHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);//鼠標點擊向上事件
upHandler.setInputAction(function () {
if (Cesium.defined(selectedPlane)) {//如果存在這個對象
selectedPlane.material = Cesium.Color.WHITE.withAlpha(0.6); // 恢復選中的切面顏色
selectedPlane.outlineColor = Cesium.Color.blue;//
selectedPlane = undefined;
}
scene.screenSpaceCameraController.enableInputs = true; // 恢復默認的鼠標一切輸入事件
}, Cesium.ScreenSpaceEventType.LEFT_UP);
// 注冊鼠標移動事件,
var moveHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);//鼠標點擊移動事件
moveHandler.setInputAction(function (movement) {
//通過指定的橢球或者地圖對應的坐標系,將鼠標的二維坐標轉換為對應橢球體三維坐標
var cartesianEnd = viewer.camera.pickEllipsoid(movement.endPosition, ellipsoid);//笛卡爾積,獲取鼠標移動結束世界坐標
var cartesianStart = viewer.camera.pickEllipsoid(movement.startPosition, ellipsoid);//笛卡爾積,獲取鼠標開始移動時世界坐標
if (Cesium.defined(selectedPlane)) {
// console.log(selectedPlane.name);//做判斷哪個面
if (selectedPlane.name == 0) {//往下
var deltaSize = movement.startPosition.y - movement.endPosition.y; // 計算鼠標移動的過程中產生的垂直高度距離
console.log("開始")
console.log("起始位置"+movement.startPosition.y);
console.log("結束為止"+movement.endPosition.y);
console.log("移動的幅度"+deltaSize);
planesDistance[selectedPlane.name] += deltaSize ;//更改鼠標移動的幅度//從初始位置開始算
console.log("結束")
}
if (selectedPlane.name == 1) {//側面
if (cartesianEnd&&cartesianStart) {//能獲取
//將笛卡爾坐標轉換為地理(地圖)坐標
var cartographiEnd = ellipsoid.cartesianToCartographic(cartesianEnd);
var cartographicStart = ellipsoid.cartesianToCartographic(cartesianStart);
//console.log(cartographic);
//將弧度轉為度的十進制度表示,因為差值很小,保留20位小數
var longitudeStringEnd = (Cesium.Math.toDegrees(cartographiEnd.longitude).toFixed(20));/
var longitudeStringStart = (Cesium.Math.toDegrees(cartographicStart.longitude).toFixed(20));/
var longitudeGap=(longitudeStringEnd-longitudeStringStart)*100000;
console.log("兩者之間的差距"+longitudeGap);
console.log("++===");/獲取經度往上變大
/
planesDistance[selectedPlane.name] +=longitudeGap;//原來的距離加上移動的距離(很重要,決定了裁切面的移動方向)
} else {
// mouse_state.innerText = "";
}
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
總結:側面的裁切面不能以屏幕坐標作為移動的依據,因為當旋轉模型時,正負值會發生改變,切面移動方向會和鼠標移動的方向相反,
然后我個人的解決方案是獲取地球坐標,然后再轉換成經緯,再以鼠標移動時經緯度差作為側面切面移動的依據,這樣就可以解決以上的問題,如果大家有更好的解決方案歡迎跟我交流
還有個問題,就是我側面的裁切面還沒觸碰模型就開始裁切,需要我手動去調,現在還沒解決,知道解決方案的大神也歡迎給我指點