SDL3 入门(5):纹理渲染

创建纹理

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

相关推荐
OH五星上将2 个月前
开源图形驱动在OpenHarmony上的使用和落地
开源·移动开发·openharmony·arkui·鸿蒙开发·图形图像
知来者逆2 个月前
视频插帧—— RIFE 和 IFNet 的机制和应用
图像处理·计算机视觉·mvc·视频处理·视频插帧·补帧
北极象2 个月前
PyQtGraph库的基本使用
python·pyqt·pyqtgraph·图形图像
Leaf Ye3 个月前
Android12 显示框架之getSurface
android·嵌入式软件·图形图像
知来者逆4 个月前
VideoAgent——使用大规模语言模型作为代理来理解长视频
人工智能·算法·语言模型·音视频·实时音视频·视频处理
小时了了4 个月前
SDL3 入门(4):选择图形引擎
视频处理·sdl3·图形图像
小时了了5 个月前
SDL3 入门(3):三角形
视频处理·sdl3·图形图像
小时了了5 个月前
SDL3 入门(2):第一个窗口
视频处理·sdl3·图形图像
忆_恒心5 个月前
【Node.js快速部署opencv项目】图像分类与目标检测
人工智能·opencv·目标检测·分类·node.js·图像分类·视频处理