我们如何解决2D游戏中大视频存储需求?


40

我们如何解决2D游戏中大视频存储需求?


我们正在开发使用Allegro C / C ++的2D游戏(Factorio),并且随着游戏内容的增加,我们面临视频存储需求增加的问题。

目前,我们收集了有关将首先使用的图像的所有信息,尽可能地裁剪所有这些图像,并尽可能紧密地将它们组织成大图册。这些地图集存储在视频内存中,视频内存的大小取决于系统限制。目前,它通常是2张图像,最高可达8192x8192,因此它们需要256Mb至512Mb的视频内存。

这个系统对我们来说非常不错,因为通过一些自定义优化以及拆分渲染和更新线程,我们能够以60 fps的速度在屏幕上绘制成千上万的图像。我们在屏幕上有许多对象,因此允许大缩放是一项关键要求。由于我们要添加更多内容,因此视频内存要求会出现一些问题,因此该系统无法容纳。

我们想要尝试的一件事是拥有一张包含最常见图像的地图集,而第二幅则作为缓存。图像将根据需要从内存位图移到那里。这种方法有两个问题:

  1. 从内存位图到视频位图的绘制速度非常缓慢。
  2. 在Allegro中,除了主线程之外,无法使用视频位图,因此实际上是不可用的。

这是我们还有的一些其他要求:

  • 游戏必须是确定性的,因此性能问题/加载时间永远不能改变游戏状态。
  • 游戏是实时的,并且很快也会成为多人游戏。我们需要不惜一切代价避免甚至最小的结结巴。
  • 游戏的大部分是一个连续的开放世界。

该测试包括批量绘制1万个精灵,大小从1x1到300x300,每种配置几次。我在Nvidia Geforce GTX 760上进行了测试。

  • 当源位图在各个位图之间没有变化时(图集变体),视频位图到视频位图的绘制每个子图花费0.1us。大小没关系
  • 视频位图到视频位图图形,而源位图在图形之间切换(非图集变体),每个子图形花费0.56us;大小也没关系。
  • 内存位图到视频位图的绘制确实令人怀疑。从1x1到200x200的大小每个位图要花0.3us,所以速度并不是那么慢。对于较大的尺寸,时间开始急剧增加,201x201的时间为9us,291x291的时间为3116us。

使用Atlas可将性能提高5倍以上。如果我有10ms的渲染时间,则使用Atlas将每帧限制为100000个精灵,如果没有它,则限制为20000个精灵。这将是有问题的。

我还试图找到一种方法来测试阴影的位图压缩和1bpp位图格式,但是我无法找到在Allegro中执行此操作的方法。


1
您是游戏的忠实拥护者,我支持Indiegogo广告系列。我每隔几个月就狂欢一次。到目前为止工作很好!我删除了与该站点无关的“使用哪种技术”问题。剩下的问题仍然很广泛,如果您有更具体的说明,应尝试缩小范围。
MichaelHouse

感谢您的支持。那么哪里问使用哪种技术呢?我不是在寻找有关特定引擎推荐的答案,但是我无法找到2d引擎的深入比较,无法逐一手动检查它们,包括性能和可用性测试会花费很多时间。
Marwin 2014年

此页面的底部查看一些地方,例如“使用哪种技术”之类的问题。您有一个完全有效和合理的问题,这不是我们在此站点上处理的问题的类型。即使您没有在寻找特定的引擎,这实际上也是回答“是否存在X技术的唯一问题”的唯一方法。有人可能只是回答“是”,而没有给出针对特定建议的建议,但这不会很有帮助。祝你好运!
MichaelHouse

2
您是否正在压缩纹理?
GuyRT

3
@Marwin,压缩纹理的性能可能比未压缩纹理好得多,因为它们减少了所需的内存带宽(在带宽要低得多的移动平台上尤其如此)。仅压缩纹理即可节省大量内存。实际上,唯一的缺点是不可避免地会引入人工制品。
GuyRT 2014年

Answers:


17

我们的RTS(KaM Remake)也有类似情况。所有单位和房屋都是精灵。我们为单位,房屋和地形提供了18 000个精灵,另外为团队颜色提供了约6000个(用作蒙版)。经过长时间拉伸,我们在字体中还使用了约3万个字符。

因此,针对您使用的RGBA32地图集进行了一些优化:

  • 首先将子画面池分成许多较小的地图集,并按其他答案所述按需使用它们。这还允许针对每个地图集分别使用不同的优化技术。我怀疑您会少浪费一些RAM,因为打包成如此大的纹理时,通常在底部有未使用的区域;

  • 尝试使用调色板纹理。如果使用着色器,则可以在着色器代码中“应用”调色板。

  • 您可能会考虑添加使用RGB5_A1而不是RGBA8的选项(例如,如果棋盘阴影适​​合您的游戏)。尽可能避免使用8位Alpha,并使用RGB5_A1或精度较低的等效格式(如RGBA4),它们占用一半的空间;

  • 确保将精灵紧密地包装到地图集中(请参阅Bin Packing算法),在必要时旋转精灵,并查看是否可以重叠菱形精灵的透明角;

  • 您可以尝试使用硬件压缩格式(DXT,S3TC等)-它们可以大大减少RAM的使用,但可以检查压缩伪像-在某些图像上,差异可能并不明显(您可以如第一个要点所述选择性地使用它),但在某些方面-非常明显。不同的压缩格式会导致不同的失真,因此您可能会选择最适合您的艺术风格的失真。

  • 研究将大精灵(当然不是手动,而是在纹理地图集打包程序中)拆分为静态背景精灵和用于动画零件的较小精灵。


2
使用DXT +1,这是一件非常好的事情。强大的压缩功能,GPU直接使用,因此开销最小。

1
我同意dxt。您也可以查询DXT7支持(DX11 +硬件),它的大小与DXT1相同,但质量更高。但是,您可能需要使纹理翻倍(一个DXT7和一个DXT1),或者在加载期间进行压缩/解压缩。
Programmdude

5

首先,您需要使用更多,更小的纹理图集。您拥有的纹理越少,存储管理就越困难和严格。我建议地图集的大小为1024,在这种情况下,您将拥有128个纹理而不是2,或者在2048中将拥有32个纹理,可以根据需要加载和卸载。

大多数游戏通过具有级别边界来进行资源管理,而显示加载屏幕时,将卸载下一级不再需要的所有资源,并加载需要的资源。

另一种选择是按需加载,如果不需要级别边界或什至单个级别太大而无法容纳到内存中,则按需加载是必需的。在这种情况下,游戏将尝试预测玩家将来会看到什么并将其加载到后台。(例如:当前距离播放器2个屏幕的东西。)同时,不再使用了较长时间的东西也将被卸载。

但是,有一个问题,当游戏无法预见的意外事件发生时会发生什么?

  • 惊慌并显示一个加载屏幕,直到所有必需的东西都加载完毕。这可能会破坏体验。
  • 对于预加载的所有内容都具有低分辨率精灵,继续游戏并在高分辨率精灵完成加载后立即替换它们。对玩家来说,这看起来很便宜。
  • 使其影响游戏玩法,并在必要时延迟事件。例如,在加载图形之前不要生成该敌人。在加载该战利品的所有图形之前,请勿打开宝藏箱,等等。

我添加了一些我省略的要求。无法加载屏幕或进行任何类型的加载。一切都必须在后台完成,或者在单个刻​​度之间(每个刻度小于15毫秒)完成,而渲染准备和游戏更新通常已经使用了大部分时间。无论如何,分割成较小的部分可能会增加切换的灵活性,这肯定会更快。问题是渲染时会严重影响性能,因为在绘制时切换源位图会减慢渲染速度。我必须进行精确的测量才能说出多少。
Marwin 2014年

@Marwin对性能有影响,是的,但是由于您正在处理2D,因此距离它仍然很遥远。如果渲染当前每帧花费1毫秒,并且通过使用较小的纹理突然花费2毫秒,那么它的速度仍然足以达到稳定的60 FPS。(16ms)
API-Beast

@Marwin Multiplayer是棘手的业务,一直都是,永远都是。您很可能不得不在那里做出让步。您会发呆,仅仅是因为您必须通过Internet传输数据,数据包会丢失,ping可能突然激增等。发呆是不可避免的,因此,让您更重要的是使网络模型本身能够抵抗发呆。知道何时等待以及如何等待其他玩家。
API-Beast

您好,在多人游戏中口吃几乎是可以避免的,我们现在正在该区域上工作,我相信我们有一个好的计划。我什至可以张贴并回答我自己的问题,以描述我们稍后详细研究的内容:)可能令人惊讶,但是渲染时间实际上是一个问题。我们做了很多优化,以加快渲染速度。现在,主要渲染是在单独的线程和其他小的调整中进行的。别忘了,在最大缩放比例下,播放器可以轻松同时看到成千上万的精灵。我们甚至希望以后允许更高的缩放级别。
Marwin

@Marwin Hm,如果您使用适当的批处理功能,则对于PC或现代笔记本电脑来说,10,000个对象通常应该没有问题,您是否已绘制了渲染代码?
API-Beast

2

哇,我想是从3D模型生成的大量动画精灵?

您真的不应该在原始2D模式下制作这款游戏​​。有了固定的视角,就会发生一件有趣的事情,您可以将预先渲染的精灵和背景与实时渲染的3D模型无缝地混合在一起,而这些3D模型在某些游戏中已经大量使用。如果您想要如此精美的动画,那似乎是最自然的方式。获取一个3D引擎,对其进行配置以使用等轴测透视图,然后将继续使用精灵的对象渲染为带有图像的简单平面。您可以将纹理压缩与3D引擎一起使用,这仅是向前迈出的一大步。

我认为加载和卸载对您没有多大帮助,因为您可以同时在屏幕上显示几乎所有内容。


2

首先,找到最有效的纹理格式,同时仍然对游戏的视觉效果感到满意,无论是RGBA4444还是DXT压缩等。如果您对DXT alpha压缩图像中生成的伪像不满意,是否可行?使图像不透明,使用DXT1压缩的颜色结合alpha的4或8位灰度蒙版纹理?我想您会在RGBA8888上使用GUI。

我主张使用您决定的任何格式将其分解为较小的纹理。确定始终在屏幕上并因此始终加载的项目,这可能是地形和GUI地图集。然后,我将尽可能多地分解通常一起渲染的其余项目。我不认为即使在PC上进行多达50-100次抽奖,您也不会损失太多性能,但是如果我错了,请纠正我。

下一步将是生成这些纹理的Mipmap版本,如上文所述。我不会将它们存储在单个文件中,而是分开存储。因此,您最终将获得每个文件的1024x1024、512x512、256x256等版本,而我将执行此操作,直到达到我想显示的最低详细级别为止。

现在,您已经拥有了单独的纹理,您可以构建一个详细程度(LOD)系统,该系统为当前缩放级别加载纹理,并在未使用时卸载纹理。如果要渲染的项目不在屏幕上或当前缩放级别不需要,则不使用纹理。尝试将纹理加载到与更新/渲染线程分开的线程中的视频RAM中。您可以显示最低的LOD纹理,直到加载所需的纹理。有时这可能会导致低细节/高细节纹理之间的可见切换,但是我想这只有在您在地图上移动时执行极快的缩小和放大时才会发生。通过尝试预加载您认为该人将在当前内存限制内尽可能多地移动或缩放并加载的位置,可以使系统智能化。

我会测试一下是否有帮助。我想获得极端的缩放级别,您将不可避免地需要一个LOD系统。


1

我相信最好的方法是将纹理分割成许多文件并按需加载。可能是您的问题是您正在尝试加载较大的纹理,而这些纹理是完整3D场景所需的,而您正在为此使用Allegro。

对于要应用的大缩小,必须使用mipmap。Mipmap是纹理的较低分辨率版本,当对象离相机足够远时使用。这意味着您可以将8192x8192保存为4096x4096,然后另存为2048x2048,依此类推,如果您在屏幕上看到的精灵越小,则切换到较低的分辨率。您既可以将它们保存为单独的纹理,也可以在加载时调整它们的大小(但是在运行时生成Mipmap会增加游戏的加载时间)。

适当的管理系统会按需加载所需文件,并在没人使用文件时以及其他情况下释放资源。资源管理是游戏开发中的重要主题,您正在将管理简化为映射到单个纹理的简单坐标,这几乎完全没有管理。


1
拆分为文件,是指将文件存储在HDD上吗?我以为我可以将所有图片存储在RAM上供初学者使用,甚至目前从内存位图复制到视频位图的速度都太慢,因此从HDD加载肯定会更慢。有小贴士对我没有帮助,因为我仍然会在vram中拥有最大的分辨率。
Marwin 2014年

是的,您不必加载所有内容,而只需加载您使用的内容。每当您想要更改VRAM中加载的纹理上的像素时,系统都必须将整个纹理移到RAM中,只是为了修改单个像素,然后将其移回到VRAM中。如果所有内容都在同一个纹理中,则需要将256 MB移至RAM,然后再次移至VRAM,这将锁定整个计算机。将其分离在不同的文件和纹理中是正确的方法。
Pablo Ariel 2014年

修改纹理以触发复制到内存并返回到ram的操作仅适用于永久位图,高速缓存可能不会设置为永久位图,唯一的缺点是在丢失/找到显示时需要刷新它。但是在快板中,即使将640X480图片从vram复制到内存位图(保存游戏预览)也需要相当长的时间。
Marwin 2014年

1
我需要将所有内容都放在一个大纹理中以优化绘图本身,如果没有它,在单个子画面之间切换上下文的效果至少会在Allegro中降低渲染速度。不要误会我的意思,但是您在这里很明显是您的队长,因为您含糊地建议我做这个问题中我要做的事情。
Marwin

1
将这些mip映射的纹理保存在不同的文件中将迫使我在播放器放大时重新加载所有地图集。由于引擎最多只具有几毫秒的单位,因此我看不到如何做到这一点。
Marwin

0

我建议创建更多的地图集文件,这些文件可以使用zlib压缩并从每个地图集的压缩流中流出,并且通过拥有更多的地图集文件和更小尺寸的文件,您可以限制视频内存中活动图像数据的数量。此外,请实现三重缓冲机制,以便您更快地准备每个并条机,并有机会更快地完成装帧,从而使装配件不会出现在屏幕上。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.