CollisionDetectionByRender

new Cesium.CollisionDetectionByRender(viewer, collider, options)

碰撞检测分析

此碰撞检测分析方案适用于室内,小场景下的慢速碰撞检测分析。对以下几种情况的支持存在不足。
1. 高速物体做碰撞检测容易出现穿隧问题。所谓高速物体指一帧中移动的步长大于碰撞检测盒的检测范围。
2. 场景相机无法观察到的位置,容易出现碰撞检测失效问题。原因是Cesium内部为了性能优化做了视锥体剔除操作,对不可见的物体不会渲染。这样就导致不可见的物体也无法获取其深度信息。使用相机做碰撞体时,后退操作容易出现此问题。
3. 对锥型物体的检测容易失效。为了尽可能的减少碰撞检测的分析数据量,在实际分析时只取碰撞盒边框所覆盖到的深度数据做计算,所以对于锥形的物体,当碰撞体从上方落下时,因为碰撞盒的边框无法覆盖到此锥形物体,故也就无法识别出发生了碰撞。为了处理这种情况可使用高精度模式,但这样就牺牲了较大的性能。
Name Type Description
viewer Viewer 场景视图
collider Camera | MapGISM3D | Entity 做碰撞检测的对象
options Object optional 可选参数
Name Type Default Description
colliderLength Number 0.4 optional 碰撞盒的长(单位米)
colliderWidth Number 0.4 optional 碰撞盒的宽(单位米)
colliderHeight Number 1.7 optional 碰撞盒的高(单位米)

原点高度属性用于通知碰撞检测实例碰撞对象的坐标原点所在的高度,如单体模型的坐标原点有的在其底部,有的在其中间。
默认值设为1.7是因为默认的碰撞对象是相机。
colliderPositionOffset Cartesian3 (0,0,0) optional 碰撞盒的位置偏移(单位米)
maxPassableHeight Number 0.5 optional 最大可通过高度(单位米)
highPrecision Boolean false optional 是否开启高精度碰撞检测

基于性能考虑默认不开启高精度碰撞检测。非高精度状态下只检测碰撞盒的边框所覆盖的区域,高精度状态下对碰撞盒覆盖的整个区域做检测。
debugShowDepthMap Boolean false optional 检查深度图(debug模式)
debugShowCollider Boolean false optional 检查碰撞盒(debug模式)

debug模式生成的碰撞盒所使用的位置是上一帧的碰撞检测结果,所以并不能精确的表示碰撞盒与场景的碰撞关系。
深度图中可查看到较为精确的碰撞关系。
开启碰撞盒检查主要是为了方便调整碰撞盒与模型相匹配。
相机做为碰撞对象时,开启碰撞盒检查,相机会被碰撞盒包在里面。
Example:
// 1. 默认使用相机做为碰撞检测对象
var collisionDetection;
collisionDetection = new Cesium.CollisionDetectionByRender(viewer, viewer.camera);
// 对目标位置进行碰撞检测
var result = collisionDetection.checkCollision(targetPosition, 0);
// 未碰撞移动到该位置
if (result.result !== 'collided') {
    camera.setView({
        destination: result.computedPosition,
        orientation: {
            heading: camera.heading,
            pitch: camera.pitch,
            roll: 0.0
        }
    });
}

// 2. 使用M3D做为碰撞检测对象
var m3d;
var url = 'http://192.168.82.89:8200/3DData/ModelCache/M3D/2.0/wujiangdizhiti/wujiangdizhiti.mcj';
var options = {
    maximumScreenSpaceError: 0,
    autoReset: false,
    loaded: function(layer) {
        m3d = layer;
        collisionDetection = new Cesium.CollisionDetectionByRender(viewer, layer._root, {
            colliderLength: 0.8, // 设置碰撞盒长
            colliderWidth: 0.6, // 设置碰撞盒宽
            colliderHeight: 1, // 设置碰撞盒高
            colliderPositionOffset: new Cesium.Cartesian3(0, 0, 0.5), // 设置碰撞盒偏移
            debugShowCollider: true, // 打开debug模式,碰撞盒检查
            debugShowDepthMap: true // 打开debug模式,深度图检查
        });
    }
};
viewer.scene.layers.appendM3DLayer(url, options);
// 对目标位置进行碰撞检测
var result = collisionDetection.checkCollision(targetPosition, 0);
// 获取M3D模型在笛卡尔空间的变换矩阵
var transform = m3d.computedTransform;
var newTransform = new Cesium.Matrix4();
var invModelMat = new Cesium.Matrix4();
if (result.result !== 'collided') {
     // 获取模型变换矩阵
     var modelMatrix = m3d.tileset.modelMatrix;
     // 求模型变换矩阵的逆
     Cesium.Matrix4.inverse(modelMatrix, invModelMat);
     // 未碰撞移动到该位置
     Cesium.Matrix4.setTranslation(transform, result.computedPosition, newTransform);
     // 乘上模型变换矩阵的逆矩阵
     Cesium.Matrix4.multiply(invModelMat, newTransform, newTransform);
     // 设置新的变换矩阵
     m3d.transform = Matrix4.clone(newTransform);
}

// 3. 使用Entity做为碰撞检测对象
var url = '../../SampleData/models/GroundVehicle/GroundVehicle.glb';
var position = Cesium.Cartesian3.fromDegrees(108.9594, 34.2186, 5);
var hpr = new Cesium.HeadingPitchRoll(0, 0, 0);
var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr);
var entity = viewer.entities.add({
    name: url,
    position: position,
    orientation: orientation,
    model: {
        uri: url,
        minimumPixelSize: 32,
        maximumScale: 20000,
    },
});
collisionDetection = new Cesium.CollisionDetectionByRender(viewer, entity, {
    colliderLength: 2,
    colliderWidth: 0.6,
    colliderHeight: 0.6,
    colliderPositionOffset: new Cesium.Cartesian3(0, 0, 0.6)
});
// 对目标位置进行碰撞检测
var result = collisionDetection.checkCollision(positionWC, 0);
// 未碰撞移动到该位置
if (result.result !== 'collided') {
    entity.position = result.computedPosition;
}

// 4. 打开调试模式
collisionDetection = new Cesium.CollisionDetectionByRender(viewer, viewer.camera, {
    debugShowCollider: false, // 相机做为碰撞检测对象时不打开碰撞盒检查
    debugShowDepthMap: true, // 打开debug模式,深度图检查
});

Members

碰撞检测对象
碰撞盒高
碰撞盒长
碰撞盒位置偏移
碰撞盒宽
是否开启高精度模式
defaultPrecision
默认模式下只检测碰撞盒的边框部分
highPrecision
高精度模式下对整个碰撞盒做检测
最大可通过高度

Methods

checkCollision(targetPosition, heading, options)Object

检测目标位置是否会碰撞,需要在场景渲染完成后即postRender事件中做检查。
Name Type Default Description
targetPosition Cartesian3 目标位置
heading Number | undefined 碰撞体航向

置空时只做俯视图的检查。
options Object {} optional 可选参数
Name Type Default Description
colliderLength Number optional 碰撞盒长,默认值取实例的同名属性值
colliderWidth Number optional 碰撞盒宽,默认值取实例的同名属性值
colliderHeight Number optional 碰撞盒高,默认值取实例的同名属性值
colliderPositionOffset Cartesian3 (0,0,0) optional 碰撞盒的位置偏移,默认值取实例的同名属性值
maxPassableHeight Number optional 最大可通过高度,默认值取实例的同名属性值
highPrecision Boolean false optional 是否开启高精度碰撞检测,默认值取实例的同名属性值
Returns:
碰撞检测结果数据结构说明:
result computedPosition
'collided' targetPosition 发生了碰撞,返回传入的位置。
'noCollision' targetPosition 没有发生碰撞,返回传入的位置。
'passable' 碰撞后抬高的位置 发生了碰撞但可以通过,计算新的位置。
销毁碰撞检测