CESIUM例子学习(十一)——3DTiles Clipping Planes(1)

2 篇文章 0 订阅
1 篇文章 0 订阅

3DTiles Clipping Planes例子,可以很容易实现对BIM、Point Cloud、Instanced、Model的任意剖切,其中Instanced是到底是一个什么对象,是怎么来的还不清楚。3DTiles Clipping Planes,对于BIM说来应用场景是有的,比如,需要查看一个建筑内部,应用从上到下的剖分,可以查看内部的结构。但对于点云和model有什么用呢?反正到现在我还没想出来。但从学习的角度去看,还是可以的。先从简单的模型剖切开始。

一、创建clippingPlanes并绑定到模型

直接使用 new Cesium.ClippingPlaneCollection创建clippingPlanes。从里面的参数可以看到创建多个剖切面,设置切面与模型相交线的线宽,如果不需要切面边线,可设置为0;设置剖切面的颜色等。创建ClippingPlane时传入的有一个new Cesium.Cartesian3参数,它定义了剖切面的任意性,传入不同参数,得到不同喑切面。如下图是一个(1.0,1.0,-1.0)剖切面:

clippingPlanes绑定到模型只需要在创建模型entity时,把clippingPlanes作为可选参数即可。代码如下:

function loadModel (url) {
    clippingPlanes = new Cesium.ClippingPlaneCollection({
        planes: [//切面
            new Cesium.ClippingPlane(
                new Cesium.Cartesian3(0.0, 0.0, -1.0),
                0.0
            ),
        ],
        edgeWidth: 2.0,// 切面与模型相交线的线宽,如果不需要切面边线,可设置为0
        edgeColor: planeColor //切面颜色
    });
    var position = Cesium.Cartesian3.fromDegrees(116.43299999999988, 39.915999999999954, 300.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: url,
            scale: 8,
            minimumPixelSize: 100.0,
            clippingPlanes: clippingPlanes,//设置模型切面
        },

    });
    viewer.flyTo(entity)
    //加载切面到场景中
    for (var i = 0; i < clippingPlanes.length; ++i) {
        var plane = clippingPlanes.get(i);
        viewer.entities.add({
            position: position,
            orientation: orientation,
            plane: {
                dimensions: new Cesium.Cartesian2(50.0, 50.0),
                material: planeColor.withAlpha(0.1),
                plane: new Cesium.CallbackProperty(createPlaneUpdateFunction(plane), false),
                outline: true,
                outlineColor: planeColor,
            },
        });
    }
}
function createPlaneUpdateFunction (plane) {
    return function () {
        plane.distance = targetY;
        return plane;
    };
}

代码中创建 一个垂直于z轴的剖切面,并在创建模型时绑定到模型上,至此,剖切面已经起作用。要注意的是源码中有一个问题,模型的方向矩阵没有应用到剖切面上,即:模型使用了  orientation: orientation,但剖切面没有使用 :orientation: orientation。如果模型有平移、旋转操作时剖切面与被切面不一致。模型旋转了135度,但剖切面没有旋转,如下图:

正常代码绘制结果,如下图:

从正常绘制结果图来看,剖切面的大小并不影响剖切完整性,即剖切面小于模型也能完整切割,其它绘制剖切面也只是显示效果和鼠标的交互操作,并没有别的作用。

二、鼠标交互

鼠标交互就是在加载剖切面时为plane设置一个属性回调函数,用回调函数实时更新plane的distance属性,从而得到不同的剖切面。关键代码:  plane: new Cesium.CallbackProperty(createPlaneUpdateFunction(plane), false)。整个鼠标交互代码如下:

function addListener () {
    let scene = viewer.scene
    var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
    handler.setInputAction(function (down) {
        var pickedObject = scene.pick(down.position);
        if (
            Cesium.defined(pickedObject) && Cesium.defined(pickedObject.id) && Cesium.defined(pickedObject.id.plane)
        ) {
            selectedPlane = pickedObject.id.plane;
            selectedPlane.material = planeColor.withAlpha(0.05);
            selectedPlane.outlineColor = planeColor;
            scene.screenSpaceCameraController.enableInputs = false;
        }
    }, Cesium.ScreenSpaceEventType.LEFT_DOWN);
    handler.setInputAction(function () {
        if (Cesium.defined(selectedPlane)) {
            selectedPlane.material = planeColor.withAlpha(0.1);
            selectedPlane.outlineColor = planeColor;
            selectedPlane = undefined;
        }
        scene.screenSpaceCameraController.enableInputs = true;
    }, Cesium.ScreenSpaceEventType.LEFT_UP);

    handler.setInputAction(function (movement) {
        if (Cesium.defined(selectedPlane)) {
            console.log('movement.endPosition=', movement.endPosition)
            var deltaY = movement.startPosition.y - movement.endPosition.y;
            console.log('deltaY=', deltaY)
            var deltaX = movement.startPosition.x - movement.endPosition.x;
            console.log('deltaX=', deltaX)
            targetY += deltaY;
        }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}

三、问题

从交互代码中可以看到,是利用鼠标在屏幕上的坐标来直接设置,在鼠标拖动函数中

var deltaY = movement.startPosition.y - movement.endPosition.y;

            targetY += deltaY;

在属性回调函数中:

 plane.distance = targetY;

但问题是,虽然鼠标y值能反应出物体在地表的上下关系,但数值并不是一致的。也就是plane.distance与屏幕坐标的数值不是一回事。plane.distance单位应该是米,而屏幕坐标是px。所以直接加就会出现问题,鼠标与剖切面不在一起。因为鼠标向上移动1px,而剖切面向上移动1米。如下图:

但是现在也没有更好的解决方案。问题先放着吧。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值