DirectX11程式設計6 紅龍書第六章練習
環境:VS2017 語言:C++
在經過紅龍書第六章大量的Demo之後,我們來到了第六章的練習題,基本上沒有什麼難度,但我們還是來看一下,瞭解更多的知識。
1.這邊的程式都是以win64執行的;
2.如果沒有找到Common指令碼,請到工程/屬性/VC++目錄中新增包含目錄“../Common”;
3.如果沒有找到libs,請到工程/屬性/連結器新增附加庫目錄“../Common/libs”
4.所有的練習都在工程中,全域性搜尋“練習6”關鍵字就能找到,想要執行開啟註釋即可。
有任何錯誤,請大佬們指正。
1.寫出以下的資料結構對應的D3D10_INPUT_ELEMENT_DESC陣列:
struct Vertex { XMFLOAT3 Pos; XMFLOAT3 Tangent; XMFLOAT3 Normal; XMFLOAT2 Tex0; XMFLOAT2 Tex1; XMCOLOR Color; }; 答: D3D11_INPUT_ELEMENT_DESC vertexLayout[6] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 36, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 1, DXGI_FORMAT_R32G32_FLOAT, 0, 44, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 52, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 } };
2.重做Cube Demo,使用兩個頂點快取分別傳遞位置和顏色資料?
答:
首先是兩個頂點快取的建立:
std::vector<VertexPos> verticesPos = { { XMFLOAT3(-1.0f, 0.0f, -1.0f) }, { XMFLOAT3(-1.0f, 0.0f, +1.0f) }, { XMFLOAT3(+1.0f, 0.0f, +1.0f) }, { XMFLOAT3(+1.0f, 0.0f, -1.0f) }, { XMFLOAT3(0.0f, 1.41f, 0.0f) }, }; // 頂點快取 Position D3D11_BUFFER_DESC vbdPos; ZeroMemory(&vbdPos, sizeof(vbdPos)); vbdPos.Usage = D3D11_USAGE_DEFAULT; vbdPos.ByteWidth = sizeof(VertexPos) * verticesPos.size(); vbdPos.BindFlags = D3D11_BIND_VERTEX_BUFFER; vbdPos.CPUAccessFlags = 0; D3D11_SUBRESOURCE_DATA InitData; ZeroMemory(&InitData, sizeof(InitData)); InitData.pSysMem = &verticesPos[0]; HR(md3dDevice->CreateBuffer(&vbdPos, &InitData, &mBoxVB)); UINT stride = sizeof(VertexPos); UINT offset = 0; md3dImmediateContext->IASetVertexBuffers(0, 2, &mBoxVB, &stride, &offset); std::vector<VertexColor> verticesColor = { { XMFLOAT4((const float*)&Colors::Red) }, { XMFLOAT4((const float*)&Colors::Green) }, { XMFLOAT4((const float*)&Colors::Blue) }, { XMFLOAT4((const float*)&Colors::Yellow) }, { XMFLOAT4((const float*)&Colors::Black) }, }; // 頂點快取 Color D3D11_BUFFER_DESC vbdColor; ZeroMemory(&vbdColor, sizeof(vbdColor)); vbdColor.Usage = D3D11_USAGE_DEFAULT; vbdColor.ByteWidth = sizeof(VertexColor) * verticesColor.size(); vbdColor.BindFlags = D3D11_BIND_VERTEX_BUFFER; vbdColor.CPUAccessFlags = 0; ZeroMemory(&InitData, sizeof(InitData)); InitData.pSysMem = &verticesColor[0]; HR(md3dDevice->CreateBuffer(&vbdColor, &InitData, &mBoxVB)); stride = sizeof(VertexColor); offset = 0; md3dImmediateContext->IASetVertexBuffers(1, 2, &mBoxVB, &stride, &offset);
然後在建立佈局時使用以下描述:
D3D11_INPUT_ELEMENT_DESC vertexLayout[2] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
3.實現第五章的不同圖元的效果?
答:
md3dImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
md3dImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP);
md3dImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
md3dImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
4.實現一個頂端為紅色、低端為綠色的椎體?
答:
誤打誤撞就是我們坍縮的正方體!那麼我們改一下顏色就可以了:
std::vector<Vertex> vertices =
{
{ XMFLOAT3(-1.0f, 0.0f, -1.0f), XMFLOAT4((const float*)&Colors::Green) },
{ XMFLOAT3(-1.0f, 0.0f, +1.0f), XMFLOAT4((const float*)&Colors::Green) },
{ XMFLOAT3(+1.0f, 0.0f, +1.0f), XMFLOAT4((const float*)&Colors::Green) },
{ XMFLOAT3(+1.0f, 0.0f, -1.0f), XMFLOAT4((const float*)&Colors::Green) },
{ XMFLOAT3(0.0f, 1.41f, 0.0f), XMFLOAT4((const float*)&Colors::Red) },
};
5.執行Box Demo,解釋方體上各個畫素點為什麼呈現出我們看到的顏色?
答:
我們只指定了頂點的顏色,而頂點之間的顏色值便是通過插值的方式來確定的。
6.以Cube Demo為基礎,實現頂點動畫?
答:
在常量快取中新增float gTime,然後在Update函式中每幀使用mTimer.TotalTime()來賦值該值,傳遞到shader中。
shader在計算齊次座標前,先計算頂點位置即可:
pIn.PosL.xy += 0.5f*sin(pIn.PosL.x)*sin(3.0f*gTime);
pIn.PosL.z *= 0.6f + 0.4f*sin(2.0f*gTime);
7.使用一個頂點快取分別渲染椎體和方體?
這個和Shapes Demo的思路是一樣的,改動比較大,所以新建工程了,請參見Chapter 6_6 Exercise7 BoxAndPryramid。
8.實現Cube Demo線上框模式下執行?
答:
線框模式沒啥好說的,使用以下程式碼建立線框模式的描述:
D3D11_RASTERIZER_DESC wireframeDesc;
ZeroMemory(&wireframeDesc, sizeof(D3D11_RASTERIZER_DESC));
wireframeDesc.FillMode = D3D11_FILL_WIREFRAME;
wireframeDesc.CullMode = D3D11_CULL_BACK;
wireframeDesc.FrontCounterClockwise = false;
wireframeDesc.DepthClipEnable = true;
HR(md3dDevice->CreateRasterizerState(&wireframeDesc, &mWireframeRS));
再在DrawIndex之前設定線框模式即可:
md3dImmediateContext->RSSetState(mWireframeRS);
9.嘗試在Cube Demo下設定不同的CullMode?
答:
三種CullMode可以嘗試一下效果:
wireframeDesc.CullMode = D3D11_CULL_BACK;
wireframeDesc.CullMode = D3D11_CULL_NONE;
wireframeDesc.CullMode = D3D11_CULL_FRONT;
10.使用32bit的Color代替128bit的Color傳遞到Shader中?
答:
本題shader不用做任何更改,轉換應該是在內部完成了。
首先是建立快取:
// 建立32bitColor的頂點資料
std::vector<Vertex32bitColor> vertices =
{
{ XMFLOAT3(-1.0f, 0.0f, -1.0f), XMCOLOR(Colors::Red) },
{ XMFLOAT3(-1.0f, 0.0f, +1.0f), XMCOLOR(Colors::Green) },
{ XMFLOAT3(+1.0f, 0.0f, +1.0f), RgbaToArgb (0x0000ffff) },
{ XMFLOAT3(+1.0f, 0.0f, -1.0f), XMCOLOR(Colors::Yellow) },
{ XMFLOAT3(0.0f, 1.41f, 0.0f), XMCOLOR(Colors::Black) },
};
D3D11_BUFFER_DESC vbd;
ZeroMemory(&vbd, sizeof(vbd));
vbd.Usage = D3D11_USAGE_DEFAULT;
vbd.ByteWidth = sizeof(Vertex32bitColor) * vertices.size();
vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vbd.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory(&InitData, sizeof(InitData));
InitData.pSysMem = &vertices[0];
HR(md3dDevice->CreateBuffer(&vbd, &InitData, &mBoxVB));
UINT stride = sizeof(Vertex32bitColor);
UINT offset = 0;
md3dImmediateContext->IASetVertexBuffers(0, 1, &mBoxVB, &stride, &offset);
然後是佈局設定:
D3D11_INPUT_ELEMENT_DESC vertexLayout[2] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_B8G8R8A8_UNORM, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
RgbaToAbgr的函式如下:
static UINT RgbaToArgb(UINT rgba)
{
BYTE R = (rgba >> 24) & 0xff;
BYTE G = (rgba >> 16) & 0xff;
BYTE B = (rgba >> 8) & 0xff;
BYTE A = (rgba >> 0) & 0xff;
return (A << 24) | (R << 16) | (G << 8) | (B << 0);
}
這邊使用XMCOLOR進行建立是最好的,它內部會進行轉換。但我們需要知道一般情況下傳遞給shader的是小端儲存的,即ABGR,使用UINT作為資料型別時就這麼傳;而使用UINT建立XMCOLOR時,需要以ARGB的順序建立。
11.在Skull Demo改變viewport,只渲染視窗內的一小塊?
答:
參見練習4.6
12.以下資料結構、描述,如果Pos和Color互相調換,資料結構之間不一一對應,shader還能獲取到正確的資料嗎?
struct Vertex
{
DirectX::XMFLOAT3 Pos;
DirectX::XMFLOAT4 Color;
};
D3D11_INPUT_ELEMENT_DESC vertexLayout[2] = {
{ "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 },
};
struct VertexIn
{
float3 PosL : POSITION;
float4 Color : COLOR;
};
答:
可以,C++中的資料結構對應的是DESC中資料offset的數值,而shader中的資料是和DESC中名稱相互對應,POSITION對應POSITION、COLOR對應COLOR。
但是這讓我想到常量,常量沒有類似的指定,所以必須一一對應,而且不能有null。
13.使用scissor test的技術剪裁畫素點,實現類似練習11的效果?
答:
在DrawIndex之前:
D3D11_RECT rects = { 100, 100, 400, 400 };
md3dImmediateContext->RSSetScissorRects(1, &rects);
在建立線框模式時啟用該技術:
wireframeDesc.ScissorEnable = true;
14.使用CreateGeosphere替代CreateSphere,並觀察效果?
答:
GeometryGenerator::CreateGeosphere(0.5f, 0, sphere);
GeometryGenerator::CreateGeosphere(0.5f, 1, sphere);
GeometryGenerator::CreateGeosphere(0.5f, 2, sphere);
GeometryGenerator::CreateGeosphere(0.5f, 3, sphere);
我們就看一下1階的Geosphere(Geosphere是以20面體為基礎,每增加一階就細分一次三角形,細分的越細越接近球體):