上一次我們學習了如何畫一個2D三角形,現在讓我們進一步學習如何畫一個旋轉的彩色立方體吧。
具體流程同畫三角形類似,因此不再給出完整代碼了,不同的部分會再說明。
由於我們要畫彩色的立方體,所以頂點結構體中加入顏色變量
struct Vertex { XMFLOAT3 pos; XMFLOAT4 color; };
着色器代碼
1 cbuffer cbPerObject 2 { 3 float4x4 gWorldViewProj; 4 }; 5 6 struct VertexIn 7 { 8 float3 PosL : POSITION; 9 float4 Color : COLOR; 10 }; 11 12 struct VertexOut 13 { 14 float4 PosH : SV_POSITION; 15 float4 Color : COLOR; 16 }; 17 18 VertexOut VS(VertexIn vin) 19 { 20 VertexOut vout; 21 22 // Transform to homogeneous clip space. 23 vout.PosH = mul(float4(vin.PosL, 1.0f), gWorldViewProj); 24 25 // Just pass vertex color into the pixel shader. 26 vout.Color = vin.Color; 27 28 return vout; 29 } 30 31 float4 PS(VertexOut pin) : SV_Target 32 { 33 return pin.Color; 34 } 35 36 technique11 ColorTech 37 { 38 pass P0 39 { 40 SetVertexShader( CompileShader( vs_5_0, VS() ) ); 41 SetGeometryShader( NULL ); 42 SetPixelShader( CompileShader( ps_5_0, PS() ) ); 43 } 44 }
定義了一個矩陣gWorldViewProj,后面我們會利用它進行旋轉立方體
BoxDemo.h
1 #pragma once 2 3 #include "Dx11DemoBase.h" 4 #include "d3dx11effect.h" 5 6 class BoxDemo : public Dx11DemoBase 7 { 8 public: 9 BoxDemo(); 10 ~BoxDemo(); 11 12 bool LoadContent() override; 13 void UnLoadContent() override; 14 15 void Update(float dt) override; 16 void Render() override; 17 18 private: 19 ID3D11Buffer *m_pVertexBuffer; 20 ID3D11Buffer *m_pIndexBuffer;//新增 21 ID3D11InputLayout *m_pInputLayout; 22 23 ID3DX11Effect *m_pFx; 24 ID3DX11EffectTechnique *m_pTechnique; 25 ID3DX11EffectMatrixVariable *m_pFxWorldViewProj; 26 XMFLOAT4X4 m_world; 27 XMFLOAT4X4 m_view; 28 XMFLOAT4X4 m_proj; 29 30 };
LoadContent()函數
頂點信息及緩沖的創建
1 Vertex vertices[] = 2 { 3 { XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT4(255, 255, 255, 1) },//white 4 { XMFLOAT3(-0.5f, +0.5f, -0.5f), XMFLOAT4(0, 0, 0, 1) },//black 5 { XMFLOAT3(+0.5f, +0.5f, -0.5f), XMFLOAT4(255, 0, 0, 1) },//red 6 { XMFLOAT3(+0.5f, -0.5f, -0.5f), XMFLOAT4(0, 255, 0, 1) },//green 7 { XMFLOAT3(-0.5f, -0.5f, +0.5f), XMFLOAT4(0, 0, 255, 1) },//blue 8 { XMFLOAT3(-0.5f, +0.5f, +0.5f), XMFLOAT4(255, 255, 0, 1) },//yellow 9 { XMFLOAT3(+0.5f, +0.5f, +0.5f), XMFLOAT4(0, 255, 255, 1) },//cyan 10 { XMFLOAT3(+0.5f, -0.5f, +0.5f), XMFLOAT4(255, 0, 255, 1) }//magenta 11 }; 12 13 14 D3D11_BUFFER_DESC vertexDesc; 15 ZeroMemory(&vertexDesc, sizeof(vertexDesc)); 16 vertexDesc.Usage = D3D11_USAGE_DEFAULT; 17 vertexDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; 18 vertexDesc.ByteWidth = sizeof(Vertex)* 8; 19 20 D3D11_SUBRESOURCE_DATA resourceData; 21 ZeroMemory(&resourceData, sizeof(resourceData)); 22 resourceData.pSysMem = vertices; 23 result = m_pd3dDevice->CreateBuffer(&vertexDesc, &resourceData, &m_pVertexBuffer); 24 if (FAILED(result)) 25 { 26 return false; 27 }
相比三角形,立方體還要定義Index信息,來確定立方體的六個面
1 UINT indices[] = { 2 // front face 3 0, 1, 2, 4 0, 2, 3, 5 6 // back face 7 4, 6, 5, 8 4, 7, 6, 9 10 // left face 11 4, 5, 1, 12 4, 1, 0, 13 14 // right face 15 3, 2, 6, 16 3, 6, 7, 17 18 // top face 19 1, 5, 6, 20 1, 6, 2, 21 22 // bottom face 23 4, 0, 3, 24 4, 3, 7 25 }; 26 27 D3D11_BUFFER_DESC indexDesc; 28 ZeroMemory(&indexDesc, sizeof(indexDesc)); 29 indexDesc.Usage = D3D11_USAGE_IMMUTABLE; 30 indexDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; 31 indexDesc.ByteWidth = sizeof(UINT)* 36; 32 33 D3D11_SUBRESOURCE_DATA indexData; 34 ZeroMemory(&indexData, sizeof(indexData)); 35 indexData.pSysMem = indices; 36 result = m_pd3dDevice->CreateBuffer(&indexDesc, &indexData, &m_pIndexBuffer); 37 if (FAILED(result)) 38 { 39 return false; 40 }
定義輸入布局
1 D3D11_INPUT_ELEMENT_DESC solidColorLayout[] = 2 { 3 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, 4 { "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 } 5 }; 6 UINT numLayoutElements = ARRAYSIZE(solidColorLayout); 7 D3DX11_PASS_DESC passDesc; 8 m_pTechnique->GetPassByIndex(0)->GetDesc(&passDesc); 9 10 result = m_pd3dDevice->CreateInputLayout(solidColorLayout, numLayoutElements, passDesc.pIAInputSignature, 11 passDesc.IAInputSignatureSize, &m_pInputLayout);
Update()函數----實現旋轉
怎么實現立方體的旋轉呢?我們之前不是給出了 world,view,proj三個矩陣嗎,實現旋轉的一種方式就是根據游戲時間旋轉相應矩陣(例如world矩陣)。
可以定義一個靜態變量表示游戲時間,每一幀運行時更新t值,同時對矩陣作相應旋轉即可。
1 static float t = 0.0f; 2 t += (float)XM_PI * 0.0125f; 3 static DWORD dwTimeStart = 0; 4 DWORD dwTimeCur = GetTickCount(); 5 if (dwTimeStart == 0) 6 dwTimeStart = dwTimeCur; 7 t = (dwTimeCur - dwTimeStart) / 1000.0f; 8 9 XMVECTOR pos = XMVectorSet(2.0f, 0.0f, 0.0f, 1.0f); 10 XMVECTOR target = XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f); 11 XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); 12 13 XMMATRIX V = XMMatrixLookAtLH(pos, target, up); 14 XMStoreFloat4x4(&m_view, V); 15 XMMATRIX T = XMMatrixPerspectiveFovLH(XM_PIDIV2, m_width / static_cast<float>(m_height), 16 0.01f, 100.0f); 17 XMStoreFloat4x4(&m_proj, T); 18 //根據時間旋轉world矩陣 19 XMMATRIX P = XMMatrixRotationY(t); 20 XMStoreFloat4x4(&m_world, P);
Render()函數
和之前的代碼大部分一樣,不同的是要設置IndexBuffer,繪制的時候要用DrawIndexed()而不是Draw().
1 if (m_pImmediateContext == 0) 2 return; 3 //清除渲染目標視圖 4 float clearColor[4] = { 1.0f, 1.0f, 1.0f, 1.0f };//背景顏色 5 m_pImmediateContext->ClearRenderTargetView(m_pRenderTargetView, clearColor); 6 7 UINT stride = sizeof(Vertex); 8 UINT offset = 0; 9 //設置數據信息格式控制信息 10 m_pImmediateContext->IASetInputLayout(m_pInputLayout); 11 //設置要繪制的幾何體信息 12 m_pImmediateContext->IASetVertexBuffers(0,1,&m_pVertexBuffer,&stride,&offset); 13 m_pImmediateContext->IASetIndexBuffer(m_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0); 14 //指明如何繪制 15 m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); 16 17 //設置常量 18 XMMATRIX world = XMLoadFloat4x4(&m_world); 19 XMMATRIX view = XMLoadFloat4x4(&m_view); 20 XMMATRIX proj = XMLoadFloat4x4(&m_proj); 21 XMMATRIX worldViewProj = world*view*proj; 22 m_pFxWorldViewProj->SetMatrix(reinterpret_cast<float*>(&worldViewProj)); 23 24 D3DX11_TECHNIQUE_DESC techDesc; 25 m_pTechnique->GetDesc(&techDesc); 26 for (UINT i = 0; i < techDesc.Passes; ++i) 27 { 28 m_pTechnique->GetPassByIndex(i)->Apply(0, m_pImmediateContext); 29 m_pImmediateContext->DrawIndexed(36, 0, 0); 30 } 31 //馬上輸出 32 m_pSwapChain->Present(0, 0);
這樣我們的工作都完成了,運行便可以得到一個旋轉的彩色立方體了.
下面是運行的一個截圖

