SDL3 入门(5):纹理渲染

sdl3 · 浏览次数 : 10

小编点评

本文介绍了在 SDL 中创建纹理的三种 API:SDL_CreateTexture、SDL_CreateTextureFromSurface 和 SDL_CreateTextureWithProperties。其中,前两个 API 内部都是通过调用 SDL_CreateTextureWithProperties 实现纹理创建的。文章还展示了如何使用这些 API 创建一个具有四个像素的简单纹理,并提供了图像混合模式和缩放模式的设置方法。最后,文章提到了如何查询当前渲染器支持的纹理格式。 1. SDL_CreateTexture:此 API 参数较少,使用方便,适用于创建简单的纹理。 2. SDL_CreateTextureFromSurface:适用于从已有图像数据创建纹理。 3. SDL_CreateTextureWithProperties:功能强大,适用于其他两个 API 无法满足需求的情况。 文章通过一个简单的例子展示了如何使用这些 API 创建纹理,并提供了图像混合模式和缩放模式的设置方法。此外,还介绍了如何查询当前渲染器支持的纹理格式,以便在不同图形引擎之间进行测试。 总之,文章详细介绍了在 SDL 中创建纹理的三种 API 的使用方法和相关概念,为开发者提供了有用的信息。

正文

创建纹理

有三个 API 可以用来创建纹理:

  • SDL_CreateTexture 参数少,使用方便,适用于创建简单的纹理
  • SDL_CreateTextureFromSurface
    适用于从已有图像数据创建纹理
  • SDL_CreateTextureWithProperties 可以指定各种属性,功能强大,用起来也比较复杂,适用于另外两个 API 无法满足需求的情况

实际上前两个 API 内部都是通过调用 SDL_CreateTextureWithProperties 实现纹理创建的。这也是 SDL API 设计的特点,对于常用操作有简洁的 API 实现,同时也有使用复杂但是功能更灵活强大的 API 提供。

这里我们准备创建一个最小的四种颜色的纹理,像素尺寸 2x2,也就是总计只有 4 个像素。首先使用数组定义图像数据:

uint8_t pixels[4 * 2 * 2] = {
    0,   0,   255, 255,  // b, g, r, a
    0,   255, 0,   255,  //
    255, 0,   0,   255,  //
    0,   255, 255, 255   //
};

SDL 对像素格式的定义是按照从高位到低位的颜色命名的,所以上面的数据对应的格式是 SDL_PIXELFORMAT_ARGB8888

由于已经有像素数据,所以我们可以从图像数据创建 Surface 然后调用 SDL_CreateTextureFromSurface 从 Surface 创建纹理:

SDL_Surface* surface = SDL_CreateSurfaceFrom(pixels, 2, 2, 4 * 2, SDL_PIXELFORMAT_ARGB8888);
if (!surface) {
    SDL_Log("Create surface failed: %s", SDL_GetError());
    return -1;
}

SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
if (!texture) {
    SDL_Log("Create texture failed: %s", SDL_GetError());
    return -1;
}

图像混合模式选择 None 也就是忽略透明通道,缩放模式选择临近点插值:

SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_NONE);
SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_NEAREST);

渲染纹理

渲染纹理使用的 API 是 SDL_RenderTexture,可以通过参数指定渲染纹理的矩形区域,也可以指定目标矩形区域。这里我们选择渲染整个纹理到目标中心附近宽高各为窗口一般的矩形区域:

// 计算目标矩形
int width = 0;
int height = 0;
SDL_GetRenderOutputSize(renderer, &width, &height);
SDL_FRect dst_rect{};
dst_rect.w = width * 0.5f;
dst_rect.h = height * 0.5f;
dst_rect.x = (width - dst_rect.w) * 0.5f;
dst_rect.y = (height - dst_rect.h) * 0.5f;

// 渲染
SDL_SetRenderDrawColor(renderer, 16, 0, 16, 255);
SDL_RenderClear(renderer);
SDL_RenderTexture(renderer, texture, nullptr, &dst_rect);
SDL_RenderPresent(renderer);

渲染效果如下:

图中每种颜色对应的是最初的 2x2 图像中的一个像素,因为前面我们选择的缩放模式是临近点插值。实际图像处理中使用更多的是双线性插值,我们可以修改前面的代码看下效果:

SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_LINEAR);

渲染效果:

纹理格式

可以使用如下代码查询当前渲染器支持的纹理格式:

void PrintSupportedTextureFormats(SDL_Renderer* renderer)
{
    SDL_PixelFormatEnum* texture_format = static_cast<SDL_PixelFormatEnum*>(SDL_GetProperty(
        SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_TEXTURE_FORMATS_POINTER, nullptr));
    int index = 0;
    while (texture_format && *texture_format != SDL_PIXELFORMAT_UNKNOWN) {
        SDL_Log("Texture format[%d]: %s", index, SDL_GetPixelFormatName(*texture_format));
        ++texture_format;
        ++index;
    }
}

使用不同的图形引擎创建渲染器时支持的纹理格式也不相同,下面是在一台 Windows 11 系统笔记本上的测试结果:

Format direct3d11 direct3d12 direct3d(9) opengl opengles2 vulkan software
SDL_PIXELFORMAT_ARGB8888 Y Y Y Y Y Y Y
SDL_PIXELFORMAT_ABGR8888 - - - Y Y - -
SDL_PIXELFORMAT_XRGB8888 Y Y - Y Y Y Y
SDL_PIXELFORMAT_XBGR8888 - - - Y Y - -
SDL_PIXELFORMAT_XBGR2101010 Y Y - - - Y -
SDL_PIXELFORMAT_RGBA64_FLOAT Y Y - - - Y -
SDL_PIXELFORMAT_YV12 Y Y Y Y Y Y -
SDL_PIXELFORMAT_IYUV Y Y Y Y Y Y -
SDL_PIXELFORMAT_NV12 Y Y - Y Y Y -
SDL_PIXELFORMAT_NV21 Y Y - Y Y Y -
SDL_PIXELFORMAT_P010 Y Y - - - Y -

可以看到 SDL_PIXELFORMAT_ARGB8888 格式被包括软件实现在内的所有图形引擎支持,这正是我们前面选择使用该格式创建纹理的原因,可以方便的选择各个图形引擎进行测试。

与SDL3 入门(5):纹理渲染相似的内容: