SDL2 纹理的作用是什么?

32

我在SDL2纹理的逻辑方面遇到了一些困难。对我来说,它们是毫无意义的,因为你不能在其上进行绘制。

在我的程序中,我有几个表面(或者在我切换到SDL2之前是表面),我只需将它们一起混合以形成层。现在,看起来我必须创建多个渲染器和纹理才能创建相同的效果,因为SDL_RenderCopy需要一个纹理指针。

不仅如此,所有渲染器都必须来自于一个窗口,我明白这点,但仍让我感到有些混乱。

这一切似乎非常笨重和缓慢。我有什么遗漏的地方吗?有没有办法直接绘制到纹理上?纹理的作用是什么?如果不是表面而是渲染器,我是否可以安全地拥有多个(甚至数百个)?


当SDL引入2.0时,其架构发生了变化,这迫使我使用SFML。由于API的更改,我无法处理重构整个程序;基本上,没有像SFML支持的离屏渲染。 - Qix - MONICA WAS MISTREATED
2
SDL2目前处于预发布状态。现在还不公正地对其进行评判。尽管它仍在开发中,但开发者很慷慨地允许我们在进展过程中进行调试。 - user1727324
@Di-0xide 旧的维基仍然可用。http://www.libsdl.org/cgi/docwiki.cgi - Wes
7
3年后回顾,我并不真正理解图形纹理的含义。对于那些仍在点赞的人,请记住,纹理不一定是图像或图形的一部分;实际上它们可以是任何发送到显卡的数据。 - Qix - MONICA WAS MISTREATED
2
又过了三年,我为Reddit ELI5写的回答现在看来有点相关性。这是一个非常基础的图形管线工作原理解释,涉及一些基本理论。如果有人对这个主题完全陌生,这是一个很好的起点。 - Qix - MONICA WAS MISTREATED
3个回答

42

SDL_Texture对象尽可能地存储在视频卡内存中,因此可以轻松地通过GPU加速。调整大小、阿尔法混合、抗锯齿和几乎任何计算密集型操作都可以受到这种性能提升的影响。如果您的程序需要在纹理上运行每个像素的逻辑,则建议您将纹理暂时转换为表面。也可以通过流式纹理进行解决。

编辑: 由于此答案受到了相当大的关注,我想详细说明我的建议。

如果您更喜欢使用纹理 -> 表面 -> 纹理工作流来应用每个像素操作,请确保缓存您的最终纹理,除非您需要在每个渲染周期重新计算它。此解决方案中的纹理是使用SDL_TEXTUREACCESS_STATIC标志创建的。

鼓励使用流式纹理(创建标志为SDL_TEXTUREACCESS_STREAMING) 来处理源数据来自网络、设备、帧服务器或其他超出 SDL 应用程序完全控制范围以及明显缓存来自源的帧是低效或无法工作的用例。

如果使用SDL_TEXTUREACCESS_TARGET标志创建纹理,则可以在纹理上方进行渲染。这限制了绘制操作的源,使其仅限于其他纹理,尽管这可能已经是您首先需要的内容。 "将纹理用作渲染目标"是 SDL2 中最新且支持最少的功能之一。

好奇读者的技术信息:

由于 SDL 实现的特性,前两种方法依赖于应用程序级别的读取和复制操作,尽管它们针对建议的场景进行了优化,并且对于实时应用程序来说足够快。

与在 GPU 上后处理相比,从应用程序层面复制数据几乎总是很慢的。如果您的要求比 SDL 提供的要求更严格,并且您的逻辑不依赖于某些外部像素数据源,则将从您的 SDL 表面绘制的原始 OpenGL 纹理分配并应用着色器(GPU逻辑)是明智的。

着色器是用GLSL编写的,这是一种可以编译成GPU汇编语言的语言。 硬件/GPU加速 实际上指的是在GPU核心上进行并行化处理的代码,并且使用着色器是实现渲染目的的首选方式。

注意!在SDL渲染函数和结构中使用原始的OpenGL纹理和着色器可能会导致意外的冲突或失去库提供的灵活性。

TLDR; 渲染和操作纹理比表面更快,尽管有时修改它们可能会很麻烦。


2
这个 streaming texture 是什么? - anatoly techtonik
1
静态纹理适用于精灵、背景和其他不经常变化的图像... ...流式纹理适用于需要频繁更新的事物,每几秒钟或每帧一次。从技术上讲,它们是可变的像素数据,在每次渲染之间都可能被修改,因此需要额外的注意来避免由于对其缓冲区的重度访问而导致的卡顿。 - diegoperini
1
texture > surface > texture 的逻辑是什么?为什么不在每一帧中使用 surface > texture - Hello World
在第一个渲染循环之后,许多材质将被缓存为纹理。对它们进行小的修改(如更改一些较小的矩形部分)将从该流程中受益。 - diegoperini

8

通过创建一个SDL2 Texture作为STREAMING类型,可以锁定和解锁整个纹理或只是像素区域来执行直接像素操作。必须先创建一个SDL2 Surface,并按照以下方式链接lock-unlock:

SDL_Surface surface = SDL_CreateSurface(..);
SDL_LockTexture(texture, &rect, &surface->pixels, &surface->pitch);
// paint into surface pixels
SDL_UnlockTexture(texture);

关键是,如果你绘制更大尺寸的纹理,并且绘制是增量的(例如实时数据图形),一定要确保仅锁定和解锁需要更新的实际区域。否则操作会变得缓慢,内存拷贝也会变得很重。
我已经有了合理的性能表现,而且使用模型也不太难理解。

1
首先创建一个表面不是必须的,而且可能也不是理想的。SDL_LockTexture() 可以让你获取纹理的像素和步长,将它们写入提供的地址中,这些地址不必是任何表面的一部分,而且可能也不应该是。说“绘制到表面像素”没有意义:实际上你在这里做的是用纹理的 *pixelspitch 成员覆盖表面的相应成员,然后通过该指针更新纹理的像素,而不是表面的像素。这在某些情况下可能有效,也许在你的情况下确实有效,但似乎既不必要也不是一个好主意。 - underscore_d

8
在SDL2中,可以进行离屏渲染或直接将其渲染到纹理上。需要使用的函数是: int SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture); 这只有在渲染器启用了SDL_RENDERER_TARGETTEXTURE时才有效。

有人知道 SDL_RENDERER_TARGETTEXTURE 的广泛支持程度吗? - Vortico
似乎你只需要将 SDL_RENDERER_TARGETTEXTURE 传递给 SDL_CreateRenderer,参见 https://stackoverflow.com/q/38813605 - Jakub Klinkovský

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接