“如何入门DX呢?”这句话不知道被说过多少次。
“看红龙书。”这句话也不知道被说过多少次。
这就是一个菜鸟在次时代的困惑,而那个答案,也许是对的,但绝对不适合所有人。
DX11已经几个年头,这到底是个什么东西呢?本菜决定去看看究竟:
传送门:DX11教程1
这个教程言简意赅,所有重要的也都说了(虽然是用英语说- -!),我不知道大家怎么样,我时常抓不住重点,从小上课就是,所以我决定这次自己总结下重点。
撇开使用win32 api创建窗口部分,单纯说说DX11的基础使用流程。其实你不必担心自己会不会窗口创建哪部分代码,因为它其实跟初始化DX一样是固定流程,然后你以后写代码的时候会一次又一次的遇到,现在不必可以花时间去背,随着使用的频率你慢慢就胸有成竹了,好了说正题。
我发现这个教程的代码里有几个全局变量,可以说是建一个正常的DX11程序所需要的最少变量数了,它们是:
ID3D11Device,它表示一个显卡对象,它是虚拟的,也就是说你一个显卡可以有多个代表它的Device对象存在,但你一个Device只能表示一个真实的物理显卡。它是干嘛呢?主要用来创建DX要用的资源以及提供显卡的性能信息。
ID3D11DeviceContext,在DX11的世界里,就这个接口和上面那个能耐最大,也最主要。因为上面的负责创建,这个负责使用。文档描述它产生commandlist,这个东西由于我在DX9中没见过,所以没太深感触(远处飘渺的声音:吹吧,你就是DX9也没什么感触。。。),目前我理解它就是直接对显卡发送指令,显卡工作。而cmdlist可以把runtime时候它发过的指令存起来,然后重复使用,而这个从cmdlist就好像CPU的cache一样可以是运行速度加快。
IDXGISwapChain,交换链,dx9就有的概念,不过现在被更加明确化了。初学者比如我,一般就用一个后备缓冲和一个前屏表面。
ID3D11RenderTargetView,在dx9我保证没有的东西,这个接口的出现是因为DX11中资源与view概念的出现,资源就是一块内存,然后不同的view就好像强类型转换一样使GPU明白它要用的那块内存是什么资源。同时,DX11里没有默认的视口,在DX9中加入我们完成初始化后直接运行,被渲染的是整个窗口或全屏,而在dx11里你没有这种默认设定,所以你必须自己指定视口的大小。一般他们要和你的窗口一样大,但有一点需要注意的是窗口的大小包括标题栏这些非客户区。
看看这个例子的代码,你会发现,上面4个主要接口,有3个可以在一个API调用中初始化,那就是:
D3D11CreateDeviceAndSwapChain, 在调用前你需要填充一个DXGI_SWAP_CHAIN_DESC,然后可以在每一个你不懂的参数上用NULL代替。
建立完之后,设置视口就可以了。
总结下就是:每当想到DX11,你会想到显卡,所以你就会想到你要用显卡的话必须有它的引用你才能用。于是想到了Device,它就是一个虚拟的显卡一样,接着你想到要使用,于是你又想到了contex。然后你决定创建一个实例来起动显卡工作,你会记起那个createDev&chain,填充参数时候你会被提示需要什么东西。最后要记得的就是万事俱备,就差设置视口了。设置后,DX11就为你所用了。
下面是我一个修改过的源码,它更加纯粹也更加清楚一点初始化的过程,去掉了一些“繁文缛节”,替换例子中的对应函数就可以运行了:
HRESULT InitDevice()
{
HRESULT hr = S_OK;
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
};
UINT numFeatureLevels = ARRAYSIZE( featureLevels );
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory( &sd, sizeof( sd ) );
sd.BufferCount = 1;
sd.BufferDesc.Width = 640; //width和height你可以调整为适合你的视口
sd.BufferDesc.Height = 480;
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;
g_driverType = driverTypes[driverTypeIndex];
hr = D3D11CreateDeviceAndSwapChain( NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0,featureLevels, numFeatureLevels,
D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );
if( FAILED( hr ) )
return hr;
// Create a render target view
ID3D11Texture2D* pBackBuffer = NULL;
hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )&pBackBuffer );
if( FAILED( hr ) )
return hr;
hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView );
pBackBuffer->Release();
if( FAILED( hr ) )
return hr;
g_pImmediateContext->OMSetRenderTargets( 1, &g_pRenderTargetView, NULL );
// Setup the viewport
D3D11_VIEWPORT vp;
vp.Width = 640f;
vp.Height = 480f;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
g_pImmediateContext->RSSetViewports( 1, &vp );
return S_OK;
}