Node3D
2026/4/14大约 7 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — Node3D
Node3D
节点继承关系
继承链:Node → Node3D
注意:
Node3D不继承 CanvasItem,它走的是和 2D 完全不同的继承分支。3D 节点没有"可见性"和"Z 排序"的概念,取而代之的是摄像机视锥体和深度缓冲。
定义
Node3D 是所有 3D 节点的基类。和 Node2D 类似,它提供三维空间中的位置、旋转和缩放。但它不继承 CanvasItem,走的是另一条继承分支。
一句话理解:Node3D = 3D 空间中的基础容器。能移动、能旋转、能缩放,但在三维世界里。
打个比方:Node2D 像是钉在平面软木板上的卡片——只能在平面上移动和旋转。而 Node3D 像是一架悬挂在天花板上的无人机模型——它可以前后左右移动(位置)、上下俯仰和左右偏航(旋转)、还能变大变小(缩放),拥有完整的三个维度。
坐标系
Godot 使用 Y 轴朝上 的右手坐标系。想象你站在桌前:
- X 轴 → 你的右手方向(右)
- Y 轴 → 往天花板的方向(上)
- Z 轴 → 朝你脸的方向(前,正值朝向你)
记忆口诀
"右手定则":伸出右手,食指指向右(X),中指指向上(Y),大拇指朝向自己(Z)。
节点用途
- 作为 3D 场景的根节点,组织 3D 子节点
- 提供 3D 空间中的位置、旋转、缩放变换
- 实现角色移动、摄像机控制等 3D 行为
- 管理局部坐标和全局坐标之间的转换
使用场景
典型场景
- 3D 场景根节点:一个 3D 关卡的根节点通常是
Node3D,下面放置地面、建筑、角色、光源等。 - 角色根节点:3D 角色场景的根节点用
Node3D,下面放模型(MeshInstance3D)、碰撞体(CollisionShape3D)、摄像机等。 - 空标记点:用空
Node3D标记 3D 空间中的特殊位置,比如巡逻路径点、生成点、NPC 站位等。
不适用场景
常用节点搭配
| 搭配节点 | 用途 | 必需? |
|---|---|---|
| MeshInstance3D | 显示 3D 模型 | 视需求 |
| Camera3D | 3D 摄像机 | 视需求 |
| CollisionShape3D | 3D 碰撞形状 | 物理交互时 |
| RigidBody3D | 刚体物理 | 需要物理模拟时 |
| DirectionalLight3D / PointLight3D | 光源 | 需要光照时 |
| Area3D | 3D 检测区域 | 视需求 |
生效必备素材/资源
Node3D 本身不需要外部资源。但通常会搭配以下资源使用:
| 资源 | 用途 | 必需? |
|---|---|---|
| Mesh | 配合 MeshInstance3D 显示 3D 模型 | 显示模型时 |
| Shape3D | 配合 CollisionShape3D 做碰撞 | 物理交互时 |
| Material | 配合 MeshInstance3D 做材质 | 需要自定义外观时 |
节点属性与信号
位置与变换属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
| Position | Vector3 | (0, 0, 0) | — | 相对于父节点的位置(局部坐标) |
| Rotation | Vector3 | (0, 0, 0) | — | 欧拉旋转,单位是弧度(X/Y/Z 三轴) |
| RotationDegrees | Vector3 | (0, 0, 0) | — | 欧拉旋转,单位是度数(更直观) |
| RotationMode | RotationModeEnum | Euler | — | 旋转模式:Euler(欧拉角)/ Quaternion(四元数)/ Basis(基向量) |
| Scale | Vector3 | (1, 1, 1) | — | 缩放比例,(1, 1, 1) 为原始大小 |
| TopLevel | bool | false | — | 是否忽略父节点变换,直接在世界根上定位 |
全局变换属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
| GlobalPosition | Vector3 | — | — | 全局坐标位置(相对于场景根) |
| GlobalRotation | Vector3 | — | — | 全局旋转(弧度) |
| GlobalRotationDegrees | Vector3 | — | — | 全局旋转(度数) |
| GlobalScale | Vector3 | — | — | 全局缩放 |
| Transform | Transform3D | — | — | 完整的局部变换矩阵 |
| GlobalTransform | Transform3D | — | — | 完整的全局变换矩阵 |
| Basis | Basis | — | — | 旋转和缩放的基向量 |
视觉属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
| Visible | bool | true | — | 是否可见(3D 节点的可见性,不同于 CanvasItem 的 Visible) |
| ShowBehindParent | bool | false | — | 是否渲染在父节点之后 |
通用属性(继承自 Node)
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
| Name | String | — | Node | 节点名称 |
| ProcessMode | ProcessModeEnum | Inherit | Node | 处理模式 |
| Script | Script | null | Node | 附加脚本 |
常用方法
| 方法 | 返回值 | 说明 |
|---|---|---|
Translate(Vector3 offset) | void | 基于自身朝向移动(受旋转影响) |
RotateX(float angle) | void | 绕自身 X 轴旋转(俯仰) |
RotateY(float angle) | void | 绕自身 Y 轴旋转(偏航,最常用) |
RotateZ(float angle) | void | 绕自身 Z 轴旋转(翻滚) |
LookAt(Vector3 target, Vector3 up) | void | 朝目标点旋转(up 通常传 Vector3.Up) |
MoveToward(Vector3 target, float speed) | Vector3 | 朝目标方向移动指定距离 |
ToGlobal(Vector3 localPos) | Vector3 | 局部坐标转全局坐标 |
ToLocal(Vector3 globalPos) | Vector3 | 全局坐标转局部坐标 |
GetDirectionTo(Node3D node) | Vector3 | 获取朝向另一个节点的方向向量 |
GetDistanceTo(Node3D node) | float | 获取到另一个节点的距离 |
Orbit(Vector3 around, Vector3 up, float angle) | void | 绕指定点和轴旋转 |
SetProcess(bool enabled) | void | 启用/禁用 _Process |
代码示例
基础变换操作
C
using Godot;
public partial class Transform3DDemo : Node3D
{
public override void _Ready()
{
// 设置 3D 位置(X=右, Y=上, Z=前)
var node3D = GetNode<Node3D>("MyNode3D");
node3D.Position = new Vector3(0, 5, -10);
// 旋转 Y 轴 90 度(转身)
node3D.RotationDegrees = new Vector3(0, 90, 0);
// 缩放为 2 倍(整体等比放大)
node3D.Scale = new Vector3(2, 2, 2);
// 只在 Y 轴上拉长(变成"瘦高"的效果)
node3D.Scale = new Vector3(1, 2, 1);
}
}GDScript
extends Node3D
func _ready():
# 设置 3D 位置(X=右, Y=上, Z=前)
var node_3d = $MyNode3D as Node3D
node_3d.position = Vector3(0, 5, -10)
# 旋转 Y 轴 90 度(转身)
node_3d.rotation_degrees = Vector3(0, 90, 0)
# 缩放为 2 倍(整体等比放大)
node_3d.scale = Vector3(2, 2, 2)
# 只在 Y 轴上拉长(变成"瘦高"的效果)
node_3d.scale = Vector3(1, 2, 1)基于自身朝向移动
C
using Godot;
public partial class Movement3D : Node3D
{
[Export] public float ExWalkSpeed = 5.0f;
[Export] public float ExTurnSpeed = 2.0f;
public override void _Process(double delta)
{
// Translate: 基于自身朝向移动
// (0, 0, -1) 是"前方",因为 Z 轴正值朝屏幕外(朝你)
// 所以 -Z 才是"进入屏幕"的方向(即"前方")
if (Input.IsKeyPressed(Key.W))
{
Translate(new Vector3(0, 0, -ExWalkSpeed * (float)delta));
}
if (Input.IsKeyPressed(Key.S))
{
Translate(new Vector3(0, 0, ExWalkSpeed * (float)delta));
}
// 绕 Y 轴旋转(左右转向)
if (Input.IsKeyPressed(Key.A))
{
RotateY(ExTurnSpeed * (float)delta);
}
if (Input.IsKeyPressed(Key.D))
{
RotateY(-ExTurnSpeed * (float)delta);
}
}
}GDScript
extends Node3D
@export var walk_speed: float = 5.0
@export var turn_speed: float = 2.0
func _process(delta):
# Translate: 基于自身朝向移动
# (0, 0, -1) 是"前方",因为 Z 轴正值朝屏幕外(朝你)
# 所以 -Z 才是"进入屏幕"的方向(即"前方")
if Input.is_key_pressed(KEY_W):
translate(Vector3(0, 0, -walk_speed * delta))
if Input.is_key_pressed(KEY_S):
translate(Vector3(0, 0, walk_speed * delta))
# 绕 Y 轴旋转(左右转向)
if Input.is_key_pressed(KEY_A):
rotate_y(turn_speed * delta)
if Input.is_key_pressed(KEY_D):
rotate_y(-turn_speed * delta)朝向目标
C
using Godot;
public partial class LookAt3DDemo : Node3D
{
private Node3D _target;
public override void _Process(double delta)
{
if (_target != null)
{
// 看向目标(炮塔追踪、敌人面向玩家等)
LookAt(_target.GlobalPosition, Vector3.Up);
// 获取到目标的方向向量(单位向量)
Vector3 direction = GetDirectionTo(_target);
GD.Print($"方向: {direction}");
// 获取到目标的距离
float distance = GlobalPosition.DistanceTo(_target.GlobalPosition);
GD.Print($"距离: {distance}");
}
}
}GDScript
extends Node3D
var _target: Node3D
func _process(delta):
if _target:
# 看向目标(炮塔追踪、敌人面向玩家等)
look_at(_target.global_position, Vector3.UP)
# 获取到目标的方向向量(单位向量)
var direction = get_direction_to(_target)
print("方向: ", direction)
# 获取到目标的距离
var distance = global_position.distance_to(_target.global_position)
print("距离: ", distance)坐标转换
C
using Godot;
public partial class Coord3DDemo : Node3D
{
public override void _Ready()
{
// 局部坐标转全局坐标
// 比如"我前方 5 米"在全局坐标中是哪个位置
Vector3 localPos = new Vector3(0, 0, -5);
Vector3 worldPos = ToGlobal(localPos);
GD.Print($"局部 (0,0,-5) -> 全局 ({worldPos})");
// 全局坐标转局部坐标
// 比如世界坐标 (10, 0, 10) 相对于我在哪个方向
Vector3 targetWorld = new Vector3(10, 0, 10);
Vector3 relativePos = ToLocal(targetWorld);
GD.Print($"全局 ({targetWorld}) -> 相对我 ({relativePos})");
}
}GDScript
extends Node3D
func _ready():
# 局部坐标转全局坐标
# 比如"我前方 5 米"在全局坐标中是哪个位置
var local_pos = Vector3(0, 0, -5)
var world_pos = to_global(local_pos)
print("局部 (0,0,-5) -> 全局 ", world_pos)
# 全局坐标转局部坐标
# 比如世界坐标 (10, 0, 10) 相对于我在哪个方向
var target_world = Vector3(10, 0, 10)
var relative_pos = to_local(target_world)
print("全局 ", target_world, " -> 相对我 ", relative_pos)