- 文档
- 教程
- 游戏开发
【免费下载链接】godot-docs
Godot Engine official documentation
本篇基于 Godot 官方文档仓库中的类参考文档 class_skeleton3d.rst,系统讲解Skeleton3D节点的骨骼层级结构、pose/rest 核心概念、完整属性与 API、皮肤绑定机制,以及它与SkeletonModifier3D体系(布娃娃物理、IK、SpringBone 等)的协作方式。读完后,你能够用 GDScript 以编程方式构建和操控骨骼、正确理解姿势更新的时序(deferred process),并照着仓库中的教程完成布娃娃物理与骨骼重定向两类典型实战。
一、Skeleton3D 是什么:继承链与核心概念
Skeleton3D继承自Node3D(Node3D←Node←Object),官方定义为“包含骨骼层级的节点,用于创建 3D 骨骼动画”(A node containing a bone hierarchy, used to create a 3D skeletal animation)。它提供管理骨骼层级的接口,涵盖pose(姿势)、rest(静止姿态)与 animation(动画),并且可以驱动布娃娃(ragdoll)物理。
理解Skeleton3D必须先分清三个概念(文档 Description 原话):
- rest(静止姿态):骨骼层级的初始变换,是骨骼“归零”时的基准;
- pose(姿势):决定骨骼相对于整个骨骼(skeleton)的总体变换。骨骼当前的实际变换 = rest 基础上的 pose;
- “global pose”(全局姿势)的坑:文档特别强调,这里的 "global pose" 指骨骼相对于 skeleton 的总体变换,而并不是骨骼在真实世界/场景中的 global(世界)变换。这一点在调用
get_bone_global_pose()/set_bone_global_pose()时最容易踩坑。
典型场景结构
在编辑器中,一个角色模型导入后通常呈现如下结构(选自布娃娃教程的 场景树截图,源自 ragdoll_system.rst):
可以看到:Skeleton3D作为骨骼数据的“宿主”,其下挂载PhysicalBoneSimulator3D,后者再挂载若干PhysicalBone3D(每个代表一根骨骼的刚体)以及各自的CollisionShape3D。蒙皮网格(MeshInstance3D)通过Skin资源绑定到Skeleton3D,随骨骼变换实时变形。
编辑器菜单
选中Skeleton3D节点后,3D 视口顶部会出现Skeleton3D菜单(截图来自 ragdoll_system.rst),提供Reset All Bone Poses、Apply All Poses to Rests、Create Physical Skeleton、Export Skeleton Profile等操作:
二、属性(Properties)完整解析
Skeleton3D共暴露 4 个属性,以下逐一给出类型、默认值与源码级含义:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
animate_physical_bones | bool | true | 已弃用(Deprecated)。控制内部虚拟PhysicalBoneSimulator3D的active状态,仅用于兼容旧配置。 |
modifier_callback_mode_process | ModifierCallbackModeProcess | 1(即PROCESS_IDLE) | 设置SkeletonModifier3D子节点的 Modifier 回调处理时机。 |
motion_scale | float | 1.0 | 对 3D 位置轨道动画进行倍数缩放。 |
show_rest_only | bool | false | 为true时无视 pose 值,强制显示骨骼的默认 rest 姿态;编辑器中同时禁止编辑骨骼。 |
animate_physical_bones(已弃用)
文档明确指出:如果你遵循推荐工作流——显式地把PhysicalBoneSimulator3D作为Skeleton3D的子节点——那么你可以通过它的SkeletonModifier3D.active属性来控制是否参与射线投射/仿真,而无需调用physical_bones_start_simulation()。animate_physical_bones只针对旧版(已弃用)配置:那些配置下Skeleton3D内部持有一个“虚拟”的PhysicalBoneSimulator3D以维持向后兼容,该属性控制的就是这个内部实例。
modifier_callback_mode_process
取值来自枚举ModifierCallbackModeProcess:
| 常量 | 值 | 含义 |
|---|---|---|
MODIFIER_CALLBACK_MODE_PROCESS_PHYSICS | 0 | 在物理帧处理修改(对应Node.NOTIFICATION_INTERNAL_PHYSICS_PROCESS)。 |
MODIFIER_CALLBACK_MODE_PROCESS_IDLE | 1 | 在 process 帧处理修改(对应Node.NOTIFICATION_INTERNAL_PROCESS),默认值。 |
MODIFIER_CALLBACK_MODE_PROCESS_MANUAL | 2 | 不自动处理修改,改用advance(delta)手动推进。 |
motion_scale 与动画归一化
motion_scale会在播放时乘以动画中的 Position 轨道数值。注意文档的告诫:除非该值为1.0,动画关键帧的位置值不会等于实际位置值(即你读到的关键帧数值与实际表现出的位移相差一个倍率)。这个属性在骨骼重定向管线中有实际来源:retargeting_3d_skeletons.rst 说明,启用 “Normalize Position Tracks” 导入选项后,位置轨道会按scale_base_bone(人形预设SkeletonProfileHumanoid中为 “Hips”)的高度归一化,该高度即被写入Skeleton3D的motion_scale;若关闭该选项,motion_scale始终导入为1.0。
show_rest_only
设为true时强制骨骼保持 rest 姿态。它对应一个show_rest_only_changed信号,可在切换时收到通知——常用于在编辑器视口中临时“定格”骨骼以便检查 rest。
三、骨骼层级管理 API
这一组方法用于以编程方式创建和修改骨骼层级,是构建程序化角色或导入自定义骨骼的核心:
| 方法 | 返回 | 说明 |
|---|---|---|
add_bone(name) | int | 新增骨骼,返回新骨骼索引;失败返回-1。骨骼名必须唯一、非空,且不能包含:与/字符。 |
set_bone_name(bone_idx, name) | void | 重命名骨骼。 |
set_bone_parent(bone_idx, parent_idx) | void | 设定父骨骼;-1表示无父。约束:parent_idx必须小于bone_idx(父骨骼索引恒小于子骨骼)。 |
get_bone_parent(bone_idx) | int | 查询父骨骼索引,无父返回-1。 |
get_bone_children(bone_idx) | PackedInt32Array | 返回子骨骼索引数组。 |
get_bone_count() | int | 骨骼总数。 |
find_bone(name) | int | 按名字查索引,不存在返回-1。 |
get_bone_name(bone_idx) | String | 按索引查名字。 |
get_parentless_bones() | PackedInt32Array | 返回所有“无父骨骼”的索引,即骨骼树的根骨骼集合。 |
get_concatenated_bone_names() | StringName | 所有骨骼名以逗号拼接成的单个StringName,文档建议用途是把它作为枚举型属性的 hint。 |
clear_bones() | void | 清空全部骨骼。 |
unparent_bone_and_rest(bone_idx) | void | 解除某骨骼的父级,并将其 rest 位置重置为解除前其父骨骼处的位置。 |
set_bone_rest(bone_idx, rest) | void | 设置骨骼的 rest 变换。 |
get_bone_rest(bone_idx) | Transform3D | 查询 rest 变换。 |
localize_rests() | void | 将全部骨骼恢复到 rest 姿态(文档描述为 “Returns all bones in the skeleton to their rest poses”)。 |
版本号与缓存失效:get_version()返回骨骼层级(含改名)发生变更的次数。文档明确其用途——“用于使 IK 求解器及其他处理骨骼的节点中的缓存失效”,且该版本不会被序列化,只应在单个Skeleton3D实例的生命周期内使用。做自定义 IK/缓存类逻辑时,这是一个低成本的脏标记机制。
骨骼元数据(Bone Meta):set_bone_meta(bone_idx, key, value)、get_bone_meta(bone_idx, key)、has_bone_meta(bone_idx, key)、get_bone_meta_list(bone_idx)四件套,让你给骨骼挂任意键值对,适合标记“手部骨骼”“攻击点骨骼”之类的自定义语义。
一个纯代码构建骨骼的示例
结合上述 API,程序化构建一个三段骨骼链的最小示例:
var skeleton := $Skeleton3D as Skeleton3D var root := skeleton.add_bone("root") # 索引 0 var arm := skeleton.add_bone("arm") # 索引 1 var hand := skeleton.add_bone("hand") # 索引 2 skeleton.set_bone_parent(arm, root) # 必须满足 parent_idx < bone_idx skeleton.set_bone_parent(hand, arm) # 设置 rest(局部变换,Transform3D 由 Basis/Vector3 构造) skeleton.set_bone_rest(arm, Transform3D(Basis(), Vector3(0, 0, -0.3))) skeleton.set_bone_rest(hand, Transform3D(Basis(), Vector3(0, 0, -0.25))) skeleton.set_bone_meta(root, &"part", "torso") # 挂自定义元数据注意add_bone在 Godot 4.3 中的返回类型从void变更为了int32——这一变更可在 upgrading_to_godot_4.3.rst 的迁移对照表中确认。
四、姿势(Pose)API 与 deferred process 时序
局部姿势与分量访问
| 方法 | 说明 |
|---|---|
set_bone_pose(bone_idx, pose) | 设置骨骼的局部pose 变换。 |
get_bone_pose(bone_idx) | 查询局部 pose。 |
set_bone_pose_position(bone_idx, position) | 只改位置,position是相对于Skeleton3D 节点局部坐标的Vector3。 |
get_bone_pose_position(bone_idx) | 查询 pose 位置(Skeleton3D 局部坐标)。 |
set_bone_pose_rotation(bone_idx, rotation) | 只改旋转,Quaternion相对于父骨骼旋转的局部空间。 |
get_bone_pose_rotation(bone_idx) | 查询 pose 旋转。 |
set_bone_pose_scale(bone_idx, scale)/get_bone_pose_scale(bone_idx) | 设置/查询 pose 缩放。 |
全局姿势与性能陷阱
set_bone_global_pose(bone_idx, pose)与get_bone_global_pose(bone_idx)操作的是相对 skeleton 的“全局”姿势(非世界变换)。文档给出了一条关键性能提示:
如果其他骨骼的 pose 已经被修改过,此方法会触发一次 dirty pose 重算,导致性能下降。若你知道会批量应用多个 global pose,请考虑改用
set_bone_pose()并自行预先计算。
骨骼皮肤缩放(Skin Scale)
set_bone_skin_scale(bone_idx, skin_scale)/get_bone_skin_scale(bone_idx)设置/查询骨骼的皮肤缩放。文档对其行为描述得非常细致:
- 该缩放不影响子骨骼,专门用于修改蒙皮的视觉“厚度”;
- 即使蒙皮在视觉上被变形,骨骼本身不会发生缩放或位移——因此你可能需要用
BoneSpaceAdjuster3D调整子骨骼原点,使其关节位置与缩放后的蒙皮保持同步; - 注意:皮肤缩放可能破坏依赖骨骼长度进行蒙皮的
SkeletonModifier类(如SpringBoneSimulator和IKModifier3D)的 gizmo 外观。
时序:pose 何时才是“最终值”
这是Skeleton3D使用中最容易误解的部分。get_bone_pose()/get_bone_global_pose()的文档都附有相同的 Note:你拿到的是 process 阶段设置的 pose,而最终 pose 可能在 deferred process 阶段被SkeletonModifier3D覆写。若需要读取 modifier 处理完的最终 pose,正确做法是监听SkeletonModifier3D.modification_processed信号,在信号触发的时刻再调用get_bone_pose()/get_bone_global_pose()。
相关的强制刷新接口:
force_update_bone_child_transform(bone_idx):强制更新指定骨骼及其所有子骨骼的变换;force_update_all_bone_transforms():已弃用,文档标注“应仅在内部调用”。
复位与启用
reset_bone_pose(bone_idx, reset_bone_skin_scale=false):把单个骨骼 pose 复位到 rest,可选同时复位皮肤缩放;reset_bone_poses(reset_bone_skin_scale=false):全部骨骼复位;set_bone_enabled(bone_idx, enabled=true)/is_bone_enabled(bone_idx):启用/禁用某根骨骼的 pose,状态切换会触发bone_enabled_changed(bone_idx)信号,信号中可再调is_bone_enabled()读取新值。禁用骨骼的典型场景是 IK 中把目标骨骼链“锁死”不参与求解。
五、皮肤绑定:register_skin 与 Skin 资源
register_skin(skin):把给定的Skin绑定到骨骼,返回一个SkinReference(引用令牌)。Skin资源本身是“逆绑定姿态(inverse bind pose)矩阵 + 对应骨骼”的列表(见 class_skin.rst),其中 bind pose 矩阵用于把顶点空间变换到骨骼空间。create_skin_from_rest_transforms():基于当前 rest 变换创建Skin(文档中该方法暂无描述,从方法名与Skin的语义可以推断:以 rest 作为绑定姿态生成蒙皮资源)。
实际工程中,Skin一般由 glTF/FBX 等格式导入器自动生成,与Mesh一同构成蒙皮网格;只有在程序化生成骨骼(如运行时构建骨骼链)时才需要手工调用register_skin。
六、信号与常量
| 信号 | 触发时机 |
|---|---|
bone_enabled_changed(bone_idx) | 通过set_bone_enabled()切换某骨骼启用状态时。 |
bone_list_changed() | 骨骼列表发生变化时,如add_bone()、set_bone_parent()、unparent_bone_and_rest()、clear_bones()。 |
pose_updated() | pose 更新时。注意:在更新流程内部该信号不触发,因此检测不到SkeletonModifier3D的修改。 |
rest_updated() | rest 更新时。 |
show_rest_only_changed() | show_rest_only属性变化时。 |
skeleton_updated() | 最终 pose 计算完成、即将应用到 skin 时。此时所有SkeletonModifier3D的处理已完成;若要检测单个 modifier 完成,使用其自身的modification_processed信号。 |
常量:NOTIFICATION_UPDATE_SKELETON = 50——当骨骼姿势需要更新时收到的通知,且每帧只会在 deferred process 中调用一次。继承Skeleton3D做自定义骨骼节点时,需要覆写notification()处理此值。
七、Modifier 体系:modifier_callback_mode_process 与 advance()
Skeleton3D的生态一半由SkeletonModifier3D子类构成。从 class_skeletonmodifier3d.rst 可以确认,SkeletonModifier3D通过拥有Skeleton3D父节点来找到要修改的目标骨骼,其继承者包括:BoneConstraint3D、BoneSpaceAdjuster3D、BoneTwistDisperser3D、IKModifier3D、LimitAngularVelocityModifier3D、LookAtModifier3D、ModifierBoneTarget3D、PhysicalBoneSimulator3D、RetargetModifier3D、SkeletonIK3D、SpringBoneSimulator3D、XRBodyModifier3D、XRHandModifier3D。
Modifier 的处理时机由Skeleton3D的modifier_callback_mode_process属性统一控制(见第二节枚举表):
- 默认(
PROCESS_IDLE):modifier 在 process 帧处理;若场景中有AnimationMixer,修改总发生在动画播放处理之后; PROCESS_PHYSICS:改到物理帧处理,适合与物理事件保持同步的场景;PROCESS_MANUAL:完全手动。此时用advance(delta)方法——“手动按指定时间(秒)推进子SkeletonModifier3D”。文档 Note 指出:delta会先在Skeleton3D中临时累加,deferred process 使用累加值统一处理修改。也就是说连续多次调用advance(0.016)不会立刻多次生效,而是在 deferred 阶段以总和一次性结算,这对实现可变速播放、暂停、回放等自研骨骼系统很重要。
八、布娃娃物理实战:从编辑期到运行期
Skeleton3D文档的 Description 明确提到“It can also use ragdoll physics”。仓库中 ragdoll_system.rst 给出了完整的推荐工作流,这里整理为可复制的步骤:
1. 创建物理骨骼:选中Skeleton3D节点,点击 3D 视口顶部的 Skeleton3D 按钮,选择Create Physical Skeleton。引擎会为每根骨骼生成PhysicalBone3D节点、碰撞形状,并用 pin joint 连接各骨骼。
2. 清理与优化:每个需要仿真的PhysicalBone3D都有性能开销,应删除过小或纯工具性的骨骼(教程示例中删除了MASTER、waist、neck、headtracker)。人形角色不需要给每根手指单独做物理骨骼,可以整只手用一根骨骼表示。
3. 调整关节约束:PhysicalBone3D默认带无约束 pin joint,需在检查器Joint区修改。可用关节类型:None(无约束)、ConeJoint(球窝,适合肩/髋/颈)、HingeJoint(角约束,适合肘/膝,记得启用Angular Limit)、PinJoint(默认,保持连接但会导致骨骼“塌陷”,不推荐默认使用)、SliderJoint(沿轴滑动)、6DOFJoint(功能最强也最复杂)。经验值:ConeJoint 的Swing Span建议 20~90 度、Twist Span建议 20~45 度。
4. 调整碰撞形状:建议在调整完关节之后再调碰撞形状(旋转关节会连带旋转碰撞形状)。一个PhysicalBone3D下可以挂多个碰撞形状以表达复杂肢体。
5. 启动/停止仿真(运行期代码):在PhysicalBoneSimulator3D节点上挂脚本:
func _ready(): physical_bones_start_simulation()public override void _Ready() { PhysicalBonesStartSimulation(); }停止仿真调用physical_bones_stop_simulation()。还可以把骨骼名(不是PhysicalBone3D节点名,可在检查器Bone Name属性中查看)数组作为参数传入,让仿真只覆盖部分骨骼——这是做“手臂拖曳”“武器挂接”等局部 ragdoll 效果的常用手法。
关于弃用 API:Skeleton3D自身也有physical_bones_start_simulation(bones = [])、physical_bones_stop_simulation()、physical_bones_add_collision_exception(exception: RID)、physical_bones_remove_collision_exception(exception: RID)四个方法,但全部标记为 Deprecated——文档的推荐路径是直接在PhysicalBoneSimulator3D上调用同名方法(见 class_physicalbonesimulator3d.rst,它还额外提供了is_simulating_physics()查询接口)。碰撞例外(collision exception)的行为与RigidBody3D一致。新代码不要依赖Skeleton3D上的这套旧接口和animate_physical_bones属性。
九、骨骼重定向中的 Skeleton3D:BoneMap 与 motion_scale 的来源
另一个与Skeleton3D强相关的实战场景是动画/骨骼重定向(retargeting_3d_skeletons.rst)。共享动画的前提是不同模型的 Bone Rest 与骨骼名一致,导入器通过选中Skeleton3D节点后的Retarget区实现:
- bone_map:配合
SkeletonProfile(人形资产可用内置的SkeletonProfileHumanoid预设)做自动映射;映射错误/缺失会以品红/红色按钮警告(不阻断导入)。自动映射基于名字模式匹配,因此建议骨骼使用通用英文名; - Remove Tracks区:
Except Bone Transform(剔除骨骼 Transform 之外的轨道)、Unimportant Positions(移除root_bone/scale_base_bone之外的位置轨道;Godot 4 中动画 Transform 值包含 Bone Rest,关闭此选项可能导致动画意外改变体型)、Unmapped Bones; - Bone Renamer区:重命名已映射骨骼;
Unique Node使 Skeleton 成为名为skeleton_name的唯一节点,让动画轨道路径与场景层级解耦; - Rest Fixer区:
Apply Node Transform、Normalize Position Tracks(将位置轨道按scale_base_bone高度归一化,高度值写入Skeleton3D的motion_scale,播放时乘以该值——这就是第二节motion_scale属性的实际来源)、Overwrite Axis等。
编辑器侧也提供了配套入口:选中Skeleton3D后通过 3D 视口工具栏的Skeleton3D菜单可导出SkeletonProfile(Export Skeleton Profile),供非标准人形模型使用。
十、弃用(Deprecated)API 汇总
文档中共有 7 处弃用标注,升级项目时应重点排查:
| 弃用项 | 状态 | 替代方案 |
|---|---|---|
属性animate_physical_bones | 可能变更或移除 | 显式添加PhysicalBoneSimulator3D子节点,用其active属性 |
方法clear_bones_global_pose_override() | 可能变更或移除 | 无直接替代,override 机制整体弃用 |
方法force_update_all_bone_transforms() | 仅应内部调用 | 不对外使用 |
方法get_bone_global_pose_no_override(bone_idx) | 可能变更或移除 | get_bone_global_pose() |
方法get_bone_global_pose_override(bone_idx) | 可能变更或移除 | 无 |
方法set_bone_global_pose_override(bone_idx, pose, amount, persistent=false) | 可能变更或移除 | 通过SkeletonModifier3D子类实现等效逻辑 |
方法physical_bones_start_simulation / stop_simulation / add_collision_exception / remove_collision_exception(共 4 个) | 可能变更或移除 | 在PhysicalBoneSimulator3D上调用同名方法 |
其中 override 系列(set/get/clear_bones_global_pose_override)曾是 IK 等模块的过渡方案,amount表示插值强度、persistent表示 pose 是否保留;文档给出的换算提示——把Node3D的世界变换转为骨骼 global pose 需乘以节点global_transform的affine_inverse()——对理解“骨骼 global pose 相对 skeleton 而非世界”的坐标系约定仍然有参考价值。
十一、参考文档索引
| 资源 | 路径 |
|---|---|
| Skeleton3D 类参考(本文主体) | classes/class_skeleton3d.rst |
| SkeletonModifier3D 类参考 | classes/class_skeletonmodifier3d.rst |
| Skin 资源类参考 | classes/class_skin.rst |
| PhysicalBoneSimulator3D 类参考 | classes/class_physicalbonesimulator3d.rst |
| 布娃娃系统教程(含截图/视频) | tutorials/physics/ragdoll_system.rst |
| 3D 骨骼重定向教程 | tutorials/assets_pipeline/retargeting_3d_skeletons.rst |
| Godot 4.3 迁移对照表 | tutorials/migrating/upgrading_to_godot_4.3.rst |
小结:Skeleton3D是 Godot 3D 骨骼动画的骨架节点——它持有骨骼层级(rest + pose + meta),通过register_skin()连接蒙皮,通过SkeletonModifier3D子节点体系(受modifier_callback_mode_process统一调度)叠加 IK、约束、SpringBone 与布娃娃物理。掌握“pose 的 deferred 结算时序”“global pose 相对 skeleton 而非世界”“弃用的 physical_bones_* 接口迁移到PhysicalBoneSimulator3D”这三点,就基本覆盖了该类在工程中的所有易错面。
- 文档
- 教程
- 游戏开发
【免费下载链接】godot-docs
Godot Engine official documentation
相关推荐
使用 Kubernetes Python 客户端 V1ContainerPort 配置容器端口:字段详解、校验规则与实战示例
使用 Kubernetes Python 客户端 V1ContainerPort 配置容器端口:字段详解、校验规则与实战示例 本篇技术指南围绕 Kubernet
文档教程游戏开发Godot 3D 布娃娃物理实战:解读 Ragdoll Physics 演示项目的骨骼模拟、冲击反馈与场景构建
Godot 3D 布娃娃物理实战:解读 Ragdoll Physics 演示项目的骨骼模拟、冲击反馈与场景构建 导读 本文围绕 godot demo proje
示例工程Godot Skeleton2D 深度解析:2D 骨骼动画的骨骼层级、位姿控制与 IK 修改体系
Godot Skeleton2D 深度解析:2D 骨骼动画的骨骼层级、位姿控制与 IK 修改体系 本文基于 godot docs 仓库中的 Skeleton2D
文档教程游戏开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考