多个小型 spritesheet 或一个巨大的 spritesheet 以提高性能? ---(java游戏开发)[关闭]

Posted

技术标签:

【中文标题】多个小型 spritesheet 或一个巨大的 spritesheet 以提高性能? ---(java游戏开发)[关闭]【英文标题】:Multiple small spritesheets or one giant spritesheet for performance? --- (java game development) [closed] 【发布时间】:2016-06-26 02:23:51 【问题描述】:

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

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

两者中哪一个会提供更好的性能?

【问题讨论】:

【参考方案1】:

对可能出现在游戏同一部分/级别中的任何动画和静态精灵使用精灵表通常是最好的方法。拥有一个巨大的 spritesheet可能会产生稍微更好的性能,但是您会很快达到收益递减规律,并且它可能会使事情变得更加占用内存。

Spritesheets 倾向于通过以下几种方式提高效率:

它们减少了从磁盘(或通过网络请求)读取图像数据的显着开销。Sprite 几乎总是在游戏开始之前加载,因为试图即时获取所有数据会很糟糕。因此,拥有精灵表可能会减少您的加载时间,而拥有一个巨大的精灵表可能会加快这一速度,但这也意味着您必须加载游戏中的每个精灵——即使您只打算使用几个。这将占用更大的内存,但可能还不足以产生很大的影响。

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

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

【讨论】:

另外请注意,硬件加速图形系统对其使用的数据大小的限制可能低于通常的限制。如果单个图像太大(不过 10,000x10,000 似乎合理),图形加速可能会受到影响。大多数系统现在都有很好的图形处理能力,不过……只是需要注意的一点。【参考方案2】:

您的目标平台是什么?

大多数游戏开发框架都使用 OpenGL 进行渲染(例如 libgdx、andengine 等) - 这可以提高性能,但有一些限制:不要为移动设备创建大于 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() 之后可能需要等到可以设置下一个纹理。

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

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

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 表,4 个 OpenGL 调用。 这很好!

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

你看:使用精灵表很重要。

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

只要您可以将所有精灵放在一张纸上,它就可以完美运行。 如果您有许多动画,则移动设备的限制(如上所述)可能不允许您将所有内容放在一张纸上。

因此,将您的精灵分布在多个精灵表中需要更多思考:

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

明显落后于其他精灵的所有内容放在一张纸上。例如。背景图形。 将明显位于其他精灵之前的所有内容放在一张纸上。例如。 UI 元素、HUD、分数 将可能出现在在其他对象之前或之后的所有内容放在一张纸上。

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

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

然后是角色、敌人、子弹、游戏对象等等。 全部在一张纸上:没问题。多张纸:可能必须切换纹理 - 强制执行额外的绘制调用:游戏中重叠的精灵(背景到前景):

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

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

所以:如果您无法将所有游戏对象、敌人和角色都放在一张纸上,请确保为它们定义清晰的 z 顺序:

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

在一张纸上尽可能多地分组 - 但不要将一组放在不同的纸上。确保您的游戏也遵守顺序。

包装精灵

透明度在精灵上似乎并不重要。它只是透明的,对吧?不!

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

使用能够最大限度利用您的精灵表的软件。游戏引擎支持修剪后的精灵,即:没有额外透明度的精灵 - 同时保持动画稳定和无抖动。

看看这个sprite sheet maker - 它负责包装您的床单,去除额外的透明度和您需要的一切。

【讨论】:

以上是关于多个小型 spritesheet 或一个巨大的 spritesheet 以提高性能? ---(java游戏开发)[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

如何在 javascript 中减慢我的 spritesheet 动画?

Pixi.js 从动画 gif 文件生成 SpriteSheet Animation 或 MovieClip

MongoDB 巨大的文档或多个查询

Libgdx - 如何加载一个巨大的精灵表,使其不呈现黑色?

带有巨大 BufferdImage 的小型 pdf 文件结果

Windows Phone 应用程序中的 SpriteSheet 动画