您的位置:首页 > 其它

dx11学习笔记-4、用DX画一个旋转的立方体

2016-02-17 23:30 405 查看
继续按照MS的官方教程来整理知识点。上一篇我们从理论层面讲了顶点变换,这一篇我们将把理论用于实践。DX11中对顶点的变换操作同样是在顶点着色器中进行,所以除了顶点信息之外,我们需要把变换矩阵也添入着色器输入的队伍中去。

初始化变换矩阵

为了方便操作,我们将三个变换矩阵都放在一个结构体中,这个结构体将作为常量缓存输入着色器。

struct ConstantBuffer
{
XMMATRIX mWorld;
XMMATRIX mView;
XMMATRIX mProjection;
};


全局变量新增:

ID3D11Buffer*           g_pConstantBuffer = NULL;
XMMATRIX                g_World;
XMMATRIX                g_View;
XMMATRIX                g_Projection;


InitDevice()新增:

// Create the constant buffer
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(ConstantBuffer);
//绑定信息是常量缓存
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bd.CPUAccessFlags = 0;
//先传NULL数据进去,render时再更新g_pConstantBuffer
hr = g_pd3dDevice->CreateBuffer( &bd, NULL, &g_pConstantBuffer );
if( FAILED( hr ) )
return hr;

//初始化各个矩阵
//设置模型矩阵,以标准矩阵初始化
// Initialize the world matrix
g_World = XMMatrixIdentity();

//设置视图矩阵,初始化照相机位置和朝向
// Initialize the view matrix
XMVECTOR Eye = XMVectorSet( 0.0f, 1.0f, -5.0f, 0.0f );
XMVECTOR At = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f );
XMVECTOR Up = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f );
g_View = XMMatrixLookAtLH( Eye, At, Up );

//设置透视投影矩阵,XM_PIDIV2=1.57,是y方向上视野角的弧度值;width和height是窗口客户区的宽高
// Initialize the projection matrix
g_Projection = XMMatrixPerspectiveFovLH( XM_PIDIV2, width / (FLOAT)height, 0.01f, 100.0f );


渲染时输入变换矩阵的实际值

在Render()时,我们将更新g_pConstantBuffer的填充数据

ConstantBuffer cb;
cb.mWorld = XMMatrixTranspose( g_World );
cb.mView = XMMatrixTranspose( g_View );
cb.mProjection = XMMatrixTranspose( g_Projection );
//更新常量缓存数据
g_pImmediateContext->UpdateSubresource( g_pConstantBuffer, 0, NULL, &cb, 0, 0 );

//设置常量缓存
g_pImmediateContext->VSSetConstantBuffers( 0, 1, &g_pConstantBuffer );


着色器处设置矩阵

//全局声明
//cbuffer(constant buffer)是hlsl内置类型
//register(b0),register说明是应用程序传入的变量,b0(buffer0)说明变量需绑定传入的buffer数组的第一个值
cbuffer ConstantBuffer : register( b0 )
{
matrix World;
matrix View;
matrix Projection;
}
//VS函数新增代码
//mul(matrix1,matrix2)是hlsl内置函数,matrix1和2不可颠倒
//由于dx是以行向量表示矩阵,所以向量在前,变换矩阵在后。
VS_OUTPUT output = (VS_OUTPUT)0;
output.Pos = mul( Pos, World );
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
return output;


画一个立方体

以上展示了如何把除顶点以外的数据信息传入着色器。

要画一个旋转的立方体,我们需要画6个正方形面,也就是12个三角形。这12个三角形的组成顶点相互重合,实际我们只需要把8个顶点反复利用即可。那么,定义了8个顶点之后,我们很明显需要一个索引数组来标明组成各个三角形需要哪几个顶点。

此外,全局变量新增了索引缓存,顶点结构体中我们新增了颜色信息。由于输入顶点着色器的顶点信息又多了COLOR的描述,所以input layout也需要做修改。

//新增索引缓存全局变量
ID3D11Buffer*           g_pIndexBuffer = NULL;


struct SimpleVertex
{
XMFLOAT3 Pos;
XMFLOAT4 Color;
};


//修改layout,新增COLOR元素
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{ "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 },
};


//InitDevice()新增代码
//顶点数组
// Create vertex buffer
SimpleVertex vertices[] =
{
{ XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT4( 0.0f, 0.0f, 1.0f, 1.0f ) },
{ XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT4( 0.0f, 1.0f, 0.0f, 1.0f ) },
{ XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT4( 0.0f, 1.0f, 1.0f, 1.0f ) },
{ XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT4( 1.0f, 0.0f, 0.0f, 1.0f ) },
{ XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT4( 1.0f, 0.0f, 1.0f, 1.0f ) },
{ XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT4( 1.0f, 1.0f, 0.0f, 1.0f ) },
{ XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ) },
{ XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) },
};
D3D11_BUFFER_DESC bd;
ZeroMemory( &bd, sizeof(bd) );
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( SimpleVertex ) * 8;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory( &InitData, sizeof(InitData) );
InitData.pSysMem = vertices;
hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer );
if( FAILED( hr ) )
return hr;

// Set vertex buffer
UINT stride = sizeof( SimpleVertex );
UINT offset = 0;
g_pImmediateContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );

//索引数组
// Create index buffer
WORD indices[] =
{
3,1,0,
2,1,3,

0,5,4,
1,5,0,

3,4,7,
0,4,3,

1,6,5,
2,6,1,

2,7,6,
3,7,2,

6,4,5,
7,4,6,
};
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( WORD ) * 36;        // 36 vertices needed for 12 triangles in a triangle list
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
InitData.pSysMem = indices;
hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pIndexBuffer );
if( FAILED( hr ) )
return hr;

// Set index buffer
g_pImmediateContext->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0 );


//Render()函数处,用DrawIndexed代替了原来的Draw方法
g_pImmediateContext->DrawIndexed( 36, 0, 0 );


顶点着色器处,顶点结构也相应加入颜色信息

struct VS_OUTPUT
{
float4 Pos : SV_POSITION;
float4 Color : COLOR0;
};
//顶点着色器
VS_OUTPUT VS( float4 Pos : POSITION, float4 Color : COLOR )
{
VS_OUTPUT output = (VS_OUTPUT)0;
output.Pos = mul( Pos, World );
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
//赋予颜色信息
output.Color = Color;
return output;
}
//像素着色器
float4 PS( VS_OUTPUT input ) : SV_Target
{
return input.Color;
}


让立方体转起来

现在我们有了一个彩色的立方体,但是它看起来不那么立体——因为它的一面正好与我们的视线垂直,这让它看起来和一个二维的正方形没什么区别。为了让它看起来更立体,我们不妨让它转起来。

需要说明的是,在这个例子中,各个顶点坐标定义在世界坐标系下,立方体的中心与世界坐标系原点重合(当然你也可以改数值,让这二者不重合),g_World初始就是单位矩阵。因此此处g_World可以直接当做三维变换矩阵来用,也可以直接用XMMatrixRotationY( t )赋值,而不用考虑其原来的值。

以下代码都在Render()函数内。

// Update our time
// 静态局部变量相当于全局变量,只在第一次初始化,之后累加,直到应用程序退出时才销毁。
static float t = 0.0f;
if( g_driverType == D3D_DRIVER_TYPE_REFERENCE )
{
t += ( float )XM_PI * 0.0125f;
}
else
{
static DWORD dwTimeStart = 0;
DWORD dwTimeCur = GetTickCount();
if( dwTimeStart == 0 )
dwTimeStart = dwTimeCur;
// 在每一帧求得当前时间与开始时间的时间差,除以1000求得已经过多少秒
t = ( dwTimeCur - dwTimeStart ) / 1000.0f;
}

//
// Animate the cube
// 对矩阵进行绕Y轴的旋转变换
g_World = XMMatrixRotationY( t );
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  缓存