- 文档
- 教程
- 游戏开发
【免费下载链接】godot-docs
Godot Engine official documentation
导读
SpringBoneCollisionPlane3D是 Godot 引擎中弹簧骨骼模拟(Spring Bone)体系的核心碰撞体之一,它提供一个无限大的 XZ 平面,法线方向固定为+Y,用于与 SpringBoneSimulator3D 驱动的骨骼链(如毛发、布料、尾巴)进行碰撞与滑动交互。读完本文,你将掌握该节点的继承关系、几何语义、骨骼绑定方式、与模拟器的配合流程,以及在实际角色骨骼上搭建碰撞场景的完整思路。
类概览:继承链与核心语义
SpringBoneCollisionPlane3D的继承链如下:
SpringBoneCollisionPlane3D < SpringBoneCollision3D < Node3D < Node < Object对应源码定义位于 class_springbonecollisionplane3d.rst。它本身没有额外的属性和方法,全部能力继承自基类 SpringBoneCollision3D。
在 Godot 的弹簧骨骼体系中,共有三种碰撞体子类,全部继承自SpringBoneCollision3D:
| 子类 | 几何形状 | 文档路径 |
|---|---|---|
| SpringBoneCollisionPlane3D | 无限 XZ 平面,法线为 +Y | class_springbonecollisionplane3d.rst |
| SpringBoneCollisionCapsule3D | 胶囊体(含圆柱中段与半球端帽) | class_springbonecollisioncapsule3d.rst |
| SpringBoneCollisionSphere3D | 球体 | class_springbonecollisionsphere3d.rst |
SpringBoneCollisionPlane3D的几何语义非常明确:它是一个尺寸无限大的 XZ 平面,因此Node3D的 Scale 对它没有传统意义上的"缩放碰撞体"效果;平面始终贯穿世界空间,其+Y 方向被当作碰撞法线。这意味着它最适合用来模拟"地面"、"桌面"、"衣领内衬"这类无限延伸的阻挡面,防止头发、裙摆、尾巴的关节穿过角色身体或地面。
碰撞体的生效前提:必须作为模拟器的子节点
与物理引擎的碰撞体(如CollisionShape3D)不同,弹簧骨骼碰撞体系完全独立于PhysicsServer3D,它不使用物理层、碰撞掩码或刚体,而是由SpringBoneSimulator3D在骨架修改阶段自行完成的纯数学求解。
基类 SpringBoneCollision3D 明确规定了生效条件:
碰撞体可以是
SpringBoneSimulator3D的子节点。如果它不是SpringBoneSimulator3D的子节点,则不产生任何效果。
因此搭建时的标准节点结构如下:
Character (Node3D) └── Skeleton3D ├── SpringBoneSimulator3D # 弹簧骨骼模拟器(继承自 SkeletonModifier3D) │ ├── SpringBoneCollisionPlane3D # 无限平面碰撞体(本文主角) │ ├── SpringBoneCollisionSphere3D # 球形碰撞体 │ └── SpringBoneCollisionCapsule3D # 胶囊碰撞体 └── (骨骼 / 蒙皮网格等)注意SpringBoneSimulator3D本身继承自 SkeletonModifier3D,而SkeletonModifier3D通过"存在一个Skeleton3D父节点"来获取目标骨架。所以模拟器和碰撞体都要挂在Skeleton3D之下。
碰撞与滑动求解的底层执行顺序
碰撞并非在主循环中独立计算,而是被内嵌进SpringBoneSimulator3D的骨架修改流程中。理解这个顺序对排查"碰撞不生效"问题至关重要,其流程分两个阶段:
- 预处理阶段(碰撞体姿态同步):如果碰撞体的
bone属性被设置,碰撞体会与祖先Skeleton3D对应骨骼的**骨骼姿态(bone pose)**同步位置与朝向,这一步发生在模拟器修改流程之前。 - 修改阶段(碰撞求解):碰撞与滑动按碰撞体列表的顺序执行。该列表由
SpringBoneSimulator3D.set_collision_path()指定;如果调用set_enable_all_child_collisions(index, true)启用了"所有子碰撞体"模式,则列表顺序与SceneTree中的节点顺序一致。
基类还给出了一条重要警告:
警告:被缩放的
SpringBoneCollision3D很可能不会按预期工作。请确保父级Skeleton3D及其骨骼未被缩放。
这同样适用于SpringBoneCollisionPlane3D:由于平面是无限大小的,缩放节点或骨骼不仅没有意义,还可能引入姿态同步误差,应在制作管线中保持骨骼与骨架单位缩放。
绑定骨骼:让平面跟随骨骼移动
SpringBoneCollisionPlane3D继承自基类的核心属性共有四个,其中前两个用于把碰撞体绑定到某根骨骼上:
bone(int,默认-1)
附加骨骼的索引。设置后,碰撞体在模拟器的预处理阶段会自动与祖先Skeleton3D中该骨骼的骨骼姿态位置同步。默认值-1表示未绑定。
bone_name(String,默认"")
附加骨骼的名称。提供名称方式的好处是当骨架导入顺序变化时,名称引用仍然稳定;Godot 内部会将其解析为骨骼索引。
position_offset(Vector3)
相对骨骼姿态位置的偏移量。例如把平面放在角色胸腔骨骼上,再通过position_offset将平面下移几厘米,让衣领平面恰好位于脖子与胸部之间。
rotation_offset(Quaternion)
相对骨骼姿态旋转的偏移量。由于SpringBoneCollisionPlane3D的法线固定为本地 +Y,通过旋转偏移可以让平面法线指向任意方向——例如把"地面平面"倾斜成一个斜坡,或者让"衣领内衬平面"朝向斜上方。
四个属性均有对应的 setter/getter(set_bone/get_bone、set_bone_name/get_bone_name、set_position_offset/get_position_offset、set_rotation_offset/get_rotation_offset),可直接在代码中动态调整。
此外,基类还提供一个查询方法:
func get_skeleton() -> Skeleton3D返回父级SpringBoneSimulator3D所属的Skeleton3D节点(如果找到),否则返回null。这在运行时检查碰撞体是否处于有效骨架下非常实用。
与模拟器的协作:碰撞列表与排除列表
SpringBoneCollisionPlane3D要真正参与求解,必须被纳入模拟器的碰撞列表。相关 API 全部位于 SpringBoneSimulator3D,以下方法均接收index参数(多套设置时的条目序号,对应settings/<index>/...配置项):
| API | 作用 |
|---|---|
set_enable_all_child_collisions(index, enabled) | true时,所有子碰撞体自动参与碰撞,并通过set_exclude_collision_path()维护排除列表;false时需要手动用set_collision_path()注册 |
set_collision_path(index, collision, node_path) | 在碰撞列表中登记指定节点路径的碰撞体(are_all_child_collisions_enabled为false时生效) |
set_exclude_collision_path(index, collision, node_path) | 在排除列表中登记碰撞体(启用"全部子碰撞体"模式时生效) |
set_collision_count(index, count)/set_exclude_collision_count(index, count) | 预先设置列表条目数量 |
get_collision_path/get_exclude_collision_path | 读取列表中的节点路径 |
clear_collisions(index)/clear_exclude_collisions(index) | 清空对应列表 |
are_all_child_collisions_enabled(index) | 查询当前模式 |
两种模式的使用建议:
- 全部子碰撞体模式(推荐编辑器工作流):直接在
SpringBoneSimulator3D节点下挂多个碰撞体,碰撞顺序即场景树顺序;个别不需要的碰撞体放入排除列表。 - 手动列表模式(适合运行时动态控制):用代码精确控制哪些碰撞体参与,适合多套骨骼设置复用同一批碰撞体的场景。
关节半径:平面碰撞的实际作用对象
平面碰撞体本身没有半径属性——真正有"粗细"的是骨骼链上的关节。SpringBoneSimulator3D.set_radius()设置骨骼链的关节半径,模拟时关节会被当作一个"球",与碰撞体表面进行**移动与滑动(move and slide)**求解。radius的值还可以通过set_radius_damping_curve()用 Curve 按关节位置逐段缩放。
因此,平面碰撞体的"厚度感"完全取决于关节半径:关节半径越大,头发或裙摆关节就越早被平面推开,视觉上像被一层更厚的"气垫"托住。
平面碰撞的典型应用场景
结合SpringBoneCollisionPlane3D的无限平面 + +Y 法线特性,以下是几种实践中验证有效的用法:
1. 裙摆防穿地
在角色脚踝附近放置一个绑定到骨盆或大腿骨骼的平面,position_offset.y设为一个略高于地面的负偏移,让裙摆骨骼链的关节永远无法穿过地面——即便裙摆因为惯性大幅下垂。
2. 衣领内衬阻挡头发
把平面绑定到头部或脖颈骨骼,通过rotation_offset将平面法线(+Y)朝向身体外侧前方,长发关节会沿着平面滑动,避免插进脖子或锁骨区域。
3. 尾巴防穿身
把平面绑定到髋部骨骼并略微前倾,作为尾巴根部的"挡板"。
需要说明的是:平面是无限大的,不存在"平面边缘",所以在制作流程中更依赖bone绑定 + 姿态同步让平面跟随角色移动,而不是试图靠节点位置"摆放一个有限区域"。
与其他碰撞体的取舍
在实际项目中,三种碰撞体通常组合使用,各有侧重:
- SpringBoneCollisionPlane3D(平面):适合无限延伸的阻挡面,如地面、衣领、肩颈挡板;参数最少,只有继承来的绑定与偏移属性。
- SpringBoneCollisionSphere3D(球体):带
radius(默认0.1)与inside(默认false)两个属性。inside = true时碰撞体会"把关节困在球体内部",适合模拟头部内部、胸部腔体等封闭空间。 - SpringBoneCollisionCapsule3D(胶囊):带
height(默认0.5)、radius(默认0.1)、mid_height与inside属性。mid_height是排除半球后的圆柱中段高度,即两个半球球心之间的距离,是height的包装属性;且胶囊约束height必须至少是radius的两倍,否则会自动调整为合法值(退化为球)。
| 属性 | SpringBoneCollisionPlane3D | SpringBoneCollisionSphere3D | SpringBoneCollisionCapsule3D |
|---|---|---|---|
| 几何参数 | 无(无限平面) | radius(默认 0.1) | radius(默认 0.1)、height(默认 0.5)、mid_height |
inside陷阱模式 | 不适用 | 支持 | 支持 |
| 继承自基类的绑定属性 | bone、bone_name、position_offset、rotation_offset | 同左 | 同左 |
调参要点与版本注意事项
要让平面碰撞与弹簧骨骼配合出自然效果,需同时理解模拟器侧的几个核心参数(它们直接决定关节在碰撞前后的运动行为):
- stiffness(刚度):值越大恢复初始姿态越快;若为
0,修改后的姿态永远不会回到原始姿态,可用来做"垂死布料"效果。 - drag(阻尼):值越大摆动被抑制得越明显。
- gravity(重力):注意它不是加速度,而是沿
gravity_direction方向的恒定速度;若不为0,姿态将始终受重力影响而无法完全复原,适合制作自然下垂的头发。 - external_force(外力):恒定施加于骨骼的力,等效于"父
Skeleton3D以反方向同速移动"的结果,常用来模拟风力或反重力。 - rotation_axis(旋转轴):设为特定轴时关节像铰链一样受限;
ROTATION_AXIS_ALL为无约束旋转,ROTATION_AXIS_CUSTOM允许自定义任意轴。文档特别提醒:旋转轴向量与骨骼前向向量不应共线,因为模拟器不考虑扭转力,共线会导致意外旋转。 - mutable_bone_axes(可变动骨骼轴,默认
true):为false时求解器从骨骼 Rest 姿态读取并缓存骨骼轴,性能略有提升,但会忽略修改流程之前对骨骼姿态的位移变化。
另外还有一个容易踩坑的细节:set_end_bone_name()要求末端骨骼必须是根骨骼或根骨骼的子骨骼;如果两者相同,则必须通过set_extend_end_bone(index, true)扩展出尾巴(扩展尾巴的配置会分配在关节列表的最后一个元素上),骨骼才能产生抖动。
关于版本:从 Godot 4.6 开始,SpringBoneSimulator3D的get_end_bone_direction、get_joint_rotation_axis、get_rotation_axis、set_end_bone_direction、set_joint_rotation_axis、set_rotation_axis的枚举类型由SpringBoneSimulator3D.BoneDirection/RotationAxis迁移为SkeletonModifier3D.BoneDirection/RotationAxis(见 upgrading_to_godot_4.6.rst),迁移时注意 GDScript 直接兼容、C# 需要源码级适配。
最小可用场景示例
下面给出一个 GDScript 代码层面的最小搭建流程,演示如何用代码把平面碰撞体接入模拟器(编辑器中也完全可以通过场景树完成同样配置):
# 假设 skeleton 是角色的 Skeleton3D 节点 var simulator := SpringBoneSimulator3D.new() skeleton.add_child(simulator) # 1. 定义骨骼链:从根骨骼到末端骨骼,中间骨骼自动生成关节列表 simulator.set_root_bone_name(0, "Hair_Root") simulator.set_end_bone_name(0, "Hair_Tip") # 2. 基础参数(按需调整) simulator.set_stiffness(0, 0.8) # 恢复力 simulator.set_drag(0, 0.6) # 阻尼 simulator.set_radius(0, 0.05) # 关节半径,决定碰撞体"厚感" simulator.set_gravity(0, 0.5) # 重力速度 simulator.set_gravity_direction(0, Vector3.DOWN) # 3. 注册碰撞体:启用所有子碰撞体模式(碰撞顺序=场景树顺序) simulator.set_enable_all_child_collisions(0, true) # 4. 添加无限平面碰撞体并绑定到骨骼 var plane := SpringBoneCollisionPlane3D.new() simulator.add_child(plane) plane.bone_name = "Neck" # 跟随颈部骨骼姿态 plane.position_offset = Vector3(0, 0.1, 0) # 相对骨骼位置偏移 plane.rotation_offset = Quaternion() # 保持法线为本地 +Y # 5. 需要排除某个子碰撞体时,加入排除列表 simulator.set_exclude_collision_count(0, 1) simulator.set_exclude_collision_path(0, 0, simulator.get_path_to(inner_collider))总结
SpringBoneCollisionPlane3D是 Godot 弹簧骨骼碰撞体系中结构最简单、用途却很关键的碰撞体:一个无限延伸、法线恒为 +Y 的平面。它的实战价值在于作为"无限阻挡面"与SpringBoneSimulator3D的关节半径求解器协作,防止毛发、布料、尾巴等惯性模拟物体穿入地面或身体。使用时牢记三条铁律:必须是模拟器的子节点、父Skeleton3D与骨骼不能被缩放、碰撞顺序由碰撞列表或场景树顺序决定。配合bone/position_offset/rotation_offset的骨骼绑定能力,它就能稳定地跟随角色移动并持续提供碰撞约束。
- 文档
- 教程
- 游戏开发
【免费下载链接】godot-docs
Godot Engine official documentation
相关推荐
Godot 弹簧骨骼碰撞体 SpringBoneCollision3D 完全指南:为 SpringBoneSimulator3D 配置头发、布料与尾巴的物理碰撞
Godot 弹簧骨骼碰撞体 SpringBoneCollision3D 完全指南:为 SpringBoneSimulator3D 配置头发、布料与尾巴的物理碰撞
文档教程游戏开发Godot 4 骨骼弹簧物理:SpringBoneCollisionCapsule3D 胶囊碰撞体完全指南
Godot 4 骨骼弹簧物理:SpringBoneCollisionCapsule3D 胶囊碰撞体完全指南 SpringBoneCollisionCapsule
文档教程游戏开发Godot 3D 粒子碰撞指南:GPUParticlesCollision3D 四种碰撞体全解析
Godot 3D 粒子碰撞指南:GPUParticlesCollision3D 四种碰撞体全解析 GPU 粒子完全在显卡上运行,天然无法访问引擎的物理世界; G
文档教程游戏开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考