OBS-D3D11渲染梳理
+ -

D3D11顶点缓冲区及纹理数据的更新

2024-07-31 13 0
  • gs_draw_sprite(0, 0, context->width, context->height);
    • gs_vb_data* data = gs_vertexbuffer_get_data(graphics->sprite_buffer); //获取顶点数据缓冲区地址
    • build_sprite_norm(data, fcx, fcy, flip); //填充顶点数据到CPU内存
    • gs_vertexbuffer_flush(graphics->sprite_buffer); //将CPU顶点数据复制到ID3D11Buffer空间中
    • gs_load_vertexbuffer(graphics->sprite_buffer);//设置为当前的curVertexBuffer device->curVertexBuffer = vertbuffer;
    • gs_draw(GS_TRISTRIP, 0, 0)
      • device_draw //d3d11渲染流程
        • device->LoadVertexBufferData()//设置IASetVertexBuffers

顶点数据格式

struct gs_vb_data {
    size_t num;
    struct vec3 *points;
    struct vec3 *normals;
    struct vec3 *tangents;
    uint32_t *colors;

    size_t num_tex;
    struct gs_tvertarray *tvarray;
};
  • num:表示顶点个数。立顶点数量为512,sprite缓冲区为4个。
  • num_tex表示纹理个数。一般为1个。

顶点参数设置

填充gs_vb_data中顶点points的内容使用函数build_sprite_norm,如参数如下:

build_sprite_norm(data, 1920, 1080, 0);

该函数的内容如下:

static inline void build_sprite_norm(struct gs_vb_data *data, float fcx, float fcy, uint32_t flip)
{
    float start_u, end_u;
    float start_v, end_v;

    assign_sprite_uv(&start_u, &end_u, (flip & GS_FLIP_U) != 0);
    assign_sprite_uv(&start_v, &end_v, (flip & GS_FLIP_V) != 0);
    build_sprite(data, fcx, fcy, start_u, end_u, start_v, end_v);
}

static inline void assign_sprite_uv(float *start, float *end, bool flip)
{
    if (!flip){
        *start = 0.0f;
        *end = 1.0f;
    } else {
        *start = 1.0f;
        *end = 0.0f;
    }
}

所以build_sprite参数如下:

build_sprite(data, 1920, 1080, 0, 1.0f, 0, 1.0f);

函数内容如下:

static void build_sprite(struct gs_vb_data *data, float fcx, float fcy,
             float start_u, float end_u, float start_v, float end_v)
{
    struct vec2 *tvarray = data->tvarray[0].array;

    vec3_zero(data->points);
    vec3_set(data->points + 1, fcx, 0.0f, 0.0f);
    vec3_set(data->points + 2, 0.0f, fcy, 0.0f);
    vec3_set(data->points + 3, fcx, fcy, 0.0f);
    vec2_set(tvarray, start_u, start_v);
    vec2_set(tvarray + 1, end_u, start_v);
    vec2_set(tvarray + 2, start_u, end_v);
    vec2_set(tvarray + 3, end_u, end_v);
}

通过分析,对于精录,其4个顶点坐标和纹理坐标如下:
(0,0,0)(1920,0,0)(0,1080,0)(1920,1080,0)
(0,0) (1.0,0) (0,1.0) (1.0,1.0)
193818140374
所以4顶点,2个三角形。

将顶点数据更新到ID3D11Buffer

顶点更新通过函数gs_vertexbuffer_flush实现的

  • gs_vertexbuffer_flush
    • gs_vertexbuffer_flush
      • gs_vertexbuffer_flush_internal
        • vertbuffer->FlushBuffer(vertbuffer->vertexBuffer, data->points,sizeof(vec3));

FlushBuffer就是对ID3D11Buffer进行映射,然后内存拷贝即可。因为是内存对齐的。

void gs_vertex_buffer::FlushBuffer(ID3D11Buffer *buffer, void *array,
                   size_t elementSize)
{
    D3D11_MAPPED_SUBRESOURCE msr;
    HRESULT hr;

    if (FAILED(hr = device->context->Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &msr)))
        throw HRError("Failed to map buffer", hr);

    memcpy(msr.pData, array, elementSize * vbd.data->num);
    device->context->Unmap(buffer, 0);
}

使用gs_vb_data的内存空间创建ID3D11Buffer,当数据更新时,需要用map映射出来再次更新。所以CPU和GPU之间的数据同步,是需要手动执行的。

纹理坐标的更新

顶点包含有纹理坐标,需要也更新。
在函数gs_vertexbuffer_flush_internal中

    for (size_t i = 0; i < num_tex; i++) 
    {
        gs_tvertarray &tv = data->tvarray[i];
        vertbuffer->FlushBuffer(vertbuffer->uvBuffers[i], tv.array,    tv.width * sizeof(float));
    }

这里num_text=1表示只有一个纹理,而tv.width=2表示坐标为2个float型的xy.

0 篇笔记 写笔记

作者信息
我爱内核
Windows驱动开发,网站开发
好好学习,天天向上。
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!