Cesium 模型剖切

效果图:

 核心代码:

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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值