dx11学习笔记-4、用DX画一个旋转的立方体
2016-02-17 23:30
405 查看
继续按照MS的官方教程来整理知识点。上一篇我们从理论层面讲了顶点变换,这一篇我们将把理论用于实践。DX11中对顶点的变换操作同样是在顶点着色器中进行,所以除了顶点信息之外,我们需要把变换矩阵也添入着色器输入的队伍中去。
全局变量新增:
InitDevice()新增:
要画一个旋转的立方体,我们需要画6个正方形面,也就是12个三角形。这12个三角形的组成顶点相互重合,实际我们只需要把8个顶点反复利用即可。那么,定义了8个顶点之后,我们很明显需要一个索引数组来标明组成各个三角形需要哪几个顶点。
此外,全局变量新增了索引缓存,顶点结构体中我们新增了颜色信息。由于输入顶点着色器的顶点信息又多了COLOR的描述,所以input layout也需要做修改。
顶点着色器处,顶点结构也相应加入颜色信息
需要说明的是,在这个例子中,各个顶点坐标定义在世界坐标系下,立方体的中心与世界坐标系原点重合(当然你也可以改数值,让这二者不重合),g_World初始就是单位矩阵。因此此处g_World可以直接当做三维变换矩阵来用,也可以直接用XMMatrixRotationY( t )赋值,而不用考虑其原来的值。
以下代码都在Render()函数内。
初始化变换矩阵
为了方便操作,我们将三个变换矩阵都放在一个结构体中,这个结构体将作为常量缓存输入着色器。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 );
相关文章推荐
- 浅析SQL Server中的执行计划缓存(上)
- Enterprise Library for .NET Framework 2.0缓存使用实例
- PowerShell中编程清空IE缓存方法
- PowerShell中使用.NET将程序集加入全局程序集缓存
- C#中缓存的基本用法总结
- wap开发中如何有效的利用缓存减少消息的传送量
- PHP基于文件存储实现缓存的方法
- smarty缓存用法分析
- 引用全局程序集缓存内的程序集的方法
- asp Response.flush 实时显示进度
- C#实现清除IE浏览器缓存的方法
- ASP.NET缓存管理的几种方法
- PHP文件缓存类实现代码
- 清除aspx页面缓存的程序实现方法
- C#缓存之SqlCacheDependency用法实例总结
- jQuery数据缓存用法分析
- Jquery validation remote 验证的缓存问题解决方法
- IE9下Ajax无法刷新数据的缓存问题解决方法
- Ajax获取页面被缓存的解决方法
- ASP.NET网站管理系统退出 清除浏览器缓存,Session的代码