环境:VS2017 语言:C++
在经过红龙书第六章大量的Demo之后,我们来到了第六章的练习题,基本上没有什么难度,但我们还是来看一下,了解更多的知识。
先附上工程的链接:https://github.com/anguangzhihen/Dx11。
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面体为基础,每增加一阶就细分一次三角形,细分的越细越接近球体):