1. 程式人生 > >基於 DirectX11 的 MMDViewer 03-渲染管線(1)

基於 DirectX11 的 MMDViewer 03-渲染管線(1)

present esc ren 調用 param directx11 回調函數 hicon 文章

  準備工作:  


  開始搭建框架之前,你需要確保已經進行了 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, 0, 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 = 0; #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 = 1; swap_desc.BufferDesc.Width = width; swap_desc.BufferDesc.Height = height; swap_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swap_desc.BufferDesc.RefreshRate.Numerator = 60; swap_desc.BufferDesc.RefreshRate.Denominator = 1; swap_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swap_desc.OutputWindow = g_hWnd; swap_desc.SampleDesc.Count = 1; swap_desc.SampleDesc.Quality = 0; swap_desc.Windowed = TRUE; for ( UINT driver_type_index = 0; 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(0, __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 = 0; view_port.TopLeftY = 0; g_pImmediateContext->RSSetViewports(1, &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 ) * 8; vertex_desc.CPUAccessFlags = 0; vertex_desc.MiscFlags = 0; vertex_desc.StructureByteStride = 0; vertex_desc.Usage = D3D11_USAGE_DEFAULT; D3D11_SUBRESOURCE_DATA vertex_data; vertex_data.pSysMem = vertices; vertex_data.SysMemPitch = 0; vertex_data.SysMemSlicePitch = 0; hr = g_pd3dDevice->CreateBuffer(&vertex_desc, &vertex_data, &g_pVertexBuffer); if ( FAILED(hr) ) return hr; /* 索引緩沖區 */ UINT indices[] = { 7, 4, 5, 7, 5, 6, // 前面 4, 0, 1, 4, 1, 5, // 上面 3, 7, 6, 3, 6, 2, // 下面 2, 1, 0, 2, 0, 3, // 後面 6, 5, 1, 6, 1, 2, // 右面 3, 0, 4, 3, 4, 7 // 左面 }; D3D11_BUFFER_DESC index_desc; index_desc.BindFlags = D3D11_BIND_INDEX_BUFFER; index_desc.ByteWidth = sizeof( UINT ) * 36; index_desc.MiscFlags = 0; index_desc.CPUAccessFlags = 0; index_desc.StructureByteStride = 0; index_desc.Usage = D3D11_USAGE_DEFAULT; D3D11_SUBRESOURCE_DATA index_data; index_data.pSysMem = indices; index_data.SysMemPitch = 0; index_data.SysMemSlicePitch = 0; hr = g_pd3dDevice->CreateBuffer(&index_desc, &index_data, &g_pIndexBuffer); if ( FAILED(hr) ) return hr; /* 設置頂點緩沖區 */ UINT stride = sizeof(SimpleVertex); UINT offset = 0; g_pImmediateContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &offset); g_pImmediateContext->IASetIndexBuffer(g_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0); /* 設置圖元 */ 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", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; 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 = { 0 /* left */, 0 /* top */, 800 /* right */, 600 /* bottom */ }; g_pImmediateContext->RSSetScissorRects(1, &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 = 1; depth_stencil_tex_desc.ArraySize = 1; depth_stencil_tex_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; depth_stencil_tex_desc.SampleDesc.Count = 1; depth_stencil_tex_desc.SampleDesc.Quality = 0; depth_stencil_tex_desc.Usage = D3D11_USAGE_DEFAULT; depth_stencil_tex_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; depth_stencil_tex_desc.MiscFlags = 0; depth_stencil_tex_desc.CPUAccessFlags = 0; hr = g_pd3dDevice->CreateTexture2D(&depth_stencil_tex_desc, 0, &depth_stencil_tex); if ( FAILED(hr) ) return hr; hr = g_pd3dDevice->CreateDepthStencilView(depth_stencil_tex, 0, &g_pDepthStencilView); if ( FAILED(hr) ) return hr; /* 設置深度、模板視圖到渲染管線 */ g_pImmediateContext->OMSetRenderTargets(1, &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, 1); 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[0].BlendEnable = true; blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP::D3D11_BLEND_OP_ADD; blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP::D3D11_BLEND_OP_ADD; blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; blend_desc.RenderTarget[0].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[4] = { 1, 1, 1, 1 }; 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 = 0; constant_desc.MiscFlags = 0; constant_desc.StructureByteStride = 0; 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 = 0; DWORD dwTimeCur = GetTickCount(); if ( dwTimeStart == 0 ) { dwTimeStart = dwTimeCur; } t = (dwTimeCur - dwTimeStart) / 1000.0f; } /* 更新世界矩陣,使正方體旋轉 */ g_World = XMMatrixRotationY(t); //---------------------------------------------------------------------------- // 渲染 //---------------------------------------------------------------------------- /* 清空後緩沖 */ float ClearColor[4] = { 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, 0); /* 更新常量緩沖區數據 */ ConstantBuffer cb; cb.mView = XMMatrixTranspose(g_View); cb.mWorld = XMMatrixTranspose(g_World); cb.mProjection = XMMatrixTranspose(g_Projection); g_pImmediateContext->UpdateSubresource(g_pConstantBuffer, 0, NULL, &cb, 0, 0); /* 渲染三角形 */ g_pImmediateContext->VSSetShader(g_pVertexShader, NULL, 0); g_pImmediateContext->PSSetShader(g_pPixelShader, NULL, 0); g_pImmediateContext->VSSetConstantBuffers(0, 1, &g_pConstantBuffer); g_pImmediateContext->DrawIndexed(36, 0, 0); g_pSwapChain->Present(1, 0); } /* 窗口事件處理回調函數 */ LRESULT CALLBACK WindowProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch ( msg ) { case WM_CLOSE: case WM_DESTROY: PostQuitMessage(0); 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, 0, sizeof(WNDCLASSA)); wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wndclass.lpfnWndProc = ( WNDPROC ) WindowProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = ( HINSTANCE ) GetModuleHandle(0); wndclass.hIcon = 0; wndclass.hCursor = 0; wndclass.hbrBackground = CreateSolidBrush(RGB(255, 255, 255)); wndclass.lpszMenuName = 0; wndclass.lpszClassName = L"MMDViewer"; /* 註冊窗口類 */ RegisterClass(&wndclass); /* 不能改變窗口大小 */ int style = WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX; /* 根據客戶區大小計算窗口大小 */ RECT rect = { 0, 0, 800, 600 }; AdjustWindowRect(&rect, style, 0); /* 居中顯示計算窗口位置和大小 */ int w = rect.right - rect.left; int h = rect.bottom - rect.top; int x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2; int y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2; /* 創建窗口 */ HWND hwnd = CreateWindow(L"MMDViewer", L"MMDViewer", style, x, y, w, h, NULL, 0, ( HINSTANCE ) GetModuleHandle(0), 0); /* 顯示窗口 */ 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 0; } /* 主事件循環 */ MSG msg = { 0 }; while ( WM_QUIT != msg.message ) { if ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) { TranslateMessage(&msg); DispatchMessage(&msg); } Render(); } CleanupDevice(); return 0; }

  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)0;
    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;
}

  配置好相關的庫後,運行程序,你會看到一個旋轉的三角形:

技術分享圖片

  渲染管線:


  渲染管線就是將 3D 圖像轉換成 2D 圖像輸出到屏幕的過程,所以你要進行渲染操作就要使用渲染管線。那麽渲染管線在哪呢?有如何創建渲染管線呢?渲染管線的渲染結果如何輸出到你創建的窗口呢?

  為此需要關註三個對象:設備(ID3D11Device)、設備上下文(ID3D11DeviceContext)和交換鏈(IDXGISwapChain),這三者和渲染管線有以下關系:

  1、設備(ID3D11Device):用於分配GPU資源,如緩沖,紋理,著色器和狀態對象(僅舉幾例),從框架代碼中可以看出,基本上都是 CreateXX() 函數。

  2、設備上下文(ID3D11DeviceContext):你可以將它理解成渲染管線,用於設置管線狀態、將資源綁定到渲染管線和生成渲染命令。

  3、交換鏈(IDXGISwapChain):渲染管線和你創建的窗口間的橋梁,將窗口句柄和交換鏈綁定,渲染管線輸出到交換鏈的後緩沖,最後呈現到窗口上。

  通過調用函數 D3D11CreateDeviceAndSwapChain() 就可以一次性創建這三個對象。下圖為渲染管線過程:

技術分享圖片

  源碼下載:MMDViewer 03.zip

基於 DirectX11 的 MMDViewer 03-渲染管線(1)