c++ - 使用 SDL2 在每一帧上渲染屏幕的一部分

标签 c++ graphics sdl-2

我正在使用 SDL2 用 C++ 制作 2D 游戏,其中世界地图由 120x67 block 组成。在任何给定时间,只会有大约 20 个左右的 Sprite (每个 Sprite 恰好占据一个图 block )在 map 上移动,并且只有一小部分图 block (主要是水图 block )会进行动画处理。因此,在绝大多数时间里,大部分图 block 将保持静态。目前,我有一个简单的绘制循环,可以迭代所有图 block 并重新绘制它们:

/* Drawing loop, excluding frame rate limiting logic and updating gamestate */
while(true) {

    /* game state is updated (omitted) */

    /* clear the entire screen */
    SDL_RenderClear(renderer);

    /* loop through all the tiles and redraw them */
    for (int i = 0; i < rows; i++) {
        for(int j = 0; j < cols; j++) {

            /* call the tile's draw method, which calls SDL_renderCopy()
             * to draw the tile background and sprite (if there is one) */
            tiles[i][j].drawTile(renderer);
        }
    }

    /* output everything to the screen */
    SDL_RenderPresent(renderer);
}

但是,由于大多数图 block 在大多数时间都保持静态,因此无需继续绘制它们。仅重绘屏幕上正在变化的小部分会更有效。所以我的新想法是,在更新游戏状态时,将所有更新的图 block 添加到列表中,然后只需在每个帧上仅重绘更新的图 block ,如下所示:

/* Drawing loop that only redraws updated tiles */
while(true) {

    /* game state is updated, updated tiles added to a list (omitted) */

    /* loop through only the updated tiles and redraw them */
    for (std::list<Tile>::iterator it=updatedTiles.begin(); it != updatedTiles.end(); ++it) {

        /* call the tile's draw method, which calls SDL_renderCopy()
         * to draw the tile background and sprite (if there is one) */
        it->drawTile(renderer);
    }

    /* output everything to the screen */
    SDL_RenderPresent(renderer);
}

由于我不想在每帧之前清除屏幕,因此在第二种情况下删除了对 SDL_RenderClear() 的调用。但是,从 SDL_RenderPresent 的 SDL2 文档中发现 here ,它说:

You are strongly encouraged to call SDL_RenderClear() to initialize the backbuffer before starting each new frame's drawing.

有了这个,我的两个问题是:

  1. 如果我只想更新修改后的图 block ,我真的需要在每个帧上调用 SDL_RenderClear() 吗?
  2. 如果我必须坚持重绘每一帧上的每个图 block ,现代显卡/SDL 库是否足够“智能”,在调用 SDL_RenderPresent() 时,仅重绘更改的屏幕,而无需我执行此操作?

最佳答案

文档的相关部分紧接在您提到的部分之前(强调我的)

The backbuffer should be considered invalidated after each present; do not assume that previous contents will exist between frames.

这意味着对 SDL_RenderClear 的调用是强制的,而不是建议的

您可以做的就是仅在目标纹理上绘制背景图像(无论它意味着什么,例如周围没有任何 PC 或 NPC 的图 block 集)进入场景之前一次(有关更多详细信息,请参阅 SDL_SetRenderTarget 和其他函数)。然后,在循环中,您可以清除默认渲染器,立即将该图像复制为背景图像,最后仅在其上绘制更新的图 block ,从而更新它们的(让我说)默认或基本表示
事实上,如果您更新了 N 个图 block ,则最终会在每次迭代时通过对 SDL_RenderCopy 或其他内容的 N+1 次调用来绘制所有内容。

说实话,只有当您观察到由于每次迭代绘制太多而导致帧数显着下降时,我才会这样做。我的两分钱。
无论如何,这是一个肮脏但有效的解决方案,至少可以满足您的要求。

关于c++ - 使用 SDL2 在每一帧上渲染屏幕的一部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46311411/

相关文章:

c++ - 用于渲染不同对象的 VAO 和 VBO

Java应用程序在按下按钮时创建矩形

c++ - 我们可以在 SDL2 中使用 std::fstream 而不是 SDL_RWops 吗?

c++ - 为什么我的 SDL/C++ 图像消失了?

c++ - 客户端使用的 REST 和 HTTP 库之间有什么区别?

c++ - 无法理解这个可变参数模板示例

c++ - Clang AST Matcher和AST Visitor之间有什么区别?

html - 小型未缩放的 SVG 在所有浏览器中呈现模糊和错误

c# - 在 ASP.NET/C# 中使用 GDI+ 裁剪图像时抗锯齿?

c - SDL2 - 纹理和频繁变化的图片