☰
Godot Skeleton3D 深入解析:3D 骨骼动画、姿势管理与布娃娃物理的完整实践指南
2026/10/13 1:50:00 网站建设 项目流程
  • 文档
  • 教程
  • 游戏开发

【免费下载链接】godot-docs

Godot Engine official documentation

项目地址:https://gitcode.com/GitHub_Trending/go/godot-docs
点击查看免费下载

本篇基于 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_bonesbooltrue已弃用(Deprecated)。控制内部虚拟PhysicalBoneSimulator3D的active状态,仅用于兼容旧配置。
modifier_callback_mode_processModifierCallbackModeProcess1(即PROCESS_IDLE)设置SkeletonModifier3D子节点的 Modifier 回调处理时机。
motion_scalefloat1.0对 3D 位置轨道动画进行倍数缩放。
show_rest_onlyboolfalse为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_PHYSICS0在物理帧处理修改(对应Node.NOTIFICATION_INTERNAL_PHYSICS_PROCESS)。
MODIFIER_CALLBACK_MODE_PROCESS_IDLE1在 process 帧处理修改(对应Node.NOTIFICATION_INTERNAL_PROCESS),默认值。
MODIFIER_CALLBACK_MODE_PROCESS_MANUAL2不自动处理修改,改用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

项目地址:https://gitcode.com/GitHub_Trending/go/godot-docs
点击查看免费下载

相关推荐

上一篇:OK-WW终极指南:鸣潮自动化战斗与资源刷取完整解决方案
下一篇:zjkal/time-helper 用户行为分析:时间维度数据处理

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询