Godot 4.3已于2024年8月15日发布,此后的文章(直到我又说换版本了为止)以4.3版本为基准
为了便于后续的学习,我们先来新建一个项目,叫它FPS或者什么都可以。
Godot项目在创建时不区分2D和3D,在游戏中同时存在2D场景和3D场景也不是什么稀奇事。渲染器默认就可以。
项目不区分2D和3D,但是场景需要区分。为了构建一个3D游戏,我们至少需要一个3D场景。新建场景,选择3D Scene。
打开3D场景后,视口默认切换到3D模式。
3D场景默认情况下根节点是Node3D,它和2D场景中的Node2D是对等的。
认识Godot的3D坐标系
3D坐标系毫无疑问有三个轴。按照惯例,Godot的3D坐标系的坐标轴也用x、y、z表示。一般来说这和数学课上用的字母一样。
虽然一般来说各种软件中的2D坐标系都是横轴为x,纵轴为y,但是它们在3D坐标系上有很大分歧。
Godot的3D坐标系使用的是y轴指向上方的右手坐标系。
换句话说,伸出右手的大拇指、食指、中指,食指向上,令三个手指相互垂直。食指指的就是y轴正方向,中指是z轴正方向,大拇指指向x轴正方向。
Godot的文档中引用了一张图片,展示了常用3D软件的3D坐标系情况:
可以看到Unreal实在是独树一帜
在3D空间中导航
为了便于在开发过程中观察3D场景,我们要学习如何在3D场景中导航。
鼠标位于3D视口中时,按住右键后即可像玩FPS游戏那样移动鼠标观察场景。同时,你也可以用WASD来前后左右移动(以当前视线方向为前方)。E和R分别是上升和下降(沿Y轴方向移动)。鼠标滚轮可以将视角拉近拉远。
按住鼠标中键,可以让视角环绕画面中心旋转——注意这和2D视口中不一样。2D视口中鼠标中键是用于平移(pan)整个画面,3D视口中的平移需要按住shift再按鼠标中键移动。
右上角的这个玩意儿是另一种用来观察场景的工具。在它身上按住鼠标左键并移动就类似于按住鼠标中键的操作。点击上面的圆球可以让视角快速调整到对应坐标轴的方向:
可以看到除了视角变了之外,左上角也发生了变化。原本的Perspective(透视)变成了Right Orthogonal(右侧正交)。
透视简单来说就是“近大远小”的效果,看起来“更有立体感” :
而正交的视角则是这样,该平行的边还是平行:
在只想要观察某一个侧面的状况时,正交的画面更容易观察。
最后,工具栏的View菜单下可以选择各种多视口视图,可以同时观察场景的不同角度:
创建简单的3D对象
在开发游戏时,有一些简单的3D对象可供实验和关卡打样是很方便的。
我们在2D游戏的开发过程中,我们想使用一些临时素材来打样的时候都是直接放一个纹理(texture)——或者直接说“图片”——到场景中。毕竟图片本身就是2D的,直接放在2D场景中很自然。
在3D场景中,我们自然要放一些3D模型到场景中。2D场景中我们把图片放到场景中会自动创建一个Sprite节点,然后图片会作为它的texture属性;又或者我们直接选择新建纹理,用Placeholder纹理或者其它选项来作为Sprite的内容。那么3D场景中对应的是什么呢?
MeshInstance3D(网格实例3D)节点用于在场景中渲染网格。啥是网格呢?你可以简单地认为它就是3D模型的同义词。为啥叫网格呢。因为3D模型是有很多顶点连成边、边又连成面形成的,这些数据最终会被计算机渲染成看起来貌似很有立体感的东西:
一个简单的3D模型,其中可以看到若干顶点(黑点)
向场景中加入一个MeshInstance3D节点。MeshInstance3D加入场景后和Sprite类似,不会显示任何内容。我们需要给它的Mesh属性赋值。类似地,我们可以在Mesh属性的下拉菜单中看到一系列内置的选项:
如你所见,除了PlaneMesh之外还有很多种选项可以选。其实不用我介绍,看一眼左边的图标大概也能猜到各自对应的是什么。你可以自行探索。
实际上你也可以看到一个Placeholder。这种Mesh会用位置和长宽高定义一个只显示边框的立方体:
这里我们也可以选择PlaneMesh(平面)来做一个地面:
类似于Sprite的Texture属性,这里填入值之后可以点击它来编辑它的各种属性。这里可以通过Size来调整其大小。平面没有高度(但凡有一点高度的那就是一个立方体了),所以这里只有两个分量。
操作3D对象
接下来我们可以利用这些基本的几何体做一个简单的关卡。你可以随心所欲地摆弄这些东西,当然我这里就简单用BoxMesh(立方体)来讲解一下。
这里新建一个MeshInstance节点,给它一个BoxMesh。默认情况下,这个立方体是边长为1的正方体。现在我希望通过调整它的尺寸,来做一面墙。
在调整尺寸这个问题上,我们这里有两种操作方式。BoxMesh作为一种在引擎内构造的网格资源,可以直接调整其参数来调整大小。
另外,3D节点和各种2D节点一样,有一系列transform属性。它的scale属性也是用于对3D对象进行缩放。自然,3D的scale有三个分量,是一个Vector3D类型的属性,分别令3D对象沿对应的轴进行缩放。
区别在于,直接调整Mesh资源自身的属性不会影响MeshInstance节点的transform。反之亦然。不过调整两者任意的大小都会在视觉上发生变化。另一方面提醒一下。我们在前面已经了解到,资源是共享的。
例如在尝试做一堵简单的墙的时候,你做完一面之后,可能会想要直接复制(duplicate)这个MeshInstance。复制发生时,节点引用的资源不会产生新的副本(copy),它们会引用同一个资源——这本身就是资源的特点。因此此时如果你再去任意一个MeshInstance节点上修改那个Mesh的话,所有引用同一个Mesh的节点都会发生变化。你不妨尝试一下。
因此,具体如何调整,还是那句老话,需要根据具体需要来。
3D视图和2D视图有类似的工具栏可以操作场景中的各种3D对象或者说节点。默认情况激活的是选择工具(图标为鼠标,快捷键为Q)。点击任意3D节点会显示这个看起来乱七八糟的红蓝绿的东西:
这些3D软件中很常见的UI元素一般称为gizmo,它们用来对3D节点进行移动、旋转、缩放等操作。选择模式下实际上是把几种工具同时显示了出来。我们可以进入对应模式单独操作,也可以在选择模式下执行各种不同的操作。
按下W激活移动工具,除了比2D多一个轴以外没有什么区别。鼠标在某个轴上按住并拖动可以让节点沿某个轴移动。和2D不一样的是这里还有三个方框一样的东西。按住它们可以把移动限制在对应平面上而不是某个轴上。
按下E激活旋转工具。没啥说的。
R是缩放工具。和移动工具类似,它也支持在某个平面上操作。
最后,按下Q可以同时激活这些工具,就得到了一开始的效果。
CSG——关卡打样的好帮手
CSG它不是CS Go的意思。它是Constructive Solid Geometry(我其实不太清楚这个constructive用在这里是否恰当,但是总是大概就是“可以构造的实心几何体”)的缩写。和内置的各种简单几何体Mesh相比,可以利用CSG构造出更复杂的网格。
例如在场景中加入一个CSGBox。咋一看和一般的BoxMesh没啥区别。不过CSG提供了几个锚点,可以直接调整其尺寸。
你说好吧,可能方便一点,这也没啥神奇的。现在加入另一个圆柱体,并在监视面板或者场景中调整其尺寸。当然默认的圆柱体只有8个棱,看起来不圆,可以在检视面板调整它的slides。最后把它大概调整成这样,然后插入到CSGBox中:
好吧,到现在为止还是没什么神奇的。接下来,我们把圆柱体的CSGShape下的Operation(操作)属性调整为Subtraction(减去)——依然没有什么神奇的。
接下来才是见证奇迹的时刻。在场景中加入一个CSGCombiner节点,然后把刚才这两个CSG作为它的子节点。
可以看到,圆柱体看不见了(不过节点本身依然在场景中),并且立方体被圆柱体打了一个洞:
这就是CSG的有趣之处。它可以像诸多3D软件那样对网格进行布尔操作,让不同的几何体相互影响来构造复杂的几何体。
CSG对其它的CSG产生什么影响就依赖于刚才的Operation属性。其取值有三,默认为Union,按照集合论的术语来说就是求并,按照布尔代数的术语来说就是与。总之就是把两个CSG合并成一个物体。Subtract已经见过,就是求差集,即从一个CSG上消除掉和另一个CSG重合的部分。Intersection是求交集,也就是只保留两个CSG重合的部分,消除其它的部分:
Combiner不止可以组合两个CSG,你可以按照这样的操作构造各种不同的、更为复杂的几何体来搭建你的场景。
如果你想搭建的几何体的基本形状不是那么基本,也可以选择用CSGPolygon。Polygon是多边形的意思,CSGPolygon会利用多边形来构造网格,其实在很多3D软件中这种建模方式也很常见。
CSGPolygon提供的锚点用于定义一个多边形,且这些锚点都在一个平面上。默认只有四个顶点,如果需要添加更多顶点可以在检视面板中的Polygon属性中编辑:
可以看到,默认情况下会用这个多边形朝一个方向构造一个一定深度(厚度)的几何体。“面动成体”嘛。
这种行为是由CSGPolygon的Mode属性控制的,默认为Depth(深度),深度默认为1米:
这个操作说白了就是3D软件里的“挤出”(extrude)操作。
Mode有三个选项。Spin(旋转)就是让这个多边形旋转起来以形成一个几何体:
剩下的Path(路径)就是让多边形沿一条曲线移动形成几何体。此模式需要场景中有一个Path3D节点。Path3D节点需要引用一个曲线资源。曲线也是自己通过控制点来定义。提示一下,如果发现曲线“太直了”的话,选中视口左上方那排按钮第二个,然后按住shift去调整控制点就可以出现贝塞尔曲线那种把手了。
总之,利用CSG和一些基本的MeshInstance,我可以(也不是特别)轻松地搭建这样一个场景:
至此你的场景可能已经搭建好了。你可能满心激动地准备启动游戏看一看。可是启动游戏之后什么都没有。
再次开拍
和2D场景不一样,3D场景必须要一个摄像机节点才能在游戏运行时渲染画面。
我们之前已经了解到2D场景中可以加入一个Camera2D节点用来控制2D游戏的画面,类似地,我们有一个Camera3D节点。
加入Camera3D节点后选中它,在3D视图中可以看到一个Preview(预览)按钮:
勾选后编辑器的3D视口中可以预览透过此摄像机看到的画面。
然而,启动游戏我们会发现画面中虽然有我们的场景,但是是黑乎乎的。
亮起来
在3D场景中,如果我们没有加入WorldEnvironment(世界环境)节点或者DirectionalLight3D(方向光)节点,编辑器会自行启用预览环境,这样我们就不会在编辑器中看到黑乎乎的场景。在工具栏可以看到,这个像太阳和地球的图标显示为启用状态:
这两个图标分别就是控制是否启用3D预览太阳光和预览环境。点击可以切换启用状态。关闭两者后我们在编辑器中看到的就是和刚才在游戏运行时看到的那样黑乎乎的。
另外点击地球旁边的三个点可以对预览太阳光和环境进行一些设定。当然,无论怎么设定,它们都不会影响到我们的实际游戏,毕竟它们是预览用的。
现在我们可以先关闭预览太阳光和预览环境,然后自行添加相应节点来构造游戏场景的环境。当然,“关闭”不是必须的操作,只是可以更好地对比场景在操作前后的样子。
基本的光照通过Light3D派生出来的各节点实现。环境中的太阳光一般通过DirectionalLight3D来实现——它的图标就是一个太阳。
Light3D本身也是Node3D的子类,它自然有各种transform属性。不过,方向光主要用来模拟一种从很远很远的照射过来的、各光线几乎平行的光源。就像太阳在不同的位置时地球上某点的光照情况也各不一样,调整其rotation属性可以控制光照的方向。不过移动它的位置并不会对光照有什么具体影响。
另外要注意,可以看到我们手动加入DirectionalLight3D节点之后,场景中的预览太阳光按钮就直接禁用了。
现在,场景中有光了,部分场景节点已经被照亮,没照亮的部分也有了明暗对比。但是我们的场景中没有背景,也就是说没有节点挡住的远处还是一片黑(灰):
WorldEnvironment节点用于控制整个场景的各种光照、背景、后处理属性。加入此节点后,预览环境和太阳光一样自动禁用。为了达到预览环境的简单效果,我们选中这个节点,然后在检视面板原地新建一个环境:
其背景(Background)属性有多种模式,默认情况下使用的是清空为默认颜色(Clear Color),也就是这个灰蒙蒙的颜色。如果你只希望要一个单色背景的话,可以选择Custom Color然后选择任意颜色。这里我们选择Sky。
其背景(Background)属性有多种模式,默认情况下使用的是清空为默认颜色(Clear Color),也就是这个灰蒙蒙的颜色。如果你只希望要一个单色背景的话,可以选择Custom Color然后选择任意颜色。这里我们选择Sky。
选择Sky后,下方也会多出一栏Sky相关的属性。类似地操作新建Sky,远处看起来是什么样子的主要靠天空的材质控制——而材质也支持多种材质。当然最简单的就是选择ProceduralSkyMaterial,默认的预览天空大致就是用它实现的。你可以点击它进一步调整相关属性来控制天空的颜色之类的。
现在启动游戏,应该就能看到一个被照亮的场景了。
总之,我们现在有了一个3D场景,可以制作3D游戏了!