Chapter 97 · 离屏渲染与 GPU 管线

Render Target

Render Target 是离屏渲染的核心——将绘制结果输出到纹理而非窗口,实现后处理、阴影贴图、UI 缓存等。

97

概念

Render Target(RT)是一块 GPU 帧缓冲,可以像窗口一样接收绘制命令。 渲染完成后,RT 的颜色附件作为纹理使用——可绘制到屏幕、作为后处理输入或回读像素。 窗口本身也是一个特殊的 RT。

API 速查

函数说明
int xgeRenderTargetWindow(xge_render_target pTarget)获取窗口 RT
int xgeRenderTargetCreate(xge_render_target pTarget, int iWidth, int iHeight)创建离屏 RT
int xgeRenderTargetResize(xge_render_target pTarget, int iWidth, int iHeight)调整尺寸
int xgeRenderTargetCaptureCurrent(xge_render_target pTarget, int iSrcX, int iSrcY)从当前帧缓冲捕获
int xgeRenderTargetReadPixels(xge_render_target pTarget, void* pPixels, int iStride)回读像素
xge_texture xgeRenderTargetTexture(xge_render_target pTarget)获取颜色纹理
void xgeRenderTargetFree(xge_render_target pTarget)释放 RT

编译本章示例

gcc -O2 -I. -o ch97.exe ch97_main.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch97.exe

示例:离屏渲染 + 后处理

// 创建离屏 RT
xge_render_target_t rt;
xgeRenderTargetCreate(&rt, 800, 600);

// 绑定 RT 进行绘制(通过 Pass)
xge_pass_t pass;
xgePassInit(&pass, &rt,
    XGE_PASS_CLEAR_COLOR, 0x1A1A2EFF);
xgePassBegin(&pass);

// 在 RT 上绘制场景
xgeShapeCircleFill(400, 300, 100, 0xFF6B5EFF);
xgeTextDraw(font, "Offscreen", 350, 280, 0xFFFFFFFF);

xgePassEnd(&pass);

// 将 RT 纹理绘制到窗口(可缩放)
xge_texture rtTex = xgeRenderTargetTexture(&rt);
xgeDraw(rtTex, 0, 0);

// 窗口大小变化时
xgeRenderTargetResize(&rt, newW, newH);

完整代码

将以下代码保存为 ch97_main.c,编译后运行即可看到离屏渲染与后处理效果:

#include "xge.h"
#include <math.h>

static xge_render_target_t g_rt;
static xge_font g_font = NULL;
static float g_time = 0.0f;

static int onFrame(void* pUser) {
    (void)pUser;
    g_time += 0.016f;

    // Pass 1:离屏渲染场景到 RT
    xge_pass_t pass;
    xgePassInit(&pass, &g_rt,
        XGE_PASS_CLEAR_COLOR, 0x1A1A2EFF);
    xgePassBegin(&pass);

    // 在 RT 上绘制动态场景
    float cx = 200.0f + 100.0f * cosf(g_time);
    float cy = 150.0f + 80.0f * sinf(g_time * 1.5f);
    xgeShapeCircleFill(cx, cy, 40.0f, 0xFF6B5EFF);
    xgeShapeRectStroke((xge_rect_t){50, 50, 300, 200}, 2.0f, 0x44FFFFFF)
    xgeTextDraw(g_font, "Offscreen RT",
        140.0f, 140.0f, 0xFFFFFFFF)

    xgePassEnd(&pass);

    // Pass 2:将 RT 纹理绘制到窗口(可缩放)
    xgeClear(0x081114FF);
    xge_texture rtTex = xgeRenderTargetTexture(&g_rt);
    xgeDraw(rtTex, 100.0f, 50.0f);

    xgeTextDraw(g_font, "RT rendered to window",
        100.0f, 400.0f, 0xFFFFFFFF)

    return XGE_OK;
}

int main(void) {
    xge_desc_t d = {0};
    d.iWidth  = 800;
    d.iHeight = 600;
    d.sTitle  = "ch97 - Offscreen RenderTarget";
    d.iFlags  = XGE_INIT_VSYNC;
    xgeInit(&d);

    xgeFontLoad(&g_font, "Roboto.ttf", 18.0f);

    // 创建离屏 RT (400x300)
    xgeRenderTargetCreate(&g_rt, 400, 300);

    xgeRun(onFrame, NULL);

    xgeRenderTargetFree(&g_rt);
    xgeFontFree(g_font);
    xgeUnit();
    return 0;
}

代码讲解

  • RenderTargetCreate:创建指定尺寸的离屏渲染目标,独立于窗口帧缓冲。
  • Pass 绘制:通过 PassBegin/PassEnd 将绘制指令定向到 RT 而非窗口。
  • RenderTargetTexture:获取 RT 的颜色纹理,可作为普通纹理绘制到窗口。
  • 后处理管线:先离屏渲染场景,再对 RT 纹理做缩放/滤镜后输出到窗口。

要点与陷阱

  • Window RT:默认帧缓冲,不需要 Create/Free。
  • Texture:RT 的纹理指针在 RT 生命周期内有效,无需 AddRef。
  • Resize:窗口大小变化时必须同步 Resize,否则内容拉伸。
  • ReadPixels:GPU→CPU 同步操作,避免每帧调用。

进阶练习

  1. 实现场景缩略图:离屏渲染 → ReadPixels → SavePNG。
  2. 多层 RT:背景层 + 前景层分别渲染后合成。
Render Target效果
图:Render Target渲染效果