【问题标题】:Is it okay to call SDL_RenderCopy() for each sprite?可以为每个精灵调用 SDL_RenderCopy() 吗?
【发布时间】:2021-02-20 17:56:47
【问题描述】:

这是我的问题的后续:Is it okay to have a SDL_Surface and SDL_Texture for each sprite?

我创建了一个名为 entity 的类,每个类都有一个 SDL_Texture,它在构造函数中设置,然后为向量中的每个屏幕实体调用成员函数 render(),它使用 SDL_RenderCopy() 绘制到渲染器。

这个 render() 函数包括根据每个精灵的位置/相机数据为每个精灵生成矩形

这样好吗?有更快的方法吗?

我用 96 个 sprite 制作了一个测试关卡,每个 sprite 占用 2% 的屏幕,有大量的过度绘制,ft 为 15ms (~65fps),分辨率为 1600x900。对于一些精灵来说似乎有点慢,而且我的电脑呼吸比玩完整游戏(如 spelunky 或 isaac)时重得多。

【问题讨论】:

  • 如果您通过在函数DL_RENDERER_PRESENTVSYNC 中使用VSYNC 来使用VSYNC,那么这可以解释为什么尽管只渲染了96 个精灵,但您的帧率却被限制在大约60 FPS。但是,这并不能解释为什么您的计算机正如您所说的“呼吸困难”。但是,我不会太在意这一点,因为这可能有几个原因,这可能超出您的控制范围。您应该主要关注的是FPS。
  • 这是 SDL 提供的唯一绘图方式,您只能缓存结果或操作输入。在内部,较新的 SDL 将多个绘制批处理为一个,但它受到您输入其输入的内容的限制。如果您可以计算出哪些部分绝对是不可见的 - 这样做并且不要绘制它们。如果您知道图像没有透明度(或其他确保可见性的方式) - 将它们从前到后渲染以减少过度绘制。将图像打包到图集中可以显着减少纹理变化,从而提供更好的性能。

标签: c++ sdl-2


【解决方案1】:

帧时间优于 FPS

您想根据帧时间而不是 FPS 来衡量和判断您的表现。因为两者之间的关系不是线性的。从 20 FPS 到 30 FPS 需要大约 16.7 毫秒的优化时间。这与从 30 FPS 到 60 FPS 所需的优化性能提升量相同。因此,如果您根据 FPS 判断性能,您会得出结论,将 FPS 从 30 提高到 60 的特定“优化”优于使 20 FPS 场景运行 31 FPS 的优化。而后者实际上是更好的优化。

批量绘制

如果将所有纹理打包成一个并存储每个单独图像的坐标,则可以使用相同的纹理来绘制许多对象。这受到纹理的大小和数量以及环境中支持的最大纹理大小的限制。根据我的经验,4096x4096 是安全的,但我更喜欢使用 2048x2048 的“纹理图集”。有许多实用程序可以制作这样的纹理。您可以通过 Google 搜索轻松找到合适的。

在此设置中,除了 SDL 纹理外,每个精灵还具有包含所需特定图像的“大”纹理中区域的 x、y、宽度和高度。您可以创建一个TextureRegion 课程。然后每个精灵都有一个TextureRegion。这整个过程通常称为批处理。查一下。整个想法是最小化状态变化。我不确定它是否适用于软件渲染或所有 SDL2 后端。

缓存您的转换

对精灵进行批处理将提高 GPU 方面的性能。 CPU 绑定代码是另一个优化机会。而不是在每一帧计算SDL_RenderCopy的参数,计算一次并缓存。然后当相机或物体的位置/旋转发生变化时,重新计算缓存。您可以在实体类的“访问器”中执行此操作(例如setPositionsetRotaion 等)。请注意,与其在位置或旋转发生变化时直接重新计算变换,不如将对象标记为“脏”并在渲染函数中检查脏标志。 if this->isDirty 然后重新计算并缓存变换。当您这样做时,这可以防止多余的计算:

//if dirty flag is not used each of the following function calls
//would have resulted in a recalculation of transforms. However by
//using the dirty flag they will be calculated only once before 
//the rendering of next frame in the render() function.
player->setPostion(start_x,start_y);
player->setRotation(0);
camera->reset();

【讨论】:

  • 很好的回答,非常感谢!我会尝试实现这些。
【解决方案2】:

因此,我通过在“要求”级别全屏检查该程序的内存/cpu 使用情况进行了更多测试,并通过强制帧速率上限使其与其他游戏相似

strong> 使用 SDL_Wait()
float g_max_framerate = 60;
float g_max_frametime = 1/g_max_framerate * 1000;
...
while (!quit) { 
        
        lastticks = ticks;
        ticks = SDL_GetTicks();
        elapsed = ticks - lastticks;
        
        ...
        
        SDL_RenderPresent(renderer);
        //lock framerate
        if(elapsed < g_max_frametime) {
            SDL_Delay(g_max_frametime - elapsed);
        }
}

由于这个限制,它是适当的低规格。

【讨论】:

  • 在您的问题中,您说 FPS 已经在大约 60 FPS 的范围内,这是正常的。因此,进一步降低帧速率似乎不能解决您的问题。但是,我相信拥有帧速率限制器始终是一个好主意,以防止帧速率过高 (>150 FPS)。
  • 是的,因此我不会接受我自己的答案。但是,这确实使 CPU 从 30% 降低到 3%,从而阻止了我的计算机发热和大声吹风扇。
猜你喜欢
  • 1970-01-01
  • 2011-12-21
  • 2020-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-01
  • 1970-01-01
相关资源
最近更新 更多