以下为个人学习笔记整理。参考 PhysX SDK 3.4.0 文档

# GeometryQuery

几何查询主要用来做物体间的碰撞检测,有以下四种形式:

  • raycasts:射线检测。
  • sweeps:扫描检测。沿一条线移动一个几何对象以找到与另一个几何对象的第一个交点
  • overlaps:重叠检测。确定两个几何对象是否相交
  • penetration depth:穿透检测,计算相撞物体的撞击点和距离。

# 射线检测 ——raycast

通过某坐标点 + 方向向量 + 查询距离

image

/**
\param [in] origin 射线起点
\param [in] unitDir 射线方向
\param [in] geom 被检测对象几何信息
\param [in] pose 被检测对象位置(世界坐标)
\param [in] maxDist 射线长度 [0, inf), 0 表示检测是否重叠
\param [in] hitFlags 标记命中需要带回的返回结果
\param [in] maxHits 记录命中结果最大数量
\param [out] rayHits 命中信息
\return 命中数量
*/
PX_PHYSX_COMMON_API static PxU32 raycast(const PxVec3& origin,
                                         const PxVec3& unitDir,
                                         const PxGeometry& geom,
                                         const PxTransform& pose,
                                         PxReal maxDist,
                                         PxHitFlags hitFlags,
                                         PxU32 maxHits,
                                         PxRaycastHit* PX_RESTRICT rayHits);
// example
PxRaycastHit hitInfo;
PxU32 maxHits = 1;
PxHitFlags hitFlags = PxHitFlag::ePOSITION|PxHitFlag::eNORMAL|PxHitFlag::eDISTANCE|PxHitFlag::eUV;
PxU32 hitCount = PxGeometryQuery::raycast(origin, unitDir,
                                          geom, pose,
                                          maxDist,
                                          hitFlags,
                                          maxHits, &hitInfo);

# 特殊查询情况 —— 如果射线起点在几何内部

# Solid Object

内部视为实心的几何体(球体、胶囊、盒子、凸面),最多得到一个结果

  • 命中点:射线起点
  • 法线:射线反方向
  • 距离:0

# 特殊查询情况 —— 特殊几何

# 网格类

支持多种命中模式:

  • 多次命中:返回全部命中点
  • 最近命中:返回距离射线最近的命中点
  • 任意命中:随机返回任意的命中点

网格的命中判定会被面剔除规则影响。

  • 如果设置了 PxMeshGeometryFlag::eDOUBLE_SIDEDPxHitFlag::eMESH_BOTH_SIDES,则禁用剔除。
  • 如果设置了 PxMeshGeometryFlag::eDOUBLE_SIDED,则反面命中的法线会取反。

raymesh

# 高度场

「thickness」表示距离地面以下多少的深度,因此 「thickness」 >0 表示 -y 方向深度值。

当「thickness」 <=0 时,法线方向为 +y ,「thickness」 >0 时,法线方向为 -y

../_images/GeomTypeHeightField.png

# Solid Object

最多得到一个命中结果

# Plane

3D 空间下的 「2D 几何」,最多得到一个命中结果,如果起点或终点和平面很接近,有可能不会视为命中

# 特殊返回结果 —— 网格类

网格和高度厂这种由三角形组成的网格几何可以获取到交点坐标的 UV 重心表示法,参考重心坐标

其中 v0、v1 和 v2 是命中三角形的顶点,详细实现见 PxTriangle::pointFromUV

pos=(1uv)v0+uv1+vv2pos = (1 - u - v)*v0 + u*v1 + v*v2

# 扫描检测 ——sweeps

一般用于检测一个物体运动过程中和其他物体的碰撞

sweep

/**
\param [in] unitDir 扫描 | 运动方向
\param [in] distance 扫描距离
\param [in] geom0 扫描的几何体
\param [in] pose0 扫描几何体的坐标
\param [in] geom1 被扫描几何体
\param [in] pose1 被扫描几何体的坐标
\param [out] sweepHit 命中信息
\param [in] hitFlags 标记命中所需返回的信息
\param [in] inflation 膨胀大小,扩大检测范围的参数,让几何看起来更圆
\return 命中数量
*/
bool PxGeometryQuery::sweep(const PxVec3& unitDir, const PxReal distance,
							const PxGeometry& geom0, const PxTransform& pose0,
							const PxGeometry& geom1, const PxTransform& pose1,
							PxSweepHit& sweepHit, PxHitFlags hitFlags,
							const PxReal inflation)
    
// example
PxSweepHit hitInfo;
PxHitFlags hitFlags = PxHitFlag::ePOSITION|PxHitFlag::eNORMAL|PxHitFlag::eDISTANCE;
PxReal inflation = 0.0f;
PxU32 hitCount = PxGeometryQuery::sweep(unitDir, maxDist,
                                        geomToSweep, poseToSweep,
                                        geomSweptAgainst, poseSweptAgainst,
                                        hitInfo,
                                        hitFlags,
                                        inflation);

# 问题

  • 如果两个几何的尺寸差异很大会导致结果的不正确。
  • 由于扫描操作也能够判断初始状态的重叠情况,但是和重叠检测算法存在差异,两者结果可能完全不同。推荐先用重叠检查初始状态,再用扫描检查看深度。

# 重叠检测 ——overlaps

用于检查两个几何的重叠情况,其中一个必须是 Solid Object,另一个可以任意

../_images/GeomQueryOverlap.png

特殊规则:

  • Plane 被视作实心空间,其后方的区域也被视作体积的一部分。
  • 网格的三角形被视为薄面片,不具备体积。
  • 高度场被视为有「thickness」的三角形面片组成,因此带有体积

# 简单版本

只判断重叠,不返回额外信息

/**
\param [in] geom0 第一个几何结构
\param [in] pose0 第一个几何位置
\param [in] geom1 第二个几何结构
\param [in] pose1 第二个几何位置
\return True if the two geometry objects overlap
*/
PX_PHYSX_COMMON_API static bool overlap(const PxGeometry& geom0, const PxTransform& pose0,
                                        const PxGeometry& geom1, const PxTransform& pose1);
// example
bool isOverlapping = overlap(geom0, pose0, geom1, pose1);

# 复杂版本

会获取到重叠的网格信息

/**
\param [in] geom 第一个几何结构
\param [in] geomPose 第一个几何位置
\param [in] meshGeom 第二个几何网格结构
\param [in] meshPose 第二个几何位置
\param [out] results 返回值,保留重叠三角形数据
\param [in] maxResults 最大重叠查询个数
\param [in] startIndex 超过阈值时正在查询的三角形编号,用于后续继续查询
\param [out] overflow 是否超过阈值了
\return Number of overlaps found, i.e. number of elements written to the results buffer
*/
PX_PHYSX_COMMON_API static PxU32 findOverlapTriangleMesh(	const PxGeometry& geom, const PxTransform& geomPose,
                                                         const PxTriangleMeshGeometry& meshGeom, const PxTransform& meshPose,
                                                         PxU32* results, PxU32 maxResults, PxU32 startIndex, bool& overflow);

# GJK 算法精确物理碰撞检测

...

# 穿透检测 ——penetration depth

穿透检测的意义在于计算物体发生碰撞时的穿透深度(MTD),并得到分离穿透所需的方向和距离。

penetration depth

/**
\param [out] 对象 1 的平移方向
\param [out] 平移距离
\param [in] 第一个几何结构
\param [in] 第一个几何位置
\param [in] 第二个几何结构
\param [in] 第二个几何位置
\return 穿透返回 true
*/
PX_PHYSX_COMMON_API static bool computePenetration(PxVec3& direction, PxF32& depth,
                                                       const PxGeometry& geom0, const PxTransform& pose0,
                                                       const PxGeometry& geom1, const PxTransform& pose1);

对于网格和高度场,使用迭代算法计算深度,本质上就是多次调用 computePenetration 的结果并更新 geom0pose0 直到返回值为 false。

更新于 阅读次数

请我[恰饭]~( ̄▽ ̄)~*

鑫酱(●'◡'●) 微信支付

微信支付

鑫酱(●'◡'●) 支付宝

支付宝