程序流程:
- 创建主窗口。注册窗口类WNDCLASS,创建窗口CreateWindow,显示窗口ShowWindow,绘制窗口客户区UpdateWindow。
bool initWndApp(HINSTANCE hInstance, int show) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.hInstance = hInstance; wc.lpfnWndProc = WndProc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hIcon = LoadIcon(0,IDI_APPLICATION); wc.hCursor = LoadCursor(0, IDC_CROSS); wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH); wc.lpszMenuName = 0; wc.lpszClassName = L"BasicWndClass"; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if ( !RegisterClassEx(&wc)) { MessageBox(0, L"RegisterClass Failed", 0, 0); return false; } //如果没有WS_VISIBLE标志,则需要手动调用ShowWindow来显示窗口 mainWnd = CreateWindowEx(NULL, L"BasicWndClass", L"我的窗口1", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); if (mainWnd == 0) { MessageBox(0, L"CreateWindow1 FAILED", 0, 0); return false; } ShowWindow(mainWnd, show); //该函数将发送一个WM_PAINT消息 UpdateWindow(mainWnd); return true; }
- 创建设备和设备环境。D3D11CreateDevice,测试多重采样质量等级ID3D11Device::CheckMultisampleQualityLevels。
- 创建后台缓冲交换链。IDXGIFactory::CreateSwapChain。
void mCreateDevice() { D3D_FEATURE_LEVEL featureLevel; HRESULT hr = D3D11CreateDevice(0, D3D_DRIVER_TYPE_HARDWARE, 0, createDeviceFlg, 0, 0, D3D11_SDK_VERSION, &g_pD3DDevice, &featureLevel, &g_pD3DImmediateContext); if (FAILED(hr)) { MessageBox(0, L"D3D11CreateDevice Failed.", 0, 0); return; } if (featureLevel != D3D_FEATURE_LEVEL_11_0) { MessageBox(0, L"DX 11 unsupported.", 0, 0); return; } DXGI_SWAP_CHAIN_DESC sd; //back buffer数 sd.BufferCount = 1; //显示器一般不支持大于24位的颜色 sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.BufferDesc.Width = g_WndWidth; sd.BufferDesc.Height = g_WndHeight; //刷新频率60/1 sd.BufferDesc.RefreshRate.Numerator = 60; sd.BufferDesc.RefreshRate.Denominator = 1; sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; //不使用多重采样 sd.SampleDesc.Count = 1; sd.SampleDesc.Quality = 0; sd.OutputWindow = mainWnd; sd.Windowed = true; sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.Flags = 0; //create swap chain IDXGIDevice *dxgiDevice = 0; HR(g_pD3DDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice)); IDXGIAdapter *dxgiAdapter = 0; HR(dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&dxgiAdapter)); IDXGIFactory *dxgiFactory = 0; HR(dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&dxgiFactory)); HR(dxgiFactory->CreateSwapChain(g_pD3DDevice, &sd, &g_pSwapChain)); dxgiDevice->Release(); dxgiAdapter->Release(); dxgiFactory->Release(); }
- 创建渲染对象视图。ID3D11Device::CreateRenderTargetView。
- 创建深度模板缓冲及其视图。ID3D11Device::CreateDepthStencilView。
- 将4、5中的视图绑定到管线。ID3D11DeviceContext::OMSetRenderTargets。
- 设置视口。ID3D11DeviceContext::RSSetViewports。
void mCreateView() { assert(g_pD3DDevice); assert(g_pD3DImmediateContext); assert(g_pSwapChain); ReleaseCOM(g_pRenderTView); ReleaseCOM(g_pDSView); ReleaseCOM(g_pDepthStencilBuffer); HR(g_pSwapChain->ResizeBuffers(1, g_WndWidth, g_WndHeight, DXGI_FORMAT_R8G8B8A8_UNORM, 0)); ID3D11Texture2D *backBuffer; HR(g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&backBuffer))); g_pD3DDevice->CreateRenderTargetView(backBuffer, 0, &g_pRenderTView); ReleaseCOM(backBuffer); D3D11_TEXTURE2D_DESC depthStencilDesc; depthStencilDesc.Width = g_WndWidth; depthStencilDesc.Height = g_WndHeight; depthStencilDesc.ArraySize = 1; depthStencilDesc.MipLevels = 1; depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; depthStencilDesc.Usage = D3D11_USAGE_DEFAULT; depthStencilDesc.SampleDesc.Count = 1; depthStencilDesc.SampleDesc.Quality = 0; depthStencilDesc.CPUAccessFlags = 0; depthStencilDesc.MiscFlags = 0; HR(g_pD3DDevice->CreateTexture2D(&depthStencilDesc, 0, &g_pDepthStencilBuffer)); HR(g_pD3DDevice->CreateDepthStencilView(g_pDepthStencilBuffer, 0, &g_pDSView)); g_pD3DImmediateContext->OMSetRenderTargets( 1, &g_pRenderTView, g_pDSView); //set view port g_pVp.TopLeftX = 0.0f; g_pVp.TopLeftY = 0.0f; g_pVp.Width = static_cast<float>(g_WndWidth); g_pVp.Height = static_cast<float>(g_WndHeight); g_pVp.MinDepth = 0.0f; g_pVp.MaxDepth = 1.0f; g_pD3DImmediateContext->RSSetViewports(1, &g_pVp); }
- 创建顶点缓冲区。创建顶点结构,定义顶点数组,定义缓冲区描述D3D11_BUFFER_DESC,定义子资D3D11_SUBRESOURCE_DATA,ID3D11Device::CreateBuffer。
- 创建索引缓冲区。定义索引数据,定义缓冲区描述D3D11_BUFFER_DESC,定义子资源D3D11_SUBRESOURCE_DATA,ID3D11Device::CreateBuffer。
void mCreateBuffer() { //顺时针方向为正面 D3D11_BUFFER_DESC vBufferDesc; vBufferDesc.ByteWidth = sizeof(myVertex) * 8; vBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; vBufferDesc.Usage = D3D11_USAGE_IMMUTABLE; vBufferDesc.CPUAccessFlags = 0; vBufferDesc.MiscFlags = 0; vBufferDesc.StructureByteStride = 0; D3D11_SUBRESOURCE_DATA vertexData; vertexData.pSysMem = mvBox; HR(g_pD3DDevice->CreateBuffer(&vBufferDesc, &vertexData, &g_pVectorBuffer)); D3D11_BUFFER_DESC iBufferDesc; iBufferDesc.ByteWidth = sizeof(UINT) * 36; iBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; iBufferDesc.Usage = D3D11_USAGE_IMMUTABLE; iBufferDesc.CPUAccessFlags = 0; iBufferDesc.MiscFlags = 0; iBufferDesc.StructureByteStride = 0; D3D11_SUBRESOURCE_DATA indexData; indexData.pSysMem = idxBox; //indexData.SysMemPitch = 0; //indexData.SysMemSlicePitch = 0; HR(g_pD3DDevice->CreateBuffer(&iBufferDesc, &indexData, &g_pIndexBuffer)); }
- 创建并编写着色器。在.FX文件(Effect文件)中编写Vertex Shader,Pixel Shader等。
- 编译Effect文件。D3DX11CompileFromFile。
void mCreateFX() { DWORD shaderFlg = 0; #if defined(DEBUG) || defined(_DEBUG) shaderFlg |= D3D10_SHADER_DEBUG; shaderFlg |= D3D10_SHADER_SKIP_OPTIMIZATION; #endif ID3D10Blob *compiledShader = 0; ID3D10Blob *compiledMsg = 0; HRESULT hr = D3DX11CompileFromFile(L"color.fx", 0, 0, 0, "fx_5_0", shaderFlg, 0, 0, &compiledShader, &compiledMsg, 0); if (compiledMsg != 0) { MessageBoxA(0, (char*)compiledMsg->GetBufferPointer(), 0, 0); compiledMsg->Release(); } if (FAILED(hr)) { DXTrace(__FILE__, (DWORD)__LINE__, hr, L"D3DX11CompileFromFile", TRUE); } HR(D3DX11CreateEffectFromMemory( compiledShader->GetBufferPointer(), compiledShader->GetBufferSize(), 0, g_pD3DDevice, &g_pEffect)); ReleaseCOM(compiledShader); // attention g_pTech = g_pEffect->GetTechniqueByName("ColorTech"); mWVP = g_pEffect->GetVariableByName("gWorldViewProj")->AsMatrix(); //buuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuug__gWorldViewProjection }
- 创建输入布局。定义输入元素描述D3D11_INPUT_ELEMENT_DESC,ID3D11Device::CreateInputLayout。
void mCreateInputLayout() { D3D11_INPUT_ELEMENT_DESC vertexDesc[] = { {"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} }; D3DX11_PASS_DESC passDesc; g_pTech->GetPassByIndex(0)->GetDesc(&passDesc); HR(g_pD3DDevice->CreateInputLayout(vertexDesc, 2, passDesc.pIAInputSignature, passDesc.IAInputSignatureSize, &g_pLayout)); }
- 进入窗口消息循环。收到消息时转14,否则转15。
void run() { MSG msg; while (true) { if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); } //do animation/game stuff drawBox(); } release(); }
- 处理窗口消息。
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; static UINT wcount = 0; switch(msg){ case WM_CREATE: // MessageBox(0, L"窗口创建成功!", L"Create", 0); ++wcount; return 0; //WM_PAINT在窗口需要重绘时发送 case WM_PAINT: hdc = BeginPaint(hWnd, &ps); drawBox(); EndPaint(hWnd, &ps); return 0; case WM_KEYDOWN: if (wParam == VK_ESCAPE){ DestroyWindow(hWnd); } return 0; case WM_DESTROY: if (!--wcount){ PostQuitMessage(0); } return 0; } return DefWindowProc(hWnd, msg, wParam, lParam); }
- 设置变换矩阵。World Matrix,View Matrix,Perspective Projection Matrix。
- 将资源绑定到管线。IASetInputLayout,IASetPrimitiveTopology,IASetVertexBuffers,IASetIndexBuffer。
- 绘制图形。
- 提交到缓冲区。
void mSetRenderState() { // clear render target and depth/stencil g_pD3DImmediateContext->ClearRenderTargetView( g_pRenderTView, reinterpret_cast<const float*>(&LightSteelBlue)); g_pD3DImmediateContext->ClearDepthStencilView( g_pDSView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); g_pD3DImmediateContext->IASetInputLayout(g_pLayout); g_pD3DImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); UINT stride = sizeof(myVertex); UINT offset = 0; g_pD3DImmediateContext->IASetVertexBuffers(0, 1, &g_pVectorBuffer, &stride, &offset); g_pD3DImmediateContext->IASetIndexBuffer(g_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0); // world matrix XMMATRIX world; world = XMMatrixIdentity(); // view matrix XMMATRIX view; float x = 3.0f; float y = 2.0f; float z = 2.0f; XMVECTOR pos = XMVectorSet(x, y, z, 1.0f); XMVECTOR target = XMVectorZero(); XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); view = XMMatrixLookAtLH(pos, target, up); // projection matrix XMMATRIX proj; proj = XMMatrixPerspectiveFovLH( 0.25*PI, static_cast<float>(g_WndWidth)/g_WndHeight, 1.0f, 1000.0f); XMMATRIX wvp = world*view*proj; mWVP->SetMatrix(reinterpret_cast<const float*>(&wvp)); D3DX11_TECHNIQUE_DESC techDesc; g_pTech->GetDesc(&techDesc); for (UINT p=0; p<techDesc.Passes; ++p) { g_pTech->GetPassByIndex(p)->Apply(0, g_pD3DImmediateContext); g_pD3DImmediateContext->DrawIndexed(36, 0, 0); } HR(g_pSwapChain->Present(0, 0)); }
- 释放资源。
void release() { ReleaseCOM(g_pD3DDevice); ReleaseCOM(g_pD3DImmediateContext); ReleaseCOM(g_pSwapChain); ReleaseCOM(g_pEffect); ReleaseCOM(g_pLayout); ReleaseCOM(g_pVectorBuffer); ReleaseCOM(g_pDepthStencilBuffer); ReleaseCOM(g_pDSView); }
注:
创建的资源在使用完后,最好都释放一下。不然小心内存用完哦!
ID3DX11Effect->GetVariableByName();里面的变量名写错了,编译器检查不到,运行时box出不来。痛苦的找了几天的bug,在仔细检查了N遍后发现。血与泪的教训啊!铭记!