本系列只针对书中每章节的编程练习题,不涉及书中的数学题,需要数学部分的解答请点击
对应原书 P264 6.15EXERCISES
6.Modify the Colored Cube demo by applying the following transformation to each vertex in the vertex shader prior to transforming to world space.
vin.Pos.xy += 0.5f*sin(vin.Pos.x)*sin(3.0f*gTime);
vin.Pos.z *= 0.6f + 0.4f*sin(2.0f*gTime);
The gTime constant buffer variable corresponds to the current GameTimer::TotalTime() value. This will animate the vertices as a function of time by distorting them periodically with the sine function.
题意:修改彩色立方体小程序,在VS阶段中的变换到世界空间之前对每个顶点使用上面的变换公式,其中 gTime是恒定缓冲区变量,其值对应GameTimer::TotalTime()(注意这个类是作者在书中提供的类)
这道题的实现效果挺有趣。这道题主要是想我们学习如何通过Effect框架对shader文件(fx文件)中的cbuffer变量赋值。
问题的关键在如何解决fx文件中的gTime变量,只要参考原文件中gWorldViewProj的操作就能实现题目效果。
在color.fx文件中修改
cbuffer cbPerObject
{
float4x4 gWorldViewProj;
// ================Ex 6 of Cp 6====================
float gTime;
// ===========================================
};
以及
VertexOut VS(VertexIn vin)
{
VertexOut vout;
// ================Ex 6 of Cp 6====================
vin.PosL.xy += 0.5f*sin(vin.PosL.x)*sin(3.0f*gTime);
vin.PosL.z += 0.6f + 0.4f*sin(2.0f*gTime);
// ===========================================
// Transform to homogeneous clip space.
vout.PosH = mul(float4(vin.PosL, 1.0f), gWorldViewProj);
// Just pass vertex color into the pixel shader.
vout.Color = vin.Color;
return vout;
}
在
Colored Cube demo的源文件中
BoxApp类中添加私有成员mfxTime
ID3DX11EffectMatrixVariable* mfxWorldViewProj;
// ================Ex 6 of Cp 6====================
ID3DX11EffectScalarVariable* mfxTime;
// ===========================================
在
BoxApp::BuildFX()方法中使成员mfxTime跟fx文件的gTime变量绑定在一起
mfxWorldViewProj = mFX->GetVariableByName("gWorldViewProj")->AsMatrix();
// ================Ex 6 of Cp 6====================
mfxTime = mFX->GetVariableByName("gTime")->AsScalar();
// ===========================================
最后在
BoxApp::DrawScene()方法中,实现赋值
mfxWorldViewProj->SetMatrix(reinterpret_cast(&worldViewProj));
// ================Ex 6 of Cp 6====================
mfxTime->SetFloat(mTimer.TotalTime());
// ===========================================
比较简单,看代码吧
void BoxApp::BuildGeometryBuffers()
{
// Create vertex buffer
Vertex vertices[] =
{
// ================正方体顶点====================
{ XMFLOAT3(-1.0f, -1.0f, -1.0f), (const float*)&Colors::White },
{ XMFLOAT3(-1.0f, +1.0f, -1.0f), (const float*)&Colors::Black },
{ XMFLOAT3(+1.0f, +1.0f, -1.0f), (const float*)&Colors::Red },
{ XMFLOAT3(+1.0f, -1.0f, -1.0f), (const float*)&Colors::Green },
{ XMFLOAT3(-1.0f, -1.0f, +1.0f), (const float*)&Colors::Blue },
{ XMFLOAT3(-1.0f, +1.0f, +1.0f), (const float*)&Colors::Yellow },
{ XMFLOAT3(+1.0f, +1.0f, +1.0f), (const float*)&Colors::Cyan },
{ XMFLOAT3(+1.0f, -1.0f, +1.0f), (const float*)&Colors::Magenta },
// ================金字塔顶点====================
{ XMFLOAT3(0.0f,+1.0f, 0.0f), (const float*)&Colors::Red }, //金字塔顶部顶点,索引号为0
{ XMFLOAT3(-1.0f, -1.0f, +1.0f), (const float*)&Colors::Green }, //金字塔底部左上顶点,索引号为1
{ XMFLOAT3(+1.0f, -1.0f, +1.0f), (const float*)&Colors::Black }, //金字塔底部右上顶点,索引号为2
{ XMFLOAT3(+1.0f, -1.0f, -1.0f), (const float*)&Colors::Blue }, //金字塔底部右下顶点,索引号为3
{ XMFLOAT3(-1.0f, -1.0f, -1.0f), (const float*)&Colors::Magenta }, //金字塔底部左下顶点,索引号为4
// ===========================================
};
D3D11_BUFFER_DESC vbd;
vbd.Usage = D3D11_USAGE_IMMUTABLE;
vbd.ByteWidth = sizeof(Vertex) * (mPyramidVerticesCount+mBoxVerticesCount);
vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vbd.CPUAccessFlags = 0;
vbd.MiscFlags = 0;
vbd.StructureByteStride = 0;
D3D11_SUBRESOURCE_DATA vinitData;
vinitData.pSysMem = vertices;
HR(md3dDevice->CreateBuffer(&vbd, &vinitData, &mBoxVB));
// Create the index buffer
UINT indices[] = {
// ================正方体索引====================
// front face
0, 1, 2,
0, 2, 3,
// back face
4, 6, 5,
4, 7, 6,
// left face
4, 5, 1,
4, 1, 0,
// right face
3, 2, 6,
3, 6, 7,
// top face
1, 5, 6,
1, 6, 2,
// bottom face
4, 0, 3,
4, 3, 7,
// ================金字塔索引====================
// back face
0, 1, 2,
// right face
0, 2, 3,
// front face
0, 3, 4,
// left face
0, 4, 1,
// bottom face
1, 3, 2,
1, 4, 3
// ===========================================
};
D3D11_BUFFER_DESC ibd;
ibd.Usage = D3D11_USAGE_IMMUTABLE;
ibd.ByteWidth = sizeof(UINT) * (mPyramidIndexCount+mBoxIndexCount);
ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
ibd.CPUAccessFlags = 0;
ibd.MiscFlags = 0;
ibd.StructureByteStride = 0;
D3D11_SUBRESOURCE_DATA iinitData;
iinitData.pSysMem = indices;
HR(md3dDevice->CreateBuffer(&ibd, &iinitData, &mBoxIB));
}
BoxApp::DrawScene()修改
// ================Ex 7 of Cp 6====================
XMMATRIX view = XMLoadFloat4x4(&mView);
XMMATRIX proj = XMLoadFloat4x4(&mProj);
// ===========================================
D3DX11_TECHNIQUE_DESC techDesc;
mTech->GetDesc( &techDesc );
for(UINT p = 0; p < techDesc.Passes; ++p)
{
// ================Ex 7 of Cp 6====================
//================绘制正方体====================
XMMATRIX world = XMLoadFloat4x4(&mBoxWorld);
XMMATRIX worldViewProj = view * proj * world;
mfxWorldViewProj->SetMatrix(reinterpret_cast(&worldViewProj));
mTech->GetPassByIndex(p)->Apply(0, md3dImmediateContext);
md3dImmediateContext->DrawIndexed(mBoxIndexCount, 0, 0);
//================绘制金字塔===================
world = XMLoadFloat4x4(&mPyramidWorld);
worldViewProj = view * proj * world;
mfxWorldViewProj->SetMatrix(reinterpret_cast(&worldViewProj));
mTech->GetPassByIndex(p)->Apply(0, md3dImmediateContext);
md3dImmediateContext->DrawIndexed(mPyramidIndexCount, mBoxIndexCount, mBoxVerticesCount);
// ===========================================
//mTech->GetPassByIndex(p)->Apply(0, md3dImmediateContext);
// 36 indices for the box.
//md3dImmediateContext->DrawIndexed(36, 0, 0);
}
在构造函数中添加
// ================Ex 7 of Cp 6====================
mPyramidIndexCount = 18;
mBoxIndexCount = 36;
mPyramidVerticesCount = 5;
mBoxVerticesCount = 8;
XMStoreFloat4x4(&mBoxWorld, XMMatrixTranslation(0.0f, 0.0f, 0.0f));
XMStoreFloat4x4(&mPyramidWorld, XMMatrixTranslation(0.5f, 0.0f, 0.0f));
// ===========================================
8.Modify the Colored Cube demo by rendering the cube in wireframe mode. Do this in two different ways: First, by setting the rasterization render state from the C++ code by callingID3D11DeviceContext::RSSetState; second, by setting the rasterization render state from the effect file by callingSetRasterizerState() in the effect pass.
题意:把立方体例子修改成只渲染线框的模式。方法有两种:
第一种在C++代码中调用ID3D11DeviceContext::RSSetState;第二种在effect文件的pass中调用SetRasterizerState()
第一种方法:
声明ID3D11RasterizerState对象,通过设置D3D11_RASTERIZER_DESC对象描述目标效果后用CreateRasterizerState实例化ID3D11RasterizerState对象,在DrawScene函数的ID3D11DeviceContext::RSSetState方法(同了挺高代码阅读性,一般放着IA相关函数后面调用)即可实现效果
创建新的类成员
// ================Ex 8 of Cp 6====================
ID3D11RasterizerState* mWireframeRS;
// ===========================================
Init()成员函数中加入
// ================Ex 8 of Cp 6====================
D3D11_RASTERIZER_DESC wireframeDesc;
ZeroMemory(&wireframeDesc, sizeof(D3D11_RASTERIZER_DESC));//必须先执行清零初始化
wireframeDesc.FillMode = D3D11_FILL_WIREFRAME;
wireframeDesc.CullMode = D3D11_CULL_NONE;
wireframeDesc.FrontCounterClockwise = false;
wireframeDesc.DepthClipEnable = true;
HR(md3dDevice->CreateRasterizerState(&wireframeDesc, &mWireframeRS));
// ===========================================
void BoxApp::DrawScene()
{
md3dImmediateContext->ClearRenderTargetView(mRenderTargetView, reinterpret_cast(&Colors::LightSteelBlue));
md3dImmediateContext->ClearDepthStencilView(mDepthStencilView, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0);
md3dImmediateContext->IASetInputLayout(mInputLayout);
md3dImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// ================Ex 8 of Cp 6====================
md3dImmediateContext->RSSetState(mWireframeRS);
// ===========================================
.....
}
第二种方法:
直接上代码吧
cbuffer cbPerObject
{
float4x4 gWorldViewProj;
};
// ================Ex 8 of Cp 6====================
RasterizerState DisableCulling
{
CullMode = NONE;
FillMode = WIREFRAME;
};
// ===========================================
struct VertexIn
{
float3 PosL : POSITION;
float4 Color : COLOR;
};
struct VertexOut
{
float4 PosH : SV_POSITION;
float4 Color : COLOR;
};
VertexOut VS(VertexIn vin)
{
VertexOut vout;
vout.PosH = mul(float4(vin.PosL, 1.0f), gWorldViewProj);
vout.Color = vin.Color;
return vout;
}
float4 PS(VertexOut pin) : SV_Target
{
return pin.Color;
}
technique11 ColorTech
{
pass P0
{
SetVertexShader( CompileShader( vs_5_0, VS() ) );
SetGeometryShader( NULL );
SetPixelShader( CompileShader( ps_5_0, PS() ) );
// ================Ex 8 of Cp 6====================
SetRasterizerState(DisableCulling);
// ============================================
}
}
补充:D3D11_RASTERIZER_DESC对象更多的设置内容,可到MSDN查找,或者参考此博客
第一种方法只需把第8题的修改CullMode为如下
wireframeDesc.CullMode = D3D11_CULL_FRONT;
第二种
方法同理
RasterizerState DisableCulling
{
CullMode = FRONT;
FillMode = SOLID;
};
如果顶点内存变得很重要,把128位的颜色值变成32位的颜色值会相当有效!把在顶点结构把颜色值修改成32位,可以像下面这样设置顶点输入描述:
struct Vertex
{
XMFLOAT3 Pos;
XMCOLOR Color;
};
D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,
D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12,
D3D11_INPUT_PER_VERTEX_DATA, 0}
};
The 8-bit color components need to be packed into a UINT in the format ABGR, not RGBA; this is because the byte order is reversed in little-endian format (the bytesABGRwill actually be ordered RGBA in littleendian). For multi-byte data, big-endian stores the most significant byte at the lowest address in memory, and the least significant byte at the highest address, and little-endian stores the least significant byte at the lowest address in memory, and the most significant byte at the highest address in memory. The conversion fromARGB(which XMCOLOR uses) to ABGR can be done with a function like the following:
注意:这里有一个ABGR的概念,其实就是RGBA在小端机中表示(RGBA的对应的颜色通道和Apla通道反转放置);多字节的大端机从最低地址开始存储最高有效字节,最高地址存储最低有效字节,而小端机则是从最低地址开始存储最低有效字节,在最高地址存储最高有效字节,从ARGB(XMCOLOR 使用的类型)转换到ABGR的方法如下:
static D3DX11INLINE UINT ArgbToAbgr(UINT argb)
{
BYTE A = (argb >> 24) & 0xff;
BYTE R = (argb >> 16) & 0xff;
BYTE G = (argb >> 8) & 0xff;
BYTE B = (argb >> 0) & 0xff;
return (A << 24) | (B << 16) | (G << 8) | (R << 0);
}
方法题目都说的差不多了,直接上代码吧
第一步:
struct Vertex
{
XMFLOAT3 Pos;
XMCOLOR Color;
};
static D3DX11INLINE UINT ArgbToAbgr(UINT argb)
{
BYTE A = (argb >> 24) & 0xff;
BYTE R = (argb >> 16) & 0xff;
BYTE G = (argb >> 8) & 0xff;
BYTE B = (argb >> 0) & 0xff;
return (A << 24) | (B << 16) | (G << 8) | (R << 0);
}
第二步:
void BoxApp::BuildVertexLayout()
{
// Create the vertex input layout.
D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}
};
// Create the input layout
D3DX11_PASS_DESC passDesc;
mTech->GetPassByIndex(0)->GetDesc(&passDesc);
HR(md3dDevice->CreateInputLayout(vertexDesc, 2, passDesc.pIAInputSignature,
passDesc.IAInputSignatureSize, &mInputLayout));
}
最后:
void BoxApp::BuildGeometryBuffers()
{
// Create vertex buffer
Vertex vertices[] =
{
{ XMFLOAT3(-1.0f, -1.0f, -1.0f), ArgbToAbgr(0xFFFFFFFF) },
{ XMFLOAT3(-1.0f, +1.0f, -1.0f), ArgbToAbgr(0xFF000000) },
{ XMFLOAT3(+1.0f, +1.0f, -1.0f), ArgbToAbgr(0xFFFF0000) },
{ XMFLOAT3(+1.0f, -1.0f, -1.0f), ArgbToAbgr(0xFF00FF00) },
{ XMFLOAT3(-1.0f, -1.0f, +1.0f), ArgbToAbgr(0xFF0000FF) },
{ XMFLOAT3(-1.0f, +1.0f, +1.0f), ArgbToAbgr(0xFFFFFF00) },
{ XMFLOAT3(+1.0f, +1.0f, +1.0f), ArgbToAbgr(0xFF00FFFF) },
{ XMFLOAT3(+1.0f, -1.0f, +1.0f), ArgbToAbgr(0xFFFF00FF) },
};
........;
}