首页 文章

SDL2:渲染引擎设计

提问于
浏览
1

我正在创建基于SDL2库的简单游戏渲染引擎 . 我的设计看起来类似于这个ASCII图 .

DrawTarget     RenderTarget
    |                |
    |                |
    +---> Window <---+

DrawTarget 是适用于SDL_Surface blitting的绘制目标的抽象类 . RenderTarget 是适合SDL_Texture的渲染目标的抽象类 . Window 是派生类,管理SDL_Window,SDL_Renderer以及所有绘制和渲染功能 .

Renderable
  |  |  |
  |  |  |
  |  |  +-> Player
  |  |         ^
  |  |         |
  |  +----> Animation
  |            ^
  |            |
  +-------> Texture

Renderable 是一切,可以渲染到屏幕或其他RenderTarget . Texture 是SDL_Texture实现 . 纹理不应该知道它自己的位置 . Animation 有一个私有纹理成员,允许设置动画帧 . 动画本身不应该知道渲染位置 . Player 有一个私人动画会员 . 玩家应该知道当前的位置 .

在这个时候,我每个窗口都有一个 SDL_Renderer 并将它全部传递给纹理,动画等 . 纹理具有 SDL_Renderer 渲染本身到屏幕的知识 . 但我不认为一直调用Texture-> draw(x,y)是有效的,并且缓存友好 .

我喜欢SFML呈现的方式 . 所有可渲染对象都有 draw 方法,它只调用窗口的draw方法 . 我想实现类似的系统 .

这将破坏我的要求,一些Renderable对象知道它们的渲染位置,有些则不然 .

例如,类Player不应该有 render( x, y ) 方法,因为它知道它的位置 . 另一方面,Texture类不应该有 render( void ) 方法,因为它不是它的位置 .

我的问题如下:如何以尽可能小的开销设计SDL2合适的渲染引擎?

2 回答

  • 2

    回答你的问题:“我的问题如下:如何设计SDL2合适的渲染引擎,尽可能少的开销?”

    快速解释可缩放的懒惰渲染器方案,以最大限度地减少SDL2渲染器开销:

    “图层”由具有相同z属性的所有纹理组成 . 只要修改了该图层中的纹理,图层就会被标记为无效 . 在渲染器运行时管理图层,这是在设置的帧速率下 . 跟踪最大层和最高无效层 . 渲染器从最高的无效层开始,到最大层结束 . 每个图层都设置为渲染器目标并清除 . 然后将上一层复制到当前图层 . 然后,它遍历图层中的每个纹理,重新绘制标记为无效的纹理,并将每个纹理复制到当前图层的顶部 . 结果是前一层是背景,而当前层是在它上面绘制的 . 当图层标记为无效时,此纹理将被缓存并失效 . 在遍历任何无效图层后,将渲染目标设置回默认值(null),将最高纹理复制到屏幕并显示 .

    在带有图层用户界面类型的环境的2d中,上面是可伸缩和懒惰的 . 在我的低端Celeron n2830上,我的测试应用程序在0%cpu使用率下空闲 . 即使我添加了一百个测试层,它或多或少都保持这种状态 . 因为它只是从哪个层向上变换,并且所有变化都以合理的帧速率排列,所以很少有工作最终完成 . 通过无效层迭代到最大层看起来渐渐变得更加友好,然后在每次运行时遍历所有层 . 以设定的间隔运行渲染器并执行所有绘制然后有助于节省时间,因为它将忽略无论如何都看不到的多余更改 . 使用一些应用程序代码以避免必须绘制内容和复制纹理是值得的 . 如果检查和属性查找,那些往往需要更长的时间 .

    请注意,此设计适用于带有图层的2D,如用户界面 . 某些原则可能不一定在其他环境中很好地工作 .

    此外,上面只支持纹理,而不支持表面 . 混合两者对我来说不值得复杂 . 让sdl2渲染器绘制到一个特定的纹理需要一些计算,但单独满足我的需求 . 如果你把两者混合起来,似乎很难避免一些额外的工作 . 加上纹理受益于gpu,这增加了cpu时间方面的效率 .

    在我的系统中,window对象有一个draw方法 . 此方法使用渲染器排列绘制操作,而不是立即绘制它们 . Window对象具有area属性 . 为了支持没有area属性的对象,也许你可以应用一个包围你的对象的包装器不 . 这样当提示输入区域时,它仍然可以提供一个区域,即使它内部没有区域也是如此 . 或者可以使用将对象映射到某个区域的表,或者任何对象跟踪其纹理的方法调用 . 我不确定这种限制的性质 .

    请注意,此绘制方法是绘制自身和渲染器绘图对象的对象的混合方法 . 对象似乎是自己绘制的,而渲染器实际上是在完成工作 .

    简而言之:

    • 纹理明显快于表面

    • 排队批处理的绘制和复制操作

    • 在绘制时缓存纹理
      将所有纹理复制到它们后

    • 缓存图层

    • 使用缓存来避免将除了无效图层以外的所有图层渲染到最大图层

  • 3

    在我看来,你所说的是你希望实体只知道它们的位置,但是为了让你想让它完全分开 . 每个实体都需要存储某种渲染数据 . 我会说你应该看一个基于组件的实体系统 . 有位置,renderdata,输入等不同的类 . 试试Component Based Entity System

相关问题