声明:纯粹出于个人兴趣,打算开始对DX开始一次系统的学习。欢迎拍砖,不对的地方望各位看官给予指正,感激不尽!!!
继续昨天的进程,通过Basic Win32窗口的创建,算是打下了一点基础,接下来该主角上场了,根据SDK的例子,开搞DX10 Basic!!!
创建窗口的过程与原来无异,首先要包含必要的头文件和库文件:
#include //dx头文件
#include //dx头文件
#pragma comment(lib,"d3d10.lib")//dx库文件
#pragma comment(lib,"d3dx10d.lib")//dx库文件
要创建d3d的应用程序,两样东西必不可少,d3d设备:ID3D10Device以及交换链:IDXGISwapChain。通俗一点说,ID3D10Device好比我们的画笔,我们想要在屏幕这张纸上作画,就一定要先有画笔,而IDXGISwapChain就相当于我们的画布,而且我们一般应该准备两张画布,以便一张画完后可以直接画下一张,而不用等着这张展览完再取下画布画下一张,而这两张画布应该是可擦写的,你用手头的画取代正在展览的画后,可以直接在替换下的画布上作画。
1.创建device和swap chain的代码:
//--------------------------------------------------------------------------------------
// Create Direct3D device and swap chain
//--------------------------------------------------------------------------------------
HRESULT InitDevice()
{
HRESULT hr = S_OK;;
RECT rc;
GetClientRect( g_hWnd, &rc );
UINT width = rc.right - rc.left;
UINT height = rc.bottom - rc.top;
UINT createDeviceFlags = 0;
#ifdef _DEBUG
createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG;
#endif
D3D10_DRIVER_TYPE driverTypes[] =
{
D3D10_DRIVER_TYPE_HARDWARE,
D3D10_DRIVER_TYPE_REFERENCE,
};
UINT numDriverTypes = sizeof( driverTypes ) / sizeof( driverTypes[0] );
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory( &sd, sizeof( sd ) );
sd.BufferCount = 1;
sd.BufferDesc.Width = width;
sd.BufferDesc.Height = height;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = g_hWnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = TRUE;
for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )//选择支持的驱动类型
{
g_driverType = driverTypes[driverTypeIndex];
hr = D3D10CreateDeviceAndSwapChain( NULL, g_driverType, NULL, createDeviceFlags,
D3D10_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice );
if( SUCCEEDED( hr ) )
break;
}
if( FAILED( hr ) )
return hr;
// Create a render target view这里是d3d10创建渲染视图的部分,通过制定渲染类型可以方便准确地进行渲染
ID3D10Texture2D* pBackBuffer;
hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D10Texture2D ), ( LPVOID* )&pBackBuffer );
if( FAILED( hr ) )
return hr;
hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView );
pBackBuffer->Release();
if( FAILED( hr ) )
return hr;
g_pd3dDevice->OMSetRenderTargets( 1, &g_pRenderTargetView, NULL );
// Setup the viewport设置视口
D3D10_VIEWPORT vp;
vp.Width = width;
vp.Height = height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
g_pd3dDevice->RSSetViewports( 1, &vp );
return S_OK;
}
CreateRenderTargetView是个比较容易迷糊的地方,创建RenderTargetView有什么用呢?照前面的理解,我们有了笔和画布,不就可以作画并展示了吗,要这个不是多余吗。其实我们可以把它理解为我们的画框。用笔在画布上画好了画,这幅画不能孤零零地贴在墙上吧,太不像话了,我们就找个画框来装裱一番,这样就漂亮多了不是吗?而在这个示例程序中我们只创建了一个缓冲区,而不是按惯例创建前后两个缓冲区,所以我们只要把我们创建的画布给了画框就是了。整个过程为:我们先用g_pSwapChain->GetBuffer( 0, __uuidof( ID3D10Texture2D ), ( LPVOID* )&pBackBuffer )取得我们的画布,也就是我们所使用的交换链的缓冲区;然后用g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView )把画布放到相框里;最后用g_pd3dDevice->OMSetRenderTargets( 1, &g_pRenderTargetView, NULL )把画布挂到墙上让观众欣赏。其实微软这样做的目的大概是为了让渲染管线可以更加确切地判断数据类型,对提高效率应该是有一定帮助的吧,拭目以待。
2.渲染代码
//--------------------------------------------------------------------------------------
// Render the frame
//--------------------------------------------------------------------------------------
void Render()
{
// Just clear the backbuffer
float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; //red,green,blue,alpha
g_pd3dDevice->ClearRenderTargetView( g_pRenderTargetView, ClearColor );
g_pSwapChain->Present( 0, 0 );
}
这部分很好理解,无非就是先用指定颜色清空渲染目标视口,也就是管你相框里有没有话,先贴上待售的标志。然后交换链开始工作,把我们画好的画布镶到框框里,观众就可以欣赏我们的蒙娜丽莎了。
3.清除代码
和谐社会需要环保,我们用完的东西也不能乱扔哦,砸到花花草草就不好了,所以要记得用完的东西送回收站:)
//--------------------------------------------------------------------------------------
// Clean up the objects we've created
//--------------------------------------------------------------------------------------
void CleanupDevice()
{
if( g_pd3dDevice ) g_pd3dDevice->ClearState();
if( g_pRenderTargetView ) g_pRenderTargetView->Release();
if( g_pSwapChain ) g_pSwapChain->Release();
if( g_pd3dDevice ) g_pd3dDevice->Release();
}
这部分比渲染更直观,我们创建了什么就释放什么就是了,要养成爱护环境的好习惯。
OK,今天终于凭着意志完成了计划,虽然还是个绿框框,没什么成就感,但我们已经跨出第一步,面包会有的,成就感也会有的,吼吼,明天我们就来创建DX的Hello World:可爱的三角形。