1. 程式人生 > >DirectX11程式設計6 紅龍書第六章練習

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面體為基礎,每增加一階就細分一次三角形,細分的越細越接近球體):