常量缓冲区和索引缓冲区

前言

在上篇文章中,我们成功在程序中心渲染了一个三角形。我们创建顶点缓冲区时,我们使用顶点位置直接在投影空间,这样我们就不必执行任何变化,就可以在屏幕上输出。但是我们如果想让物体在D3D中动起来,必须就在每一帧前把顶点缓冲中的数据变成物体动完后再投影空间。但是那样太麻烦了,我们应该输入的就是模型空间的位置,再在着色器中变换位置以造成动画效果。在本篇中,我们了解一些新知识用来实现我们的效果。

修改常量缓冲区

由于我们开始起来,所以我们实际上就进入了3D空间。因此我们将之前的平面三角形更改为3维物体立方体。

// ******************
// 设置立方体顶点
//    5________ 6
//    /|      /|
//   /_|_____/ |
//  1|4|_ _ 2|_|7
//   | /     | /
//   |/______|/
//  0       3
VertexPosCol vertices[] =
{
    { XMFLOAT3(-1.0f, -1.0f, -1.0f), XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f) },
    { XMFLOAT3(-1.0f, 1.0f, -1.0f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) },
    { XMFLOAT3(1.0f, 1.0f, -1.0f), XMFLOAT4(1.0f, 1.0f, 0.0f, 1.0f) },
    { XMFLOAT3(1.0f, -1.0f, -1.0f), XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f) },
    { XMFLOAT3(-1.0f, -1.0f, 1.0f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f) },
    { XMFLOAT3(-1.0f, 1.0f, 1.0f), XMFLOAT4(1.0f, 0.0f, 1.0f, 1.0f) },
    { XMFLOAT3(1.0f, 1.0f, 1.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f) },
    { XMFLOAT3(1.0f, -1.0f, 1.0f), XMFLOAT4(0.0f, 1.0f, 1.0f, 1.0f) }
};

如果你注意到,实际上我知识指定了立方体的8个顶点,我们并没有描述各个三角形。如果我们原样输入,我们是无法得到我们想要的结果的。
在立方体上,许多三角形共享相同的顶点,如果一遍又一遍的定义三角形的顶点将会浪费空间。因此,有一个方法只指定八个点,然后让D3D知道要为三角形选择哪些点。这就是索引缓冲区完成的。

索引缓冲区

使用索引缓冲区代替指定顺序绘制,可以有效减少顶点缓冲区占用的空间。避免提供大量重复的顶点数据。
索引数组初始化

// 索引数组
WORD indices[] = {
    // 正面
    0, 1, 2,
    2, 3, 0,
    // 左面
    4, 5, 1,
    1, 0, 4,
    // 顶面
    1, 5, 6,
    6, 2, 1,
    // 背面
    7, 6, 5,
    5, 4, 7,
    // 右面
    3, 2, 6,
    6, 7, 3,
    // 底面
    4, 0, 3,
    3, 7, 4
};

然后填充缓冲区描述信息并创建索引缓冲区

D3D11_BUFFER_DESC ibd = {};
ibd.Usage = D3D11_USAGE_DEFAULT;
ibd.ByteWidth = sizeof(indices);
ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
ibd.CPUAccessFlags = 0;

D3D11_SUBRESOURCE_DATA initData = {};
initData.pSysMem = indices;

g_pD3D11Device->CreateBuffer(&ibd, &initData, g_pIndiceBuffer.GetAddressOf()))

就像顶点缓冲区一样,我们得到索引缓冲区后,还需要把它绑定到渲染管道上。

void ID3D11DeviceContext::IASetIndexBuffer( 
    ID3D11Buffer *pIndexBuffer,     // [In]索引缓冲区
    DXGI_FORMAT Format,             // [In]数据格式
    UINT Offset);                   // [In]字节偏移量

其中Format
图片说明
所以我们这里示例如下;

    g_pImmediateContext->IASetIndexBuffer(g_pIndiceBuffer.Get(), DXGI_FORMAT_R16_UINT, 0);

修改顶点着色器

我们需要在顶点着色器内完成一个顶点从模型空间转换到