多个小型 spritesheet 还是一个巨大的 spritesheet 以提高性能? --- (java 游戏开发)

Multiple small spritesheets or one giant spritesheet for performance? --- (java game development)

所以我知道使用 spritesheet 比加载单个图像要好得多,但是 spritesheet 的最佳实现是什么?

使用许多 spritesheet(例如在游戏中,每个角色一个,等等),或者将所有图像放入一个 MEGA spritesheet,其大小可以说是 10,000 x 10,000。

两者哪个性能更好?

对可能出现在同一游戏 section/level 中的任何动画和静态精灵使用 spritesheet 通常是最好的方法。拥有一个巨大的 spritesheet 可能会 产生稍微更好的性能,但是你会相当快地遇到递减法则 returns ,并且它可能会使事情更加占用内存。

Spritesheet 可以通过多种方式提高效率:

  • 它们减少了从磁盘(或通过网络请求)读取图像数据的大量开销。

    Sprites 几乎总是在游戏开始前加载,因为尝试即时获取所有这些数据会非常糟糕。因此,拥有 sprite 表可能会减少您的加载时间,而拥有一个巨大的 spritesheet 可能会加快加载速度,但也意味着您将不得不加载游戏中的每个 sprite——即使您只打算使用几个。这将占用更大的内存,但可能不足以产生很大的不同。

  • 他们通过允许简单地翻译已经在内存中的图像,而不是复制一堆数据来加快 painting/animation。

    这是可能是 spritesheets 提供的更显着的性能优势。通常,这些类型的转换是硬件加速的(尽管这实际上取决于系统架构),但它比四处复制图像数据的性能要高得多,即使没有硬件加速也是如此。在这里,一个巨大的 spritesheet 可能不会产生太多收益,因为您只需要将动画中存在的帧放在 sprite 中。

由于拥有一个巨大的 spritesheet 与一些组织良好的 spritesheet 相比,只有很小的性能提升潜力,我会推荐最简单的实现。如果一个巨大的 spritesheet 很难在您的系统中使用,您可能最终会在代码中做一些尴尬的事情来管理它,这最终会很快破坏任何性能提升。但是如果你有一个系统可以很好地处理它,并且它是翻转某些配置的问题,那么它可能是值得的。

你的目标平台是什么?

大多数游戏开发框架使用 OpenGL 进行渲染(例如 libgdx,和引擎,...)- 这提高了性能但有限制:不要创建精灵 sheet 大于移动设备的 2048x2048。我建议所有设备都保持在 4096x4096 以下。台式机可以处理更大的纹理,但您可能会遇到着色器精度问题。

性能

为 OpenGL 更改纹理和设置参数需要时间。

使用单个精灵看起来像这样(伪代码)

foreach(sprite in sprites)
{
    opengl.setTexture(sprite.texture)
    opengl.setTextureCoordinates(sprite.sourceRect)
    opengl.setTargetCoordinates(sprite.screenPosition)
    opengl.draw()
}

所以你的每个精灵都有大约 4 个调用。 100 个精灵 => 400 次 OpenGL 调用。 这很糟糕!

draw() 之后,可能需要 uired 等待下一个纹理可以设置。

为了优化绘制调用的数量,您的游戏引擎会批处理精灵的绘制。

游戏引擎可以通过 3 个绘制调用绘制一个精灵 sheet 上的所有精灵:

foreach(sprite in sprites)
{
    textureCoordinates.append(sprite.sourceRect)
    screenPositions.append(sprite.screenPosition)
}

opengl.setTexture(sheet.texture)
opengl.setTextureCoordinates(textureCoordinates)
opengl.setTargetCoordinates(screenPositions)
opengl.draw()

1 个 Sprite sheet,4 次 OpenGL 调用。 这个不错!

这太理论化了?这是关于 optimizing game performance 的有趣视频。

你看:使用 sprite sheets 很重要。

这幅画从背景中的物体开始,一直到前景。这是 required 以确保正确处理重叠对象的透明度。

只要您可以将所有精灵都放在 1 sheet 中,这就完美了。 如果你有很多动画,移动设备的限制(上面提到的)可能不允许你把所有的东西都放在 1 sheet.

因此,将您的精灵分布到多个精灵 sheets requires 需要更多思考:

将精灵、对象和 ui 元素分组到图层中 - 根据它们的重叠方式:

  • 将所有 明显落后于 1 sheet 中的其他 sprite。例如。背景图形。
  • 将所有清楚地放在 1 sheet 中 其他 sprite 之前。例如。 UI 元素、HUD、分数
  • 将可能出现在之前或之后其他对象的所有内容放在一个sheet中。

前两个很明显ui- 后者可能不是。

如上所述:游戏引擎从后台开始,到前台工作。它首先分批绘制您的背景。很好。

然后是角色、敌人、子弹、游戏对象等等。 All on one sheet: 没问题。多个 sheets:可能必须切换纹理 - 强制执行额外的绘制调用:游戏中的精灵重叠(背景到前景):

Sheet A: Sprites: a1,a2
Sheet B: Sprites b1

a1,a2,b1 => 2 batches: A,B 
a1,b1,a2 => 3 batches: A,B,A

因此:如果您无法将所有游戏对象、敌人和角色放入 1 sheet,请确保为它们定义清晰的 z 顺序:

  • 背景中的敌人
  • 中间的字符
  • 前方有子弹
  • 前面的游戏对象

尽可能多地在一个 sheet 中分组 - 但不要将一组分配到不同的 sheet 中。确保您的游戏也符合顺序。

打包精灵

透明度似乎对精灵来说并不是什么。它只是透明的,对吧?没有!

透明度很昂贵。它浪费内存。它还会降低性能 - 因为所有透明像素都必须由 OpenGL 读取和处理。

使用可以最大限度地发挥精灵 sheet 的软件。游戏引擎支持修剪精灵,即:没有额外透明度的精灵 - 同时保持动画稳定和无抖动。

看看这个 sprite sheet maker - 它负责打包您的 sheets,删除额外的透明度和您需要的一切。