游戏引擎:什么是场景图?

32

我已经开始阅读维基百科上的资料,但我仍然感觉不太理解场景图是如何工作以及它如何为游戏提供好处。

  • 在游戏引擎开发中,场景图是什么?
  • 为什么我想要为我的2D游戏引擎实现一个场景图?
  • 使用场景图是否作为具有线性实体管理器的经典实体系统的替代方案?

3
有一个游戏开发的 StackExchange 网站,你可能会想要去看一下。它专注于游戏开发相关话题。 - Zan Lynx
2
谁写了“试试谷歌...”的评论,如果你在说那句话之前读了我的问题,那就太好了!显然,你也无法回答它 :P - Loms
2
@Zan:嗯,这并不是仅针对游戏开发的。场景图可能即使你不制作游戏也是同样的工作方式,如果我错了请纠正我。此外,我希望在这里获得我的问题的答案比在GameDev StackExchange上更好。 - Loms
1
你的问题主题以“游戏引擎”开头,标记为“游戏开发”,因此似乎非常适合游戏开发。 耸肩 - Zan Lynx
5个回答

28
在游戏引擎开发中,场景图是什么?
它是一些代码,可以将游戏对象在游戏空间中主动排序,使得能够很容易地快速找到围绕着游戏空间某个点的物体。
这样,就很容易:
1. 快速找到相机视野内的物体(并只将它们发送给显卡,使渲染非常快);
2. 快速找到靠近玩家的物体(并只对它们进行碰撞检测);
等等。这是为了允许在空间中进行快速搜索。这被称为"空间划分"。它是关于分而治之的思想。
我为什么要为我的2D游戏引擎实现一个场景图呢?
这取决于游戏类型,更准确地说是取决于你的游戏空间结构。
例如,像《塞尔达传说》这样的游戏,如果可以快速地测试屏幕上所有物体之间的碰撞,则不需要使用这种技术。但是它很容易变得非常缓慢,所以通常至少设置一个场景图(或任何类型的空间划分),以至少知道围绕所有移动对象的内容,并只对那些物体进行碰撞检测。
因此,这取决于你的游戏类型。大多数时候,出于性能原因,需要使用场景图。但是,空间划分的实现完全取决于你的游戏空间结构。
使用场景图是否可以代替具有线性实体管理器的经典实体系统?
不可以。无论如何管理游戏实体对象的生命周期,空间划分/场景图只在于让您能够快速地在空间中搜索对象,不多也不少。大多数情况下,它将是一个对象,该对象将具有一些物体插槽,对应于游戏空间的不同部分,在这些插槽中,将是那些在这些部分的物体。它可以是平面的(像2或4个2D屏幕分割器),也可以是一棵树(如二叉树或四叉树,或任何其他类型的树)或任何其他限制执行操作数以获取一些空间相关信息的排序结构。

请注意:

在某些情况下,您甚至需要针对不同的目的使用不同的独立空间划分系统。通常,“场景图”用于渲染,因此优化方式取决于玩家的视角,并且其目的是允许快速收集要渲染并发送到图形卡的对象列表。它并不适合执行查找周围其他对象的对象,并且这使得它难以用于精确定位检测,例如当您使用物理引擎时。因此,为了帮助,您可能需要专门针对物理目的的不同空间分区系统。

举个例子,我想做一个“弹幕”游戏,其中有很多球需要玩家的飞船以非常精确的方式躲避。为了实现足够的渲染和碰撞检测性能,我需要知道:

  1. 子弹何时出现在屏幕空间中
  2. 子弹何时离开屏幕空间
  3. 玩家何时与子弹相撞
  4. 玩家何时与怪物相撞

所以我递归地将2D屏幕分成4个部分,这给了我一个四叉树。 四叉树在每个游戏tick上都会更新,因为一切都在不断移动,所以我必须跟踪四叉树中每个对象(飞船、子弹、怪物)的位置以知道哪个对象位于屏幕的哪个部分。

实现1很容易,只需将子弹输入系统即可。

要实现2,我在四叉树中保留了一个叶子列表(屏幕的平方部分),它们位于屏幕边框上。 这些叶子包含靠近边界的子弹的ID /指针,因此我只需要检查它们是否正在向外移动,就可以知道是否可以停止渲染它们并处理碰撞。(可能会更加复杂,但您会明白的。)

为了实现3和4,我需要检索离玩家飞船近的对象。所以我首先获取玩家飞船所在的叶子节点,并获取其中所有的对象。这样我就只需要测试与围绕其周围的对象发生碰撞的玩家飞船,而不是所有的对象。(它确实有些复杂,但你理解了意思就好。)
这样,即使有成千上万的子弹不断移动,我也可以确保我的游戏会平稳运行。
在其他类型的空间结构中,需要其他类型的空间划分。通常,卡丁车/汽车游戏将具有“隧道”场景图,因为从视觉上来看,玩家只会看到沿路的事物,所以你只需检查他在路上的位置,就可以检索出“隧道”周围所有可见的物体。

18
什么是场景图? 场景图 包含了特定场景中所有的几何形状,它们有助于表示物体相对于其他物体的平移、旋转和缩放(以及其他仿射变换)。
例如,考虑一个坦克(带履带和炮管的那种)。您的场景可能有多个坦克,但每个坦克的方向和位置不同,每个坦克的炮塔转向不同的方位角并且具有不同的炮口仰角。与其确定每个坦克炮管的确切位置,您可以在遍历场景图时累加仿射变换来正确地定位它。这使得这些计算变得更加容易。 2D场景图: 对于2D使用场景图可能很有用,如果您的内容足够复杂,并且您的对象有许多非刚性固定在较大主体上的子组件。否则,就像其他人提到的那样,这可能过度复杂化了。在2D情况下,仿射变换的复杂度要比3D情况下少得多。 线性实体管理器:我不是很清楚你所说的线性实体管理器具体指什么,但如果你只是想跟踪场景中物体的位置,那么如果场景中各个对象或子对象之间存在高度空间依赖关系,则场景图可以使事情变得更容易。

3
一个场景图是一种组织环境中所有对象的方式。通常会注意将数据组织成高效渲染的形式。这个图,或者说树,可以显示子对象的所有权。例如,在最高层可能有一个城市对象,在它下面会有许多建筑物对象,在这些对象下面可能会有墙壁、家具等。
但是,对于大多数情况,这些只用于3D场景。我建议不要在2D场景中使用太复杂的东西。

你正在创建什么类型的2D场景? - Nick Banks
我正在创建一个引擎,应该支持尽可能多种不同的场景,从相当小的到巨大的都有。 - Loms

3

在网上,有很多关于场景图职责的不同哲学观。人们倾向于将许多不同的内容放入其中,如几何形状、摄像机、光源、游戏触发器等。

总体而言,我会将场景图描述为一个场景的描述,由包含场景中实体的单个或多个数据结构组成。这些数据结构可以是任何类型(数组、树、组合模式等),并且可以描述实体的任何属性或实体之间的任何关系。

这些实体可以是任何东西,从实心可绘制对象到碰撞网格、摄像机和光源等。迄今为止唯一真正的限制是人们建议将游戏特定组件(如游戏触发器)排除在外,以避免后期的依赖问题。这些东西必须被抽象化,比如说“逻辑实体”、“隐形实体”或者只是“实体”。

以下是场景图中常见用途和数据结构。

父/子关系

您可以在游戏或引擎中使用场景图来描述任何具有位置的物体(如实体对象、相机或其他物体)之间的父子关系。这种关系意味着任何子对象的位置、缩放和方向都是相对于其父对象的。这将使您能够让相机跟随玩家或让光源跟随手电筒对象。它还将使您能够创建太阳系等事物,在其中可以描述行星相对于太阳的位置以及卫星相对于它们的行星的位置,如果您正在制作这样的事物。
此外,您可以将某些系统特定的内容存储在场景图中。例如,作为物理引擎的一部分,您可能已经为实体对象定义了简单的碰撞网格,这些对象可能具有过于复杂的几何形状以进行碰撞测试。您可以将这些碰撞网格(我确定它们有另一个名称,但我忘记了:P)放入您的场景图中,并让它们跟随所模拟的对象。
空间划分
另一种可能的场景图数据结构是某种形式的空间划分,如其他答案所述。这将允许您在场景中执行快速查询,例如裁剪不在视锥体内的任何对象或有效地过滤需要进行碰撞检查的对象。您还可以允许客户端代码(如果您正在编写引擎)执行自定义查询以用于任何目的。这样客户端代码就不必维护自己的空间划分结构。
我希望我为您和其他读者提供了一些关于如何使用场景图以及您可以在其中放置什么的想法。我确定有很多其他使用场景图的方式,但这些是我想到的事情。

2
实际上,在电子游戏中,场景对象很少组织成一个“走”树状图的结构进行渲染。图形系统通常期望有一个大数组来渲染所有东西,并且对这个大数组进行线性遍历。
需要几何父子关系的游戏(例如那些人手持枪支或坦克带有炮塔的游戏)在图形系统之外根据需要定义和执行这些关系。这些关系往往只有一层,因此几乎从不需要任意深度的树形结构。

其实并不是这样的。任何引擎都有一个适当的场景图,存储实体之间的关系。大多数引擎(无论是哪种程度的)也在空间分区中拥有实体。遍历八叉树仍然比绘制比实际可见对象多100%的对象要快。 - RecursiveExceptionException
只有在遍历树的成本低于实际渲染所有内容的成本时,才会出现这种情况,如果你的计算机受限于 CPU,那么是这样的。如果你的计算机受限于 GPU,那么是另外一回事了。 - Ray Garner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接