渲染流水线的各个阶段
必须初始化的3个组件
ID3D11Device(设备):该设备包含创建资源的方法
ID3D11DeviceContext(上下文):主要用于在缓冲区执行渲染
IDXGISwapChain(交换链):将后台缓存与前台缓存交换,在显示器上显示
创建目标视图和深度模板视图
assert(m_pImmediateContext);
assert(m_pd3dDevice);
assert(m_pSwapChain);
ReleaseCOM(m_pRenderTargetView);
ReleaseCOM(m_pDepthStencilView);
ReleaseCOM(m_pDepthStencil);
//创建渲染目标视图
HR(m_pSwapChain->ResizeBuffers(1, m_Width, m_Height, DXGI_FORMAT_R8G8B8A8_UNORM, 0));
ID3D11Texture2D* backBuffer;
HR(m_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&backBuffer)));
HR(m_pd3dDevice->CreateRenderTargetView(backBuffer, 0, &m_pRenderTargetView));
ReleaseCOM(backBuffer);
//深度模板视图
D3D11_TEXTURE2D_DESC depthStencilDesc;
depthStencilDesc.Width = m_Width;
depthStencilDesc.Height = m_Height;
depthStencilDesc.MipLevels = 1;
depthStencilDesc.ArraySize = 1;
depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthStencilDesc.SampleDesc.Count = 1;
depthStencilDesc.SampleDesc.Quality = 0;
depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depthStencilDesc.CPUAccessFlags = 0;
depthStencilDesc.MiscFlags = 0;
HR(m_pd3dDevice->CreateTexture2D(&depthStencilDesc, 0, &m_pDepthStencil));
HR(m_pd3dDevice->CreateDepthStencilView(m_pDepthStencil, 0, &m_pDepthStencilView));
m_pImmediateContext->OMSetRenderTargets(1, &m_pRenderTargetView, m_pDepthStencilView);
//设置视口
m_ScreenViewport.TopLeftX = 0;
m_ScreenViewport.TopLeftY = 0;
m_ScreenViewport.Width = static_cast<float>(m_Width);
m_ScreenViewport.Height = static_cast<float>(m_Height);
m_ScreenViewport.MinDepth = 0.0f;
m_ScreenViewport.MaxDepth = 1.0f;
m_pImmediateContext->RSSetViewports(1, &m_ScreenViewport);
创建顶点布局
const D3D11_INPUT_ELEMENT_DESC InputLayoutDesc::Basic32[3] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
ID3D11InputLayout* InputLayouts::Basic32 = 0;
void InputLayouts::InitAll(ID3D11Device* device)
{
D3DX11_PASS_DESC passDesc;
Effects::FX->Light1TexTech->GetPassByIndex(0)->GetDesc(&passDesc);
HR(device->CreateInputLayout(InputLayoutDesc::Basic32, 3, passDesc.pIAInputSignature,
passDesc.IAInputSignatureSize, &Basic32));
}
创建顶点和索引
Vertex::Basic32 v[24];
float w2 = 1.0f*1;
float h2 = 1.0f*1;
float d2 = 1.0f*1;
v[0] = { { -w2, -h2, -d2 }, { 0.0f, 0.0f, -1.0f }, { 0.0f, 1.0f } };
v[1] = { { -w2, +h2, -d2 }, { 0.0f, 0.0f, -1.0f }, { 0.0f, 0.0f } };
v[2] = { { +w2, +h2, -d2 }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 0.0f } };
v[3] = { { +w2, -h2, -d2 }, { 0.0f, 0.0f, -1.0f }, { 1.0f, 1.0f } };
// Fill in the back face vertex data.
v[4] = { { -w2, -h2, +d2 }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f } };
v[5] = { { +w2, -h2, +d2 }, { 0.0f, 0.0f, 1.0f }, { 0.0f, 1.0f } };
v[6] = { { +w2, +h2, +d2 }, { 0.0f, 0.0f, 1.0f }, { 0.0f, 0.0f } };
v[7] = { { -w2, +h2, +d2 }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 0.0f } };
// Fill in the top face vertex data.
v[8] = { { -w2, +h2, -d2 }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 1.0f } };
v[9] = { { -w2, +h2, +d2 }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f } };
v[10] = { { +w2, +h2, +d2 }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 0.0f } };
v[11] = { { +w2, +h2, -d2 }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f } };
// Fill in the bottom face vertex data.
v[12] = { { -w2, -h2, -d2 }, { 0.0f, -1.0f, 0.0f }, { 1.0f, 1.0f } };
v[13] = { { +w2, -h2, -d2 }, { 0.0f, -1.0f, 0.0f }, { 0.0f, 1.0f } };
v[14] = { { +w2, -h2, +d2 }, { 0.0f, -1.0f, 0.0f }, { 0.0f, 0.0f } };
v[15] = { { -w2, -h2, +d2 }, { 0.0f, -1.0f, 0.0f }, { 1.0f, 0.0f } };
// Fill in the left face vertex data.
v[16] = { { -w2, -h2, +d2 }, { -1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f } };
v[17] = { { -w2, +h2, +d2 }, { -1.0f, 0.0f, 0.0f }, { 0.0f, 0.0f } };
v[18] = { { -w2, +h2, -d2 }, { -1.0f, 0.0f, 0.0f }, { 1.0f, 0.0f } };
v[19] = { { -w2, -h2, -d2 }, { -1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f } };
// Fill in the right face vertex data.
v[20] = { { +w2, -h2, -d2 }, { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f } };
v[21] = { { +w2, +h2, -d2 }, { 1.0f, 0.0f, 0.0f }, { 0.0f, 0.0f } };
v[22] = { { +w2, +h2, +d2 }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 0.0f } };
v[23] = { { +w2, -h2, +d2 }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f } };
D3D11_BUFFER_DESC vbd;
vbd.Usage = D3D11_USAGE_IMMUTABLE;
vbd.ByteWidth = sizeof(Vertex::Basic32)* 24;
vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vbd.CPUAccessFlags = 0;
vbd.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA vinitData;
vinitData.pSysMem = &v[0];
HR(m_pd3dDevice->CreateBuffer(&vbd, &vinitData, &m_VB));
UINT i[36];
// Fill in the front face index data
i[0] = 0; i[1] = 1; i[2] = 2;
i[3] = 0; i[4] = 2; i[5] = 3;
// Fill in the back face index data
i[6] = 4; i[7] = 5; i[8] = 6;
i[9] = 4; i[10] = 6; i[11] = 7;
// Fill in the top face index data
i[12] = 8; i[13] = 9; i[14] = 10;
i[15] = 8; i[16] = 10; i[17] = 11;
// Fill in the bottom face index data
i[18] = 12; i[19] = 13; i[20] = 14;
i[21] = 12; i[22] = 14; i[23] = 15;
// Fill in the left face index data
i[24] = 16; i[25] = 17; i[26] = 18;
i[27] = 16; i[28] = 18; i[29] = 19;
// Fill in the right face index data
i[30] = 20; i[31] = 21; i[32] = 22;
i[33] = 20; i[34] = 22; i[35] = 23;
D3D11_BUFFER_DESC ibd;
ibd.Usage = D3D11_USAGE_IMMUTABLE;
ibd.ByteWidth = sizeof(UINT)* 36;
ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
ibd.CPUAccessFlags = 0;
ibd.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA iinitData;
iinitData.pSysMem = &i[0];
HR(m_pd3dDevice->CreateBuffer(&ibd, &iinitData, &m_IB));
在Render函数中
//先请屏
float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
m_pImmediateContext->ClearRenderTargetView(m_pRenderTargetView, color);
m_pImmediateContext->ClearDepthStencilView(m_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
//设置输入布局和拓扑结构
m_pImmediateContext->IASetInputLayout(InputLayouts::Basic32);
m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
//设置顶点和索引
UINT stride = sizeof(Vertex::Basic32);
UINT offset = 0;
m_pImmediateContext->IASetVertexBuffers(0, 1, &m_VB, &stride, &offset);
m_pImmediateContext->IASetIndexBuffer(m_IB, DXGI_FORMAT_R32_UINT, 0);
//设置变换矩阵
XMMATRIX view = XMLoadFloat4x4(&m_View);
XMMATRIX proj = XMLoadFloat4x4(&m_Proj);
XMMATRIX world = XMLoadFloat4x4(&m_BoxWorld);
XMMATRIX worldViewProj = world*view*proj;
//设置材质
Material Mat;
Mat.Ambient = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f);
Mat.Diffuse = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
Mat.Specular = XMFLOAT4(0.6f, 0.6f, 0.6f, 16.0f);
//设置观察的位置,用于计算镜面高光
XMFLOAT3 mEyePosW = XMFLOAT3(-2.3f, 5.06f, -19.0f);
//方向光源
DirectionalLight mDirLights[3];
mDirLights[0].Ambient = XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f);
mDirLights[0].Diffuse = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f);
mDirLights[0].Specular = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f);
mDirLights[0].Direction = XMFLOAT3(0.57735f, -0.57735f, 0.57735f);
mDirLights[1].Ambient = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f);
mDirLights[1].Diffuse = XMFLOAT4(0.20f, 0.20f, 0.20f, 1.0f);
mDirLights[1].Specular = XMFLOAT4(0.25f, 0.25f, 0.25f, 1.0f);
mDirLights[1].Direction = XMFLOAT3(-0.57735f, -0.57735f, 0.57735f);
mDirLights[2].Ambient = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f);
mDirLights[2].Diffuse = XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f);
mDirLights[2].Specular = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f);
mDirLights[2].Direction = XMFLOAT3(0.0f, -0.707f, -0.707f);
//设置GPU的常量缓冲
Effects::FX->SetDirLights(mDirLights);
Effects::FX->SetEyePosW(mEyePosW);
XMFLOAT4X4 mTexTransform;
XMMATRIX I = XMMatrixIdentity();
XMStoreFloat4x4(&mTexTransform, I);
D3DX11_TECHNIQUE_DESC techDesc;
Effects::FX->Light3TexTech->GetDesc(&techDesc);
for (UINT p = 0; p < techDesc.Passes; ++p)
{
world = XMLoadFloat4x4(&m_BoxWorld);
XMMATRIX worldInvTranspose = MathHelper::InverseTranspose(world);
worldViewProj = world*view*proj;
Effects::FX->SetWorld(world);
Effects::FX->SetWorldInvTranspose(worldInvTranspose);
Effects::FX->SetWorldViewProj(worldViewProj);
Effects::FX->SetTexTransform(XMLoadFloat4x4(&mTexTransform));
Effects::FX->SetMaterial(Mat);
Effects::FX->SetDiffuseMap(m_DiffuseMapSRV);
//将设置的常量缓冲和纹理贴图传送给GPU
Effects::FX->Light3TexTech->GetPassByIndex(p)->Apply(0, m_pImmediateContext);
//绘制
m_pImmediateContext->DrawIndexed(36, 0, 0);
}
//将前台缓冲和后台缓冲交换,显示图像
HR(m_pSwapChain->Present(0, 0));
初始化和创建各种D3D11资源后。1
每帧基本上就是清屏和清除深度模板缓存。2
设置输入布局和拓扑结构 3
设置输入顶点 4
设置光栅化状态设置Shader,将相应的常量缓冲或纹理贴图输送给GPU 5
GPU完成绘制 6
3 - 6的步骤应该就是所谓的一次draw call(个人理解)
一些设置方法如果当前draw call没有设置(如光栅化状态, 输入布局, 拓扑结构等)应该使用的是上一次的设置。
以上是Introdution to 3D programming with DirectX 11里的一个例子
可以去这里下载完整例子
上图就是光照和纹理映射,主要实现都在Shader里完成。光照和纹理映射的软件实现在之前的软件光栅化 五
十张里有差不多的实现。