基于 DirectX11 的 MMDViewer 03-渲染管线

时间:2021-11-17 13:49:17

  准备工作:  


  开始搭建框架之前,你需要确保已经进行了 D3D 开发环境的搭建,相关教程可以阅读这篇文章。不了解 DirectX11 的人,这个作者有关 DirectX11 的教程最好阅读一下,虽然文章不多,但都很详细,有了基础以后在进行深一步的扩展。

  和 OpenGL 一样,在渲染出图形之前,都需要经过很多步骤(窗口配置、图形上下文的创建、顶点数据配置、着色器的配置、变换矩阵配置等等),不是一两行代码就可以了。而 DirectX11 则更为复杂,其中如果发生一点错误,将导致图形渲染失败,但你难以检测发生的错误。对于初学者,在你辛辛苦苦编写完渲染代码后,却出现显示不出图形但又不知道哪里出错的情况,那你又能怎么办呢?

  下面给出一个基本的渲染框架(能够渲染出一个旋转正方体),通过在这个框架上进行扩展,开发 MMDViewer 项目。而不是自己编写一个可能有错误的框架,这样会浪费大量时间。

这个框架并不是最简单的框架,但它包括了渲染管线的大部分内容:着色器设置、MVP 变换矩阵设置、裁剪矩形区域(在 GUI 项目常用)、光栅化状态设置、模板测试、深度测试、颜色混合(支持 alpha 通道)。

#include <windows.h>
#include <string> /* 引入 D3D 头文件 */
#include <D3D11.h>
#include <D3DX11.h>
#include <D3Dcompiler.h>
#include <xnamath.h> #pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dx10.lib")
#pragma comment(lib, "d3dx11.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "d3dcompiler.lib") //--------------------------------------------------------------------------------------
// Structures
//--------------------------------------------------------------------------------------
struct SimpleVertex
{
XMFLOAT3 Pos;
XMFLOAT4 Color;
}; struct ConstantBuffer
{
XMMATRIX mWorld;
XMMATRIX mView;
XMMATRIX mProjection;
}; //--------------------------------------------------------------------------------------
// Global Variables
//--------------------------------------------------------------------------------------
HINSTANCE g_hInst = NULL;
HWND g_hWnd = NULL;
D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL;
D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0;
ID3D11Device* g_pd3dDevice = NULL;
ID3D11DeviceContext* g_pImmediateContext = NULL;
IDXGISwapChain* g_pSwapChain = NULL;
ID3D11RenderTargetView* g_pRenderTargetView = NULL;
ID3D11DepthStencilView* g_pDepthStencilView = NULL;
ID3D11VertexShader* g_pVertexShader = NULL;
ID3D11PixelShader* g_pPixelShader = NULL;
ID3D11InputLayout* g_pVertexLayout = NULL;
ID3D11Buffer* g_pVertexBuffer = NULL;
ID3D11Buffer* g_pIndexBuffer = NULL;
ID3D11Buffer* g_pConstantBuffer = NULL;
XMMATRIX g_World;
XMMATRIX g_View;
XMMATRIX g_Projection; //--------------------------------------------------------------------------------------
// Helper for compiling shaders with D3DX11
//--------------------------------------------------------------------------------------
HRESULT CompileShaderFromFile(char* fiel_name, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut)
{
HRESULT hr = S_OK; DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#if defined( DEBUG ) || defined( _DEBUG )
// Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders.
// Setting this flag improves the shader debugging experience, but still allows
// the shaders to be optimized and to run exactly the way they will run in
// the release configuration of this program.
dwShaderFlags |= D3DCOMPILE_DEBUG;
#endif ID3DBlob* pErrorBlob;
hr = D3DX11CompileFromFileA(fiel_name, NULL, NULL, szEntryPoint, szShaderModel, dwShaderFlags, , NULL, ppBlobOut, &pErrorBlob, NULL);
if ( FAILED(hr) )
{
if ( pErrorBlob != NULL )
{
OutputDebugStringA(( char* ) pErrorBlob->GetBufferPointer());
}
if ( pErrorBlob ) pErrorBlob->Release();
return hr;
}
if ( pErrorBlob ) pErrorBlob->Release(); return S_OK;
} //--------------------------------------------------------------------------------------
// Forward declarations
//--------------------------------------------------------------------------------------
HRESULT InitDevice()
{
HRESULT hr = S_OK; RECT rc;
GetClientRect(g_hWnd, &rc);
UINT width = rc.right - rc.left;
UINT height = rc.bottom - rc.top; //----------------------------------------------------------------------------
// 渲染管线设置,创建设备、设备上下文和交换链
//----------------------------------------------------------------------------
/* 设置调试标记,程序退出时也可以显示所有对象的引用数量,可以用于内存泄露检测 */
UINT create_device_flags = ;
#ifdef _DEBUG
create_device_flags |= D3D11_CREATE_DEVICE_DEBUG;
#endif D3D_DRIVER_TYPE driver_types[] =
{
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE,
};
UINT num_driver_types = ARRAYSIZE(driver_types); D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
};
UINT numFeatureLevels = ARRAYSIZE(featureLevels); DXGI_SWAP_CHAIN_DESC swap_desc;
ZeroMemory(&swap_desc, sizeof(swap_desc));
swap_desc.BufferCount = ;
swap_desc.BufferDesc.Width = width;
swap_desc.BufferDesc.Height = height;
swap_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swap_desc.BufferDesc.RefreshRate.Numerator = ;
swap_desc.BufferDesc.RefreshRate.Denominator = ;
swap_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_desc.OutputWindow = g_hWnd;
swap_desc.SampleDesc.Count = ;
swap_desc.SampleDesc.Quality = ;
swap_desc.Windowed = TRUE; for ( UINT driver_type_index = ; driver_type_index < num_driver_types; driver_type_index++ )
{
g_driverType = driver_types[driver_type_index];
hr = D3D11CreateDeviceAndSwapChain(NULL, g_driverType, NULL, create_device_flags, featureLevels, numFeatureLevels,
D3D11_SDK_VERSION, &swap_desc, &g_pSwapChain, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext);
if ( SUCCEEDED(hr) ) break;
}
if ( FAILED(hr) ) return hr; //----------------------------------------------------------------------------
// 渲染管线输出设置
//----------------------------------------------------------------------------
/* 获取交换链的后缓冲 */
ID3D11Texture2D* pBackBuffer = NULL;
hr = g_pSwapChain->GetBuffer(, __uuidof(ID3D11Texture2D), ( LPVOID* ) &pBackBuffer);
if ( FAILED(hr) ) return hr; /* 创建渲染目标视图 */
hr = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_pRenderTargetView);
pBackBuffer->Release();
if ( FAILED(hr) ) return hr; /* 设置视口 */
D3D11_VIEWPORT view_port;
view_port.Width = ( FLOAT ) width;
view_port.Height = ( FLOAT ) height;
view_port.MinDepth = 0.0f;
view_port.MaxDepth = 1.0f;
view_port.TopLeftX = ;
view_port.TopLeftY = ;
g_pImmediateContext->RSSetViewports(, &view_port); //----------------------------------------------------------------------------
// 渲染管线输入数据
//----------------------------------------------------------------------------
/* 顶点缓冲区 */
SimpleVertex vertices[] =
{
{ XMFLOAT3(-0.5f, 0.5f, 0.5f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) },
{ XMFLOAT3(0.5f, 0.5f, 0.5f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) },
{ XMFLOAT3(0.5f, -0.5f, 0.5f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) },
{ XMFLOAT3(-0.5f, -0.5f, 0.5f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) },
{ XMFLOAT3(-0.5f, 0.5f, -0.5f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f) },
{ XMFLOAT3(0.5f, 0.5f, -0.5f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f) },
{ XMFLOAT3(0.5f, -0.5f, -0.5f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f) },
{ XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f) }
};
D3D11_BUFFER_DESC vertex_desc;
vertex_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertex_desc.ByteWidth = sizeof( SimpleVertex ) * ;
vertex_desc.CPUAccessFlags = ;
vertex_desc.MiscFlags = ;
vertex_desc.StructureByteStride = ;
vertex_desc.Usage = D3D11_USAGE_DEFAULT; D3D11_SUBRESOURCE_DATA vertex_data;
vertex_data.pSysMem = vertices;
vertex_data.SysMemPitch = ;
vertex_data.SysMemSlicePitch = ;
hr = g_pd3dDevice->CreateBuffer(&vertex_desc, &vertex_data, &g_pVertexBuffer);
if ( FAILED(hr) ) return hr; /* 索引缓冲区 */
UINT indices[] = {
, , , , , , // 前面
, , , , , , // 上面
, , , , , , // 下面
, , , , , , // 后面
, , , , , , // 右面
, , , , , // 左面
};
D3D11_BUFFER_DESC index_desc;
index_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
index_desc.ByteWidth = sizeof( UINT ) * ;
index_desc.MiscFlags = ;
index_desc.CPUAccessFlags = ;
index_desc.StructureByteStride = ;
index_desc.Usage = D3D11_USAGE_DEFAULT; D3D11_SUBRESOURCE_DATA index_data;
index_data.pSysMem = indices;
index_data.SysMemPitch = ;
index_data.SysMemSlicePitch = ;
hr = g_pd3dDevice->CreateBuffer(&index_desc, &index_data, &g_pIndexBuffer);
if ( FAILED(hr) ) return hr; /* 设置顶点缓冲区 */
UINT stride = sizeof(SimpleVertex);
UINT offset = ;
g_pImmediateContext->IASetVertexBuffers(, , &g_pVertexBuffer, &stride, &offset);
g_pImmediateContext->IASetIndexBuffer(g_pIndexBuffer, DXGI_FORMAT_R32_UINT, ); /* 设置图元 */
g_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); //----------------------------------------------------------------------------
// 着色器设置
//----------------------------------------------------------------------------
/* 编译顶点着色器 */
ID3DBlob* pVSBlob = NULL;
hr = CompileShaderFromFile("shader.hlsl", "VS", "vs_5_0", &pVSBlob);
if ( FAILED(hr) )
{
MessageBox(NULL, L"不能编译着色程序", L"Error", MB_OK); return hr;
} /* 创建顶点着色器 */
hr = g_pd3dDevice->CreateVertexShader(pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &g_pVertexShader);
if ( FAILED(hr) )
{
pVSBlob->Release(); return hr;
} D3D11_INPUT_ELEMENT_DESC layout[] =
{
{ "POSITION", , DXGI_FORMAT_R32G32B32_FLOAT, , , D3D11_INPUT_PER_VERTEX_DATA, },
{ "COLOR", , DXGI_FORMAT_R32G32B32A32_FLOAT, , , D3D11_INPUT_PER_VERTEX_DATA, },
};
UINT numElements = ARRAYSIZE(layout); /* 创建输入布局 */
hr = g_pd3dDevice->CreateInputLayout(layout, numElements, pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), &g_pVertexLayout);
pVSBlob->Release();
if ( FAILED(hr) ) return hr; /* 设置输入布局 */
g_pImmediateContext->IASetInputLayout(g_pVertexLayout); /* 编译像素着色器 */
ID3DBlob* pPSBlob = NULL;
hr = CompileShaderFromFile("shader.hlsl", "PS", "ps_5_0", &pPSBlob);
if ( FAILED(hr) )
{
MessageBox(NULL, L"不能编译着色程序", L"Error", MB_OK); return hr;
} /* 创建像素着色器 */
hr = g_pd3dDevice->CreatePixelShader(pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &g_pPixelShader);
pPSBlob->Release();
if ( FAILED(hr) ) return hr; //----------------------------------------------------------------------------
// 光栅化状态
//----------------------------------------------------------------------------
ID3D11RasterizerState* rasterater_state = nullptr;
D3D11_RASTERIZER_DESC rasterizer_desc;
ZeroMemory(&rasterizer_desc, sizeof(rasterizer_desc)); rasterizer_desc.CullMode = D3D11_CULL_BACK; // 背面剔除
rasterizer_desc.FillMode = D3D11_FILL_SOLID; // 填充由顶点形成的三角形
rasterizer_desc.ScissorEnable = true; // 开启裁剪
rasterizer_desc.FrontCounterClockwise = false; // 顺时针为正方向
hr = g_pd3dDevice->CreateRasterizerState(&rasterizer_desc, &rasterater_state);
if ( FAILED(hr) ) return hr; g_pImmediateContext->RSSetState(rasterater_state);
rasterater_state->Release(); /* 设置裁剪矩形,这里仅设置和窗口大小一样,所以没有效果 */
D3D11_RECT scissor = { /* left */, /* top */, /* right */, /* bottom */ };
g_pImmediateContext->RSSetScissorRects(, &scissor); //----------------------------------------------------------------------------
// 模板测试和深度测试
//----------------------------------------------------------------------------
ID3D11Texture2D* depth_stencil_tex = nullptr;
D3D11_TEXTURE2D_DESC depth_stencil_tex_desc;
ZeroMemory(&depth_stencil_tex_desc, sizeof(depth_stencil_tex_desc)); depth_stencil_tex_desc.Width = width;
depth_stencil_tex_desc.Height = height;
depth_stencil_tex_desc.MipLevels = ;
depth_stencil_tex_desc.ArraySize = ;
depth_stencil_tex_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depth_stencil_tex_desc.SampleDesc.Count = ;
depth_stencil_tex_desc.SampleDesc.Quality = ;
depth_stencil_tex_desc.Usage = D3D11_USAGE_DEFAULT;
depth_stencil_tex_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depth_stencil_tex_desc.MiscFlags = ;
depth_stencil_tex_desc.CPUAccessFlags = ;
hr = g_pd3dDevice->CreateTexture2D(&depth_stencil_tex_desc, , &depth_stencil_tex);
if ( FAILED(hr) ) return hr; hr = g_pd3dDevice->CreateDepthStencilView(depth_stencil_tex, , &g_pDepthStencilView);
if ( FAILED(hr) ) return hr; /* 设置深度、模板视图到渲染管线 */
g_pImmediateContext->OMSetRenderTargets(, &g_pRenderTargetView, g_pDepthStencilView);
depth_stencil_tex->Release(); /* 设置深度、模板状态到渲染管线 */
ID3D11DepthStencilState* depth_stencil_state = nullptr;
D3D11_DEPTH_STENCIL_DESC depth_stencil_desc;
ZeroMemory(&depth_stencil_desc, sizeof(depth_stencil_desc)); depth_stencil_desc.DepthEnable = TRUE;
depth_stencil_desc.DepthFunc = D3D11_COMPARISON_FUNC::D3D11_COMPARISON_LESS;
depth_stencil_desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK::D3D11_DEPTH_WRITE_MASK_ALL;
depth_stencil_desc.StencilEnable = FALSE;
depth_stencil_desc.FrontFace.StencilFunc = D3D11_COMPARISON_FUNC::D3D11_COMPARISON_ALWAYS;
depth_stencil_desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP::D3D11_STENCIL_OP_KEEP;
depth_stencil_desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP::D3D11_STENCIL_OP_KEEP;
depth_stencil_desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP::D3D11_STENCIL_OP_KEEP;
depth_stencil_desc.BackFace = depth_stencil_desc.FrontFace;
depth_stencil_desc.StencilReadMask = 0xFF;
depth_stencil_desc.StencilWriteMask = 0xFF;
hr = g_pd3dDevice->CreateDepthStencilState(&depth_stencil_desc, &depth_stencil_state);
if ( FAILED(hr) ) return hr; g_pImmediateContext->OMSetDepthStencilState(depth_stencil_state, );
depth_stencil_state->Release(); //----------------------------------------------------------------------------
// 颜色混合
//----------------------------------------------------------------------------
D3D11_BLEND_DESC blend_desc;
ZeroMemory(&blend_desc, sizeof(blend_desc)); blend_desc.AlphaToCoverageEnable = false;
blend_desc.IndependentBlendEnable = false; // 是否使用多个目标渲染视图
blend_desc.RenderTarget[].BlendEnable = true;
blend_desc.RenderTarget[].BlendOp = D3D11_BLEND_OP::D3D11_BLEND_OP_ADD;
blend_desc.RenderTarget[].BlendOpAlpha = D3D11_BLEND_OP::D3D11_BLEND_OP_ADD;
blend_desc.RenderTarget[].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blend_desc.RenderTarget[].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
blend_desc.RenderTarget[].SrcBlendAlpha = D3D11_BLEND_ONE;
blend_desc.RenderTarget[].DestBlendAlpha = D3D11_BLEND_ZERO;
blend_desc.RenderTarget[].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; ID3D11BlendState* blend_state = nullptr;
hr = g_pd3dDevice->CreateBlendState(&blend_desc, &blend_state);
if ( FAILED(hr) ) return hr; const float blend_factor[] = { , , , };
g_pImmediateContext->OMSetBlendState(blend_state, blend_factor, 0xFFFFFFFF);
blend_state->Release(); //----------------------------------------------------------------------------
// 视图矩阵和投影矩阵
//----------------------------------------------------------------------------
D3D11_BUFFER_DESC constant_desc;
constant_desc.Usage = D3D11_USAGE_DEFAULT;
constant_desc.ByteWidth = sizeof(ConstantBuffer);
constant_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
constant_desc.CPUAccessFlags = ;
constant_desc.MiscFlags = ;
constant_desc.StructureByteStride = ;
hr = g_pd3dDevice->CreateBuffer(&constant_desc, NULL, &g_pConstantBuffer);
if ( FAILED(hr) ) return hr; /* 初始化世界矩阵 */
g_World = XMMatrixIdentity(); /* 初始化视图矩阵 */
XMVECTOR eye = XMVectorSet(1.0f, 1.0f, -1.5f, 0.0f);
XMVECTOR at = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
g_View = XMMatrixLookAtLH(eye, at, up); /* 初始化投影矩阵 */
g_Projection = XMMatrixPerspectiveFovLH(XM_PIDIV2, width / ( FLOAT ) height, 0.01f, 100.0f); return S_OK;
} void CleanupDevice()
{
if ( g_pImmediateContext ) g_pImmediateContext->ClearState(); if ( g_pVertexBuffer ) g_pVertexBuffer->Release();
if ( g_pIndexBuffer ) g_pIndexBuffer->Release();
if ( g_pVertexLayout ) g_pVertexLayout->Release();
if ( g_pVertexShader ) g_pVertexShader->Release();
if ( g_pPixelShader ) g_pPixelShader->Release();
if ( g_pConstantBuffer ) g_pConstantBuffer->Release();
if ( g_pRenderTargetView ) g_pRenderTargetView->Release();
if ( g_pDepthStencilView ) g_pDepthStencilView->Release();
if ( g_pSwapChain ) g_pSwapChain->Release();
if ( g_pImmediateContext ) g_pImmediateContext->Release();
if ( g_pd3dDevice ) g_pd3dDevice->Release();
} void Render()
{
//----------------------------------------------------------------------------
// 旋转正方体
//----------------------------------------------------------------------------
/* 更新时间 */
static float t = 0.0f;
if ( g_driverType == D3D_DRIVER_TYPE_REFERENCE )
{
t += ( float ) XM_PI * 0.0125f;
}
else
{
static DWORD dwTimeStart = ;
DWORD dwTimeCur = GetTickCount();
if ( dwTimeStart == )
{
dwTimeStart = dwTimeCur;
}
t = (dwTimeCur - dwTimeStart) / 1000.0f;
}
/* 更新世界矩阵,使正方体旋转 */
g_World = XMMatrixRotationY(t); //----------------------------------------------------------------------------
// 渲染
//----------------------------------------------------------------------------
/* 清空后缓冲 */
float ClearColor[] = { 0.0f, 0.125f, 0.3f, 1.0f };
g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, ClearColor);
g_pImmediateContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, ); /* 更新常量缓冲区数据 */
ConstantBuffer cb;
cb.mView = XMMatrixTranspose(g_View);
cb.mWorld = XMMatrixTranspose(g_World);
cb.mProjection = XMMatrixTranspose(g_Projection);
g_pImmediateContext->UpdateSubresource(g_pConstantBuffer, , NULL, &cb, , ); /* 渲染三角形 */
g_pImmediateContext->VSSetShader(g_pVertexShader, NULL, );
g_pImmediateContext->PSSetShader(g_pPixelShader, NULL, );
g_pImmediateContext->VSSetConstantBuffers(, , &g_pConstantBuffer);
g_pImmediateContext->DrawIndexed(, , ); g_pSwapChain->Present(, );
} /* 窗口事件处理回调函数 */
LRESULT CALLBACK WindowProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch ( msg )
{
case WM_CLOSE:
case WM_DESTROY:
PostQuitMessage();
break;
case WM_PAINT:
RECT rect;
if ( GetUpdateRect(wnd, &rect, FALSE) )
{
ValidateRect(wnd, &rect);
}
break;
}
return DefWindowProc(wnd, msg, wParam, lParam);
} /* 创建窗口并返回句柄 */
HWND Create()
{
/* 设计窗口类 */
WNDCLASS wndclass;
memset(&wndclass, , sizeof(WNDCLASSA)); wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wndclass.lpfnWndProc = ( WNDPROC ) WindowProc;
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
wndclass.hInstance = ( HINSTANCE ) GetModuleHandle();
wndclass.hIcon = ;
wndclass.hCursor = ;
wndclass.hbrBackground = CreateSolidBrush(RGB(, , ));
wndclass.lpszMenuName = ;
wndclass.lpszClassName = L"MMDViewer"; /* 注册窗口类 */
RegisterClass(&wndclass); /* 不能改变窗口大小 */
int style = WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX; /* 根据客户区大小计算窗口大小 */
RECT rect = { , , , };
AdjustWindowRect(&rect, style, ); /* 居中显示计算窗口位置和大小 */
int w = rect.right - rect.left;
int h = rect.bottom - rect.top;
int x = (GetSystemMetrics(SM_CXSCREEN) - w) / ;
int y = (GetSystemMetrics(SM_CYSCREEN) - h) / ; /* 创建窗口 */
HWND hwnd = CreateWindow(L"MMDViewer", L"MMDViewer", style, x, y, w, h, NULL, , ( HINSTANCE ) GetModuleHandle(), ); /* 显示窗口 */
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd); return hwnd;
} int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine); g_hWnd = Create(); if ( FAILED(InitDevice()) )
{
CleanupDevice();
return ;
} /* 主事件循环 */
MSG msg = { };
while ( WM_QUIT != msg.message )
{
if ( PeekMessage(&msg, NULL, , , PM_REMOVE) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Render();
} CleanupDevice();
return ;
}

  Shader 代码:

//--------------------------------------------------------------------------------------
// Constant Buffer Variables
//--------------------------------------------------------------------------------------
cbuffer ConstantBuffer : register( b0 )
{
matrix World;
matrix View;
matrix Projection;
} //--------------------------------------------------------------------------------------
struct VS_OUTPUT
{
float4 Pos : SV_POSITION;
float4 Color : COLOR0;
}; //--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
VS_OUTPUT VS( float4 Pos : POSITION, float4 Color : COLOR )
{
VS_OUTPUT output = (VS_OUTPUT);
output.Pos = mul( Pos, World );
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
output.Color = Color;
return output;
} //--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PS( VS_OUTPUT input ) : SV_Target
{
return input.Color;
}

  配置好相关的库后,运行程序,你会看到一个旋转的三角形:

基于 DirectX11 的 MMDViewer 03-渲染管线

  渲染管线:


  渲染管线就是将 3D 图像转换成 2D 图像输出到屏幕的过程,所以你要进行渲染操作就要使用渲染管线。那么渲染管线在哪呢?有如何创建渲染管线呢?渲染管线的渲染结果如何输出到你创建的窗口呢?

  为此需要关注三个对象:设备(ID3D11Device)、设备上下文(ID3D11DeviceContext)和交换链(IDXGISwapChain),这三者和渲染管线有以下关系:

  1、设备(ID3D11Device):用于分配GPU资源,如缓冲,纹理,着色器和状态对象(仅举几例),从框架代码中可以看出,基本上都是 CreateXX() 函数。

  2、设备上下文(ID3D11DeviceContext):你可以将它理解成渲染管线,用于设置管线状态、将资源绑定到渲染管线和生成渲染命令。

  3、交换链(IDXGISwapChain):渲染管线和你创建的窗口间的桥梁,将窗口句柄和交换链绑定,渲染管线输出到交换链的后缓冲,最后呈现到窗口上。

  通过调用函数 D3D11CreateDeviceAndSwapChain() 就可以一次性创建这三个对象。下图为渲染管线过程:

基于 DirectX11 的 MMDViewer 03-渲染管线

   结语:

  这篇文章简要说明一下渲染管线,接下来将介绍框架源码中的内容。

  源码下载:MMDViewer 03.zip