资讯动态

Turbulenz Engine 中 RayHit 对象详解:射线检测与凸体扫掠检测的结果数据契约

发布时间:2026/10/14 23:36:02 来源:尧图企业网站定制
游戏开发图形学【免费下载链接】turbulenz_engineTurbulenz is a modular 3D and 2D game framework for making HTML5 powered games for browsers, desktops and mobile devices.项目地址https://gitcode.com/gh_mirrors/tu/turbulenz_engine点击查看免费下载RayHit 是 Turbulenz Engine 物理查询接口DynamicsWorld.rayTest()射线检测与DynamicsWorld.convexSweepTest()凸体扫掠检测统一使用的结果载体。读完本文你将掌握 RayHit 四个只读属性的确切语义哪个为 null 代表命中了谁、命中点与世界空间法线的坐标含义、参数结构体的字段定义以及从公共 API 到 AABBTree 宽相位再到各形状窄相位 rayTest 的完整调用链从而在游戏拾取、命中判定、角色接地检测等场景中正确消费检测结果。一、RayHit 是什么两类物理查询的统一返回值RayHit 对象承载一次 :ref 射线检测ray test或凸体扫掠检测convex sweep test的结果信息。在 Turbulenz 中这两类查询都属于对物理世界做查询但不产生任何力或状态改变的操作区别于接触式碰撞。它们的入口分别是 DynamicsWorld API 文档中定义的// 射线检测 var rayHit dynamicsWorld.rayTest({ from: hitScanStart, to: hitScanEndPoint, group: physicsDevice.FILTER_PROJECTILE, exclude: ownerPhysicsObject }); if (rayHit) { // 命中消费 rayHit 结果 } // 凸体扫掠检测 var hit dynamicsWorld.convexSweepTest({ shape: queryShape, from: transformStart, to: transformEnd, group: physicsDevice.FILTER_PROJECTILE, exclude: myRigidBody });两种检测在命中时都返回一个 RayHit 对象未命中时返回null。注意判断方式是对返回对象本身做真值判断而不是对某个属性做判断——这是使用 RayHit 的第一步约定。从类型声明看RayHit 在 turbulenz.d.ts 中的接口定义为interface RayHit { collisionObject? : PhysicsCollisionObject; body? : PhysicsRigidBody; hitPoint : any; // v3 hitNormal : any; // v3 }与之配套的输入参数结构体同文件内也给出了完整字段RayTestParameters 与 ConvexSweepTestParametersinterface RayTestParameters { from: any; // v3 to: any; // v3 group?: number; mask?: number; exclude?: PhysicsCollisionObject; } interface ConvexSweepTestParameters extends RayTestParameters { shape: PhysicsShape; }即convexSweepTest的参数就是rayTest参数加上一个参与扫掠的shape。二、四个只读属性逐一解析RayHit 的四个属性全部是Read Only只读不要试图反向写入。collisionObject引起命中的 CollisionObject如果检测命中的是 RigidBody则为 null。var collisionObject rayHit.collisionObject; if (collisionObject) { // 命中的是静态碰撞对象 }body引起命中的 RigidBody如果检测命中的是 CollisionObject则为 null。var body rayHit.body; if (body) { // 命中的是刚体 }collisionObject与body二者互斥一次命中要么落在 CollisionObject 上body null要么落在 RigidBody 上collisionObject null。这个互斥不是口头约定而是在物理世界私有实现中显式维护的。见 physicsdevice.ts 中世界级 rayTest 的回调var resultObj obj.rayTest(pRay); if (resultObj ! null) { if (obj.collisionObject) { resultObj.collisionObject actual_obj; resultObj.body null; } else { resultObj.collisionObject null; // 此处省略在源码中对应分支 resultObj.body actual_obj; } }每命中一个对象回调都会把结果对象上对应的一方置为该对象、另一方置为 null。因此对结果的标准用法就是对两个属性分别做真值判断。hitPoint表示命中位置的世界空间坐标是一个 Vector3 对象。var hitLocation rayHit.hitPoint;hitNormal表示命中处表面法线的世界空间向量同样是一个 Vector3 对象。var hitNormal rayHit.hitNormal;两个关键细节坐标系是世界空间。若需要刚体局部坐标必须自行做逆变换。仓库内 scenedebugging.ts 的 rayCastFromPlane 就是标准示范if (rayHit (rayHit.body body || rayHit.collisionObject body)) { var hitPoint rayHit.hitPoint; var normal rayHit.hitNormal; var inv m43InverseOrthonormal.call(md, transform); m43TransformPoint.call(md, inv, hitPoint, hitPoint); m43TransformVector.call(md, inv, normal, normal); }属性可被原地修改。上例直接对rayHit.hitPoint/rayHit.hitNormal调用变换函数第三参数传自身即 in-place 写法。只读约束指的是不能替换 RayHit 的属性指向而非这些 Vector3 本身不可写。三、RayHit 是如何产生的从公共 API 到形状级窄相位公共 API 层DynamicsWorld 的公共实现 只做一层转发rayTest(ray: RayTestParameters): RayHit { return this._private.rayTest(ray); } convexSweepTest(params: ConvexSweepTestParameters): RayHit { return this._private.convexSweepTest(params); }私有世界级 rayTest默认过滤与三棵空间树私有实现physicsdevice.ts中可以看到过滤参数的默认值group未指定时默认为FILTER_DYNAMICmask未指定时默认为FILTER_ALL。随后它把 from/to 转换成参数化射线origin direction maxFactor然后委托给 AABBTree 做宽相位查询var ret AABBTree.rayTest([this.staticSpatialMap, this.dynamicSpatialMap, this.sleepingSpatialMap], pRay, rayCallback); //delete additional factor property if (ret ! null) { delete ret.factor; }两个值得注意的实现事实物理世界同时维护static / dynamic / sleeping 三棵 AABBTree 空间树射线检测会在全部三棵树上做并集查询休眠刚体同样可以被射线命中。宽相位 形状级结果中临时携带的factor射线参数比例属性在返回给 JS 层之前被删除因此 RayHit 上不存在factor属性距离信息只能通过hitPoint与from自行计算。宽相位AABBTree.rayTestAABBTree.rayTest 是静态方法接收一棵或多棵树、参数化射线和一个回调。它先把射线转换为参数形式并预计算方向分量倒数然后在树节点上加速遍历只对真正相交的叶子节点调用回调进入窄相位。窄相位每种形状自带 rayTest回调中实际调用的是命中对象所持形状自己的rayTest(ray)。physicsdevice.ts 中各类 WebGL 形状都实现了该函数可逐一印证 RayHit 的底层来源形状实现位置求交方式地面FloorWebGLPhysicsFloorShape.rayTest射线与半平面求交胶囊CapsulerayTestCap rayTest先解柱面二次方程再对上下两个 cap 求交取最优球SphereWebGLPhysicsSphereShape.rayTest标准二次方程 at^2 bt c 0盒BoxWebGLPhysicsBoxShape.rayTestslab 法基于 halfExtents圆柱CylinderWebGLPhysicsCylinderShape.rayTest柱面 端盖求交圆锥ConeWebGLPhysicsConeShape.rayTest基于 conicK radius / (2 * halfHeight) 的锥面求交三角形阵列WebGLPrivateTriangleArray.rayTest有 spatialMap 时走 AABBTree 加速否则全量遍历三角形三角形网格 / 凸体委托 triangleArray.rayTest复用三角形阵列求交所有形状级 rayTest 都遵循同一契约未命中返回null命中返回携带factor、hitPoint、hitNormal的结果对象且命中点与法线先在形状局部坐标系中算出。最后的坐标还原发生在 WebGLPhysicsShape 的统一封装 中// used for all types. rayTest(ray) { //Transform ray; assuming transform is orthogonal var transform this.transform; var rayT { origin: ...InverseOrthonormalTransformPoint(transform, ray.origin), direction: ...InverseOrthonormalTransformVector(transform, ray.direction), maxFactor: ray.maxFactor }; var result this.shape.rayTest(rayT); if (result ! null) { result.hitPoint VMath.m43TransformPoint(transform, result.hitPoint, result.hitPoint); result.hitNormal VMath.m43TransformVector(transform, result.hitNormal, result.hitNormal); } return result; }先逆变换射线到形状局部空间求交再把hitPoint正变换回世界空间、把hitNormal做正交变换回世界方向——这正是文档中hitPoint 与 hitNormal 均为世界空间这一语义的实现依据。凸体扫掠的复用convexSweepTest的私有实现physicsdevice.ts首次调用时会惰性初始化一个sweepCacheaxis、shapeA/shapeB、closestA/closestB 等复用向量和sweepTriangle假三角形形状用于逐物体做 GJK 类最近点迭代。命中时同样填充 RayHit 的hitPoint/hitNormal/collisionObject/body。它还支持传入第二个 callback 参数用于在迭代过程中接收中间 RayHit源码注释中提到回调签名为(rayHit: RayHit) boolean的形式。四、仓库内的真实使用案例1. 鼠标拾取刚体MouseForcestslib/mouseforces.ts 展示了射线检测命中刚体后建立拖拽约束的完整流程是 RayHit 四个属性联合使用的典型样例//add a point to point constraint for picking var rayHit dynamicsWorld.rayTest({ from : this.pickRayFrom, to : this.pickRayTo, mask : this.pickFilter }); if (rayHit) { var body rayHit.body; var pickPos rayHit.hitPoint; body.active true; this.pickedBody body; var localPivot md.m43TransformPoint(md.m43InverseOrthonormal(body.transform), pickPos); this.pickConstraint this.pd.createPoint2PointConstraint({ bodyA : body, pivotA : localPivot, force : force, damping : 0.5, impulseClamp : this.clamp }); dynamicsWorld.addConstraint(this.pickConstraint); this.oldPickingDist md.v3Length(md.v3Sub(pickPos, this.pickRayFrom)); }这里同时演示了三个常见操作用rayHit.body拿到刚体并active true唤醒休眠体、用md.m43TransformPoint(md.m43InverseOrthonormal(body.transform), pickPos)把世界空间命中点转为刚体局部坐标做约束支点、以及用v3Sub(pickPos, from)的模长恢复拾取距离。2. 场景调试包围盒射线展开tslib/scenedebugging.ts 的 rayCastFromPlane 对刚体包围盒的每个面发射 numRays x numRays 组射线用rayHit.hitPoint与rayHit.hitNormal收集表面点构建调试几何。其中过滤命中对象的写法值得注意if (rayHit (rayHit.body body || rayHit.collisionObject body))即通过对比 RayHit 的两个谁属性来确认命中的是目标物体本身因为一次 rayTest 只会报告最近的一次命中。3. 角色控制器的接地检测角色控制器的内部实现用 convexSweepTest 做落地判定physicsdevice.ts以角色形状从stepHeight * 0.5处向下扫掠一个小段onGroundConvexCallback收到中间 RayHit 后即判定着地。这说明 RayHit 不只是给游戏脚本消费的最终结果引擎内部模块角色控制器也基于同一套契约工作。五、使用要点与边界注意事项只读collisionObject、body、hitPoint、hitNormal 四个属性均为 Read Only只能读取。null 语义双向rayTest/convexSweepTest未命中时返回null命中时body与collisionObject中恰有一个为 null。写判断时应对两属性分别判空避免假设刚体一定存在。世界空间坐标hitPoint / hitNormal 是世界空间的点与方向需要局部坐标时用md.m43InverseOrthonormal(transform)逆变换刚体变换近似正交时可直接使用。默认过滤组私有实现中group缺省为FILTER_DYNAMIC、mask缺省为FILTER_ALL。若要命中静态碰撞对象务必显式传入 group/mask如physicsDevice.FILTER_PROJECTILE等过滤值否则会漏检。exclude 参数rayTest支持exclude指定一个不参与检测的碰撞对象用于排除射击者自身等情形。没有 factor 属性内部宽相位使用的factor在返回前被deleteJS 层拿不到参数化距离需要距离时自行对hitPoint与from做减法求模。适用范围以上行为基于本仓库当前源码tslib/webgl/physicsdevice.ts 的 WebGL 物理实现与 tslib/turbulenz.d.ts 的类型声明。2D 物理有独立的碰撞工具 API见 physics2d_collisionutils_api.rst与 3D 的 RayHit 契约不同不可混用。六、速查表成员类型只读说明collisionObjectCollisionObject | null是命中为 CollisionObject 时给出该对象否则为 nullbodyRigidBody | null是命中为 RigidBody 时给出该刚体否则为 nullhitPointVector3是命中位置世界空间hitNormalVector3是命中表面法线世界空间相关文档入口rayhit_api.rst本页对应源文档、dynamicsworld_api.rstrayTest / convexSweepTest 的调用侧文档、aabbtree_api.rst宽相位空间树的 API 文档。赞分享游戏开发图形学【免费下载链接】turbulenz_engineTurbulenz is a modular 3D and 2D game framework for making HTML5 powered games for browsers, desktops and mobile devices.项目地址https://gitcode.com/gh_mirrors/tu/turbulenz_engine点击查看免费下载相关推荐Turbulenz 引擎 Physics2D World 对象完全指南从世界创建、固定时间步模拟到射线/凸体扫描检测Turbulenz 引擎 Physics2D World 对象完全指南从世界创建、固定时间步模拟到射线/凸体扫描检测 导读 World 世界是 Turbu游戏开发图形学Godot 3D 射线检测结果对象 PhysicsIntersectRayResult3D 完全指南字段详解、生命周期与实战用法Godot 3D 射线检测结果对象 PhysicsIntersectRayResult3D 完全指南字段详解、生命周期与实战用法 本篇指南聚焦 Godot 引文档教程游戏开发Turbulenz 引擎 CollisionUtils 对象详解2D 碰撞检测查询与源码级原理Turbulenz 引擎 CollisionUtils 对象详解2D 碰撞检测查询与源码级原理 导读 本文围绕 Turbulenz 开源 3D/2D 游戏引游戏开发图形学创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑