效果图:
核心代码:
1. 设置模型的 clippingPlanes 属性(用于有选择地禁用渲染模型)
/****************** 加载模型 *********************/
const position = new Cesium.Cartesian3(-2489625.0836225147,-4393941.44443024,3890535.9454173897);
let clippingPlanes = new Cesium.ClippingPlaneCollection({
planes: [],
edgeWidth: 1.0,
});
const addModal = () => {
modelEntity = viewer.entities.add({
name: "model",
position,
model: {
uri: '/public/modals/haimianbaobao.glb',
minimumPixelSize: 500, // 最小的模型像素
maximumScale: 500, // 最大的模型像素
runAnimations: false, // 关闭动画
show: true,
clippingPlanes
},
});
// 聚焦模型
viewer.trackedEntity = modelEntity;
}
2. 动态清空、生成切割面
/** 使用的核心方法 **/
//清空切割面数据
modelEntity.model.clippingPlanes._value.removeAll();
// 添加切割面数据
modelEntity.model.clippingPlanes._value.add(
new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 1.0, 0.0), 0.0)
);
其中 new Cesium.ClippingPlane(new Cesium.Cartesian3(x, y, z), distance),
切割面位于哪个轴,就把那个轴设为1,其他轴为0;
distance为该切割面距离初始原点的距离
// 添加剖切面
const addSlice = () => {
for (let i = 0; i < clippingPlanes.length; ++i) {
// plane 为上面 modelEntity.model.clippingPlanes._value.add 添加的数据
const plane = clippingPlanes.get(i);
planeEntity = viewer.entities.add({
position,
plane: {
dimensions: new Cesium.Cartesian2(10, 10),
material: Cesium.Color.WHITE.withAlpha(0.1),
plane: new Cesium.CallbackProperty(createPlaneUpdateFunction(plane),false),
outline: true,
outlineColor: Cesium.Color.WHITE,
},
});
}
}
3. 动态控制切割面距离原点的距离
const createPlaneUpdateFunction = (plane) => {
return function () {
plane.distance = actionData.distance; // 动态更新距离
return plane;
};
}
完整代码:
<template>
<div id="cesiumViewer"></div>
<div class="action">
<div>
<span>轴:</span>
<div>
<button
v-for="axis in axisArr"
:key="axis"
:class="{active: actionData.axis === axis}"
@click="changeAxis(axis)"
>
{
{axis}}
</button>
</div>
</div>
<div>
<span>方向:</span>
<div>
<button
v-for="direction in directionArr"
:key="direction"
:class="{active: actionData.direction === direction}"
@click="changeDirection(direction)"
>
{
{direction}}
</button>
</div>
</div>
<div>
<span>离原点距离:</span>
<div>
<a-slider v-model:value="actionData.distance" :max="10" :min="-10" :step="0.01" :tooltip-open="true" />
</div>
</div>
</div>
</template>
<script setup>
import * as Cesium from 'cesium';
import { onBeforeUnmount, onMounted, reactive } from 'vue';
let viewer, modelEntity, planeEntity = null;
onMounted(() => {
initCesium(); //初始化
addModal();
})
/****************** 初始化 *********************/
const initCesium = () => {
Cesium.Ion.defaultAccessToken = 'eyJ...';
viewer = new Cesium.Viewer('cesiumViewer',{
infoBox: false, // 禁用沙箱,解决控制台报错
animation: false, // 是否创建动画小器件,左下角仪表
baseLayerPicker: false, // 是否显示图层选择器
fullscreenButton: false, // 是否显示全屏按钮
geocoder: false, // 是否显示geocoder小器件,右上角查询按钮
homeButton: false, // 是否显示Home按钮
infoBox: false, // 是否显示信息框
sceneModePicker: false, // 是否显示3D/2D选择器
selectionIndicator: false, // 是否显示选取指示器组件
timeline: false, // 是否显示时间轴
navigationHelpButton: false, // 是否显示右上角的帮助按钮
navigationInstructionsInitiallyVisible: false, //是否显示帮助信息控件
showRenderLoopErrors: false, // 是否显示渲染错误
// 设置背景透明
orderIndependentTranslucency: false,
shouldAnimate: true, //执行模型动画
terrainProvider: Cesium.createWorldTerrain(), //地形
});
viewer._cesiumWidget._creditContainer.style.display = 'none' // 隐藏logo
viewer.scene.globe.enableLighting = true; //启用使用场景光源照亮地球
viewer.scene.globe.depthTestAgainstTerrain = true; //启用深度测试
}
/****************** 控制面板 *********************/
let axisArr = ['x', 'y', 'z'];
let directionArr = [1, -1];
const actionData = reactive({
axis: '',
direction: 1,
distance: 0
})
// 设置剖切面板的轴和方向
const setClippingPlane = () => {
let axisVal = { x: 0, y: 0, z: 0 };
if(actionData.axis in axisVal) {
axisVal[actionData.axis] = actionData.direction;
}
return new Cesium.ClippingPlane(new Cesium.Cartesian3(axisVal.x, axisVal.y, axisVal.z), actionData.distance);
}
// 轴改变
const changeAxis = (axis) => {
clearPlanes();
if(actionData.axis === axis) {
actionData.axis = "";
return;
}
actionData.axis = axis;
let clippingPlane = setClippingPlane();
modelEntity.model.clippingPlanes._value.add(clippingPlane);
addSlice();
}
// 方向改变
const changeDirection = (direction) => {
actionData.direction = direction;
clearPlanes();
let clippingPlane = setClippingPlane();
modelEntity.model.clippingPlanes._value.add(clippingPlane);
addSlice();
}
//清空
const clearPlanes = () => {
modelEntity.model.clippingPlanes._value.removeAll();
planeEntity && viewer.entities.remove(planeEntity);
planeEntity = null;
}
/****************** 加载模型 *********************/
const position = new Cesium.Cartesian3(-2489625.0836225147,-4393941.44443024,3890535.9454173897);
let clippingPlanes = new Cesium.ClippingPlaneCollection({
planes: [],
edgeWidth: 1.0,
});
const addModal = () => {
modelEntity = viewer.entities.add({
name: "model",
position,
model: {
uri: '/public/modals/haimianbaobao.glb',
minimumPixelSize: 500, // 最小的模型像素
maximumScale: 500, // 最大的模型像素
runAnimations: false, // 关闭动画
show: true,
clippingPlanes
},
});
// 聚焦模型
viewer.trackedEntity = modelEntity;
}
// 添加剖切面
const addSlice = () => {
for (let i = 0; i < clippingPlanes.length; ++i) {
const plane = clippingPlanes.get(i);
planeEntity = viewer.entities.add({
position,
plane: {
dimensions: new Cesium.Cartesian2(10, 10),
material: Cesium.Color.WHITE.withAlpha(0.1),
plane: new Cesium.CallbackProperty(createPlaneUpdateFunction(plane),false),
outline: true,
outlineColor: Cesium.Color.WHITE,
},
});
}
}
const createPlaneUpdateFunction = (plane) => {
return function () {
plane.distance = actionData.distance;
return plane;
};
}
onBeforeUnmount(() => {
})
</script>
<style lang="less" scoped>
#cesiumViewer {
width: 100%;
height: 100%;
}
.action {
width: 300px;
position: absolute;
right: 10px;
top: 10px;
background-color: #fff;
padding: 20px;
>div {
display: flex;
align-items: center;
margin-top: 20px;
&:first-of-type {
margin-top: 0;
}
button {
cursor: pointer;
}
>span {
flex-shrink: 0;
width: 100px;
}
>div {
flex: 1;
}
}
.active {
color: #fff;
background-color: cadetblue;
}
}
</style>