Skeleton3D
2026/4/14大约 6 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — Skeleton3D
Skeleton3D
节点继承关系
继承自 Node
| 类型 | 名称 | 说明 |
|---|---|---|
| 属性 | Name | 节点名称 |
| 属性 | ProcessMode | 处理模式(始终 / 暂停时 / 仅编辑器) |
| 属性 | ProcessPriority | 处理优先级,数字越小越先执行 |
| 信号 | ready | 节点进入场景树并准备就绪 |
| 信号 | tree_entered | 节点进入场景树 |
| 信号 | tree_exited | 节点完全离开场景树 |
| 方法 | GetNode<T>() | 按路径获取子节点 |
| 方法 | AddChild() | 添加子节点 |
| 方法 | RemoveChild() | 移除子节点 |
| 方法 | QueueFree() | 帧结束后释放节点 |
| 方法 | GetParent() | 获取父节点 |
定义
Skeleton3D 是 Godot 中的 3D 骨骼系统(Skeleton)节点。与 Skeleton2D 不同的是,Skeleton3D 通常不需要你手动创建——当你导入一个带有骨骼的 3D 模型文件(如 .glb、.fbx、.gltf)时,Godot 会自动在导入的场景中生成 Skeleton3D 节点及其所有骨骼。
你可以把 Skeleton3D 理解为一个机器人的内部骨架:你看到的 3D 角色模型(皮肤/网格)是贴在骨架外面的"外衣",而 Skeleton3D 负责管理骨架的每一根骨头。当 AnimationPlayer 播放动画时,实际上是驱动这些骨骼旋转和位移,然后网格(MeshInstance3D)跟着骨骼一起变形运动。
一句话理解:Skeleton3D 是 3D 模型的骨骼容器,负责管理 3D 骨骼层级和变换。它通常从导入的 3D 模型自动生成,你只需要了解如何通过代码查找和操作骨骼即可。
使用频率:★★★ 一般常用——只要你的 3D 角色有骨骼动画(Skeletal Animation),就会自动存在这个节点。
节点用途
- 管理 3D 模型的骨骼层级结构(通常是自动生成的)
- 提供骨骼查找和变换操作接口
- 作为 BoneAttachment3D 和 SkeletonIK3D 的父节点
- 在代码中程序化控制骨骼(比如头部朝向目标、身体倾斜等)
- 存储骨骼的休息姿态(Rest Pose)和当前姿态(Pose)
使用场景
典型场景
- 导入带骨骼的 3D 角色模型后自动生成,配合 AnimationPlayer 播放动画
- 通过代码让角色的头部或眼睛朝向目标位置
- 在骨骼上挂载武器、特效等附件(配合 BoneAttachment3D)
- 使用 IK 让角色的脚贴合地面(配合 SkeletonIK3D)
不适用场景
- 2D 角色骨骼动画 -> 使用 Skeleton2D
- 不带骨骼的静态 3D 模型 -> 不需要骨骼系统
- 简单的 3D 物体动画 -> 直接用 AnimationPlayer 驱动 Node3D 的变换即可
常用节点搭配
| 搭配节点 | 用途 | 必需? |
|---|---|---|
| AnimationPlayer | 驱动骨骼动画 | 必需 |
| MeshInstance3D | 3D 网格模型(皮肤),跟随骨骼变形 | 必需(导入时自动生成) |
| BoneAttachment3D | 在骨骼上挂载武器、特效等 | 需要挂载附件时 |
| SkeletonIK3D | 逆向运动学,让骨骼链自动计算关节角度 | 需要 IK 效果时 |
| AnimationTree | 管理多个骨骼动画的自动切换 | 角色动作多时推荐 |
导入 3D 模型后的典型节点树:
CharacterBody3D
├── Node3D (或 "GeneralSkeleton") ← 导入的根节点
│ ├── Skeleton3D ← 骨骼系统(自动生成)
│ │ ├── Bone: Hips ← 臀部骨骼(自动生成)
│ │ │ ├── Bone: Spine ← 脊柱
│ │ │ │ ├── Bone: Head ← 头部
│ │ │ │ ├── Bone: LeftArm ← 左臂
│ │ │ │ └── Bone: RightArm ← 右臂
│ │ │ ├── Bone: LeftUpLeg ← 左大腿
│ │ │ └── Bone: RightUpLeg ← 右大腿
│ │ └── ...
│ └── MeshInstance3D ← 角色网格模型(自动生成)
└── AnimationPlayer ← 动画播放器(需要手动添加)生效必备素材/资源
| 资源 | 类型 | 说明 |
|---|---|---|
| 3D 模型文件 | .glb / .gltf / .fbx | 带骨骼的 3D 角色模型文件,导入后自动生成 Skeleton3D |
| Animation | Animation 资源 | 骨骼动画数据,可以内嵌在模型文件中,也可以单独导入 |
| Skin | Skin 资源 | 蒙皮数据,定义网格顶点和骨骼的绑定关系(导入时自动生成) |
节点属性与信号
骨骼属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
MotionScale | Vector3 | (1, 1, 1) | — | 运动缩放。用于调整动画的整体幅度,比如设为 (0.5, 0.5, 0.5) 可以让动作幅度减半 |
SkeletonName | StringName | "" | — | 骨骼名称。导入模型时自动设置,用于区分同一模型中的多套骨骼 |
ModifierStack | SkeletonModificationStack3D | null | — | 骨骼修改器栈,用于挂载 IK、约束等高级修改器 |
信号
| 信号 | 参数 | 说明 |
|---|---|---|
BonePoseChanged | boneIdx: int | 某个骨骼的姿势发生变化时触发 |
BoneSetupChanged | — | 骨骼层级结构发生变化时触发 |
SkeletonUpdateBegins | — | 骨骼更新开始时触发(每帧) |
SkeletonUpdateFinished | — | 骨骼更新完成时触发(每帧) |
常用方法
| 方法 | 返回值 | 说明 |
|---|---|---|
GetBoneCount() | int | 获取骨骼总数 |
GetBoneName(boneIdx) | StringName | 获取指定索引的骨骼名称 |
FindBone(name) | int | 根据名称查找骨骼索引,找不到返回 -1 |
GetBoneParent(boneIdx) | int | 获取指定骨骼的父骨骼索引 |
GetBoneGlobalPose(boneIdx) | Transform3D | 获取骨骼的全局变换(世界空间) |
GetBonePose(boneIdx) | Transform3D | 获取骨骼的本地变换(相对于父骨骼) |
SetBonePose(boneIdx, pose) | void | 设置骨骼的本地变换 |
GetBoneRest(boneIdx) | Transform3D | 获取骨骼的休息姿态 |
SetBoneRest(boneIdx, rest) | void | 设置骨骼的休息姿态 |
IsBoneRestDirty() | bool | 休息姿态是否被修改过 |
PhysicalBonesStopSimulation() | void | 停止物理骨骼模拟(物理骨骼相关) |
PhysicalBonesStartSimulation() | void | 启动物理骨骼模拟(物理骨骼相关) |
代码示例
找到头部骨骼并让头部朝向目标
C
using Godot;
public partial class HeadTracker : Node3D
{
private Skeleton3D _skeleton;
private int _headBoneIdx;
private int _neckBoneIdx;
[Export] public Node3D Target { get; set; }
public override void _Ready()
{
_skeleton = GetNode<Skeleton3D>("Model/GeneralSkeleton");
// 查找骨骼索引
_headBoneIdx = _skeleton.FindBone("Head");
_neckBoneIdx = _skeleton.FindBone("Neck");
if (_headBoneIdx == -1)
{
GD.PrintErr("找不到名为 Head 的骨骼!");
return;
}
GD.Print($"头部骨骼索引: {_headBoneIdx}");
GD.Print($"模型总骨骼数: {_skeleton.GetBoneCount()}");
}
public override void _Process(double delta)
{
if (_headBoneIdx == -1 || Target == null) return;
// 获取头部骨骼的全局位置
var headGlobalPose = _skeleton.GetBoneGlobalPose(_headBoneIdx);
Vector3 headPosition = headGlobalPose.Origin;
// 计算头部到目标的方向
Vector3 direction = (Target.GlobalPosition - headPosition).Normalized();
// 使用 LookAt 让头部朝向目标
var boneTransform = _skeleton.GetBonePose(_headBoneIdx);
boneTransform = boneTransform.LookingAt(direction, Vector3.Up);
_skeleton.SetBonePose(_headBoneIdx, boneTransform);
}
}GDScript
extends Node3D
@onready var skeleton: Skeleton3D = $Model/GeneralSkeleton
@export var target: Node3D
var head_bone_idx: int
var neck_bone_idx: int
func _ready():
# 查找骨骼索引
head_bone_idx = skeleton.find_bone("Head")
neck_bone_idx = skeleton.find_bone("Neck")
if head_bone_idx == -1:
push_error("找不到名为 Head 的骨骼!")
return
print("头部骨骼索引: ", head_bone_idx)
print("模型总骨骼数: ", skeleton.get_bone_count())
func _process(_delta):
if head_bone_idx == -1 or not target:
return
# 获取头部骨骼的全局位置
var head_global_pose = skeleton.get_bone_global_pose(head_bone_idx)
var head_position = head_global_pose.origin
# 计算头部到目标的方向
var direction = (target.global_position - head_position).normalized()
# 使用 LookingAt 让头部朝向目标
var bone_transform = skeleton.get_bone_pose(head_bone_idx)
bone_transform = bone_transform.looking_at(direction, Vector3.UP)
skeleton.set_bone_pose(head_bone_idx, bone_transform)骨骼名称可能不一样
不同 3D 模型的骨骼命名可能不同。常见的头部骨骼名称有:Head、head、Head_end、Bip01 Head 等。你可以在 Godot 编辑器中选中 Skeleton3D 节点,在检查器(Inspector)面板中查看所有骨骼名称,确保代码中使用的名称和模型一致。
