可以为每个精灵调用 SDL_RenderCopy() 吗?

Is it okay to call SDL_RenderCopy() for each sprite?

这是我的问题的后续:

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

此 render() 函数包括根据 position/cameradata

为每个精灵生成矩形

这样可以吗?有没有更快的方法?

我用 96 个精灵制作了一个测试关卡,每个精灵占据屏幕的 2%,并且有大量透支,在 1600x900 的分辨率下,英尺为 15 毫秒(~65fps)。对于一些 sprite 来说似乎有点慢,而且我的电脑在玩 spelunky 或 isaac 等完整游戏时呼吸更重。

因此,我通过 memory/cpu 以“要求”级别全屏检查此程序的使用情况并通过 设法使其与其他游戏相似,从而进行了更多测试使用 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

您想根据帧时间而不是 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、宽度和高度。你可以做一个TextureRegionclass。然后每个精灵都有一个 TextureRegion。这整个过程通常称为批处理。查一下。整个想法是尽量减少状态变化。我不确定它是否适用于软件渲染或所有 SDL2 后端。

缓存您的转换

批处理精灵将提高 GPU 方面的性能。 CPU 绑定代码是另一个优化机会。不是每一帧都计算SDL_RenderCopy的参数,而是计算一次,缓存起来。然后当camera或object的position/rotation发生变化时,重新计算缓存。您可以在实体 class(如 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();