> 3D 的门槛一半在数学,一半在心理。本篇只取必要集合:坐标系与朝向、节点家族、模型导入、光照相机。目标是看完不慌,能在 3D 视口里搭出一个能探索的小房间。
一、坐标系:先立规矩
- 右手坐标系,Y 向上。X 右、Y 上、Z 朝屏幕外——与 Unity(左手)不同,与 Blender 相同。
- 位置是
Vector3,旋转是Vector3欧拉角(度)或Quaternion(四元数)。代码里动画旋转优先四元数,欧拉角万向锁是 3D 第一坑。 - 节点的
transform是Transform3D(基向量 + 原点),global_position与position的区别从 2D 一脉相承:局部 vs 世界。 - 前方向约定:Godot 里 -Z 是前方(相机看向 -Z),模型导入后「脸朝 Z 正方向」的八成要转 180 度。
二、3D 节点家族:把 2D 的心智映射过来
对照表比解释省力:
| 2D | 3D | 说明 |
|---|---|---|
| CharacterBody2D | CharacterBody3D | 手动控速 + move_and_slide(),玩家/NPC 首选 |
| RigidBody2D | RigidBody3D | 物理引擎接管,扔、砸、滚 |
| StaticBody2D | StaticBody3D | 静态碰撞,墙、地 |
| Area2D | Area3D | 触发器、感知区域 |
| Sprite2D | MeshInstance3D + Mesh | 外观载体换成网格 |
| Camera2D | Camera3D | 3D 里没有「自动跟随」,必须自己写或挂脚本 |
4.6 还有个实用小功能:Mesh 菜单一键把 box/sphere/cylinder/capsule 网格转成匹配的 CollisionShape3D——「给模型配碰撞」这个 3D 日常动作从此不用再手动对齐。
三、导入管线:glTF 是亲儿子
- 首选 glTF 2.0(.gltf/.glb),Godot 官方标准格式,PBR 材质、骨骼、动画全保留;
.blend可直接导入(需本机装 Blender);FBX 走 ufbx 导入器(4.3 起内置)。 - 导入后模型是一个场景,可「继承场景」实例化后覆写属性;材质在导入面板或 MeshInstance 的 Surface Override 里调。
- 4.5 修了骨架层级里非关节节点的处理,并引入「Naming Version」——老资源保持旧行为、新资源用新规则,迁移手册有细节。
- 网格简化(LOD)在 4.6 拿到组件剪除:多部件网格生成 LOD 时更好保留原形。
四、光照三件套与阴影心智
3D 光源家族:DirectionalLight3D(太阳,影响全场景)、OmniLight3D(点光,向四面八方)、SpotLight3D(聚光)、以及 4.7 新成员 AreaLight3D——矩形面光源,电视屏幕的柔光、霓虹广告牌、磨砂窗透光,以前要「自发光材质 + GI」模拟,现在是一个节点直接发光,阴影与反射都更柔更真。
新房间标准开局:
WorldEnvironment:环境设置容器(天空、雾、环境光、色调映射全在这);DirectionalLight3D:主光,开阴影(Shadow → Enabled);Camera3D:加个Camera3D子节点到玩家上,初学者最易忘的第三件套就是它。
- SDFGI:有向距离场 GI,大世界实时 GI,Forward+ 专属,编辑器一键开;
- VoxelGI:体素 GI,小场景更准,可实时刷新动态光源;
- LightmapGI:烘焙光照图,性能最好,静态光专用;4.8 dev 还在给方向光照图加镜面高光;
- SSAO/SSIL:屏幕空间环境光遮蔽/间接光,作为上面任一方案的「增味剂」。
五、给房间装上「可探索」:十分钟 Demo 清单
- 地面:
CSGBox3D(Use Collision勾上)——CSG 是 3D 里的原型利器,布尔运算直接在编辑器里挖门凿窗,正式管线再换导入模型;4.7 给 CSG 加了 Autosmooth(按平滑角自动分光滑面/硬面),原型也好看。 - 玩家:
CharacterBody3D+CollisionShape3D(胶囊体)+Camera3D(弹簧臂式跟随可手写 20 行,或用社区 CameraRig)。 - 移动脚本与 2D 几乎同构,只是向量升到三维:
extends CharacterBody3D
const SPEED := 5.0
const JUMP := 4.5
func _physics_process(delta: float) -> void:
if not is_on_floor():
velocity += get_gravity() * delta
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = JUMP
var input_2d := Input.get_vector("move_left", "move_right", "move_up", "move_down")
var dir := (transform.basis * Vector3(input_2d.x, 0, input_2d.y)).normalized()
if dir:
velocity.x = dir.x * SPEED
velocity.z = dir.z * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide()
看清楚了:move_and_slide() 一个字没变——2D 与 3D 在 Godot 里是同一套 API 的两次实例化。这就是「同构」的含义:学会一个,等于学会两个。
下一篇,第七级台阶:渲染与着色器——三大渲染方法怎么选、4.7 的 HDR 输出与 AreaLight3D 实战、着色器语言第一个程序,3D 视觉的进价与回报全在本篇。
*本篇配图:三轴坐标与光照场景。*