本系列文章由zhmxy555(毛星雲)編寫,轉載請注明出處。
http://blog.csdn.net/zhmxy555/article/details/7707628
作者:毛星雲 郵箱: happylifemxy@qq.com 期待着與志同道合的朋友們相互交流
上一節里我們介紹了在邁入DirectX 11的學習旅程之后第一個demo創建的全過程。但由於知識銜接的需要,我們的第一個demo里面涉及到的大部分知識都是關於Win32的。而為了使之前講解的Blank Win32 Window Demo蛻變成我們期望的Direct3D的模樣,我們將在這節的筆記里面對Direct3D的入門級的基礎知識做一個詳細的介紹,以便在下節筆記里輕車熟路地寫出屬於我們的第一個完整的Direct3D11 Demo。
由於DirectX 11龐雜的知識體系,初學DirectX11在所難免地會面對浩如煙海而略顯枯燥的基礎知識的介紹,在依次介紹完必要的知識之后,淺墨會按照【Visual C++】游戲開發筆記系列專欄的傳統風格,逐步放出幾個有趣的基於DirectX 11的小游戲demo,敬請期待。
入門知識的第一步當然是進行DirectX開發環境的配置,這在筆記二十五里面有詳細介紹,詳情請移步:
【Visual C++】游戲開發筆記二十五 最簡化的DirectX 11開發環境的配置
下面就開始正題,我們將分八個部分對入門級的Direct3D知識進行一個講解。
一、 Direct3D的初始化
初始化Direct3D,我們需要完成以下四個步驟:
1.定義我們需要檢查的設備類型(device types)和特征級別(feature levels)
2.創建Direct3D設備,渲染設備(context)和交換鏈(swap chain)。
3.創建渲染目標(render target)。
4.設置視口(viewport)
這里只是給大家一個框架的概念,各個部分下面會詳細展開講解。
二、驅動設備類型與特征等級
在Direct3D 11中我們能使用的設備有硬件設備(hardware device),參考設備(reference device),軟件驅動設備(software driver device), 以及WARP設備 (WARP device)。
硬件設備(hardware device)是一個運行在顯卡上的D3D設備,在所有設備中運行速度是最快的。這將是我們日后討論最多的一種類型。
參考設備(reference device)是用於沒有可用的硬件支持時在CPU上進行渲染的設備。
簡言之,參考設備就是利用軟件,在CPU對硬件渲染設備的一個模擬。但是不幸的是,這種方式非常的低效,所以在開發過程中,沒有其他可用選擇的時候,我們才采用這種方式。比如新一代的DirectX發布了,市面上還沒有支持這種新版本DirectX的硬件,我們在開發過程中就只能采用這種方式來跑了。
軟件驅動設備(software driverdevice)是開發人員自己編寫的用於Direct3D的渲染驅動軟件。這種方式通常不推薦用於高性能或者對性能要求苛刻的應用程序,下面介紹的WARP設備將是更好的選擇。
WARP設備(WARPdevice)是一種高效的CPU渲染設備,可以模擬現階段所有的Direct3D特性。WARP使用了Windows Vista /Windows 7/Winodws 8中的Windows Graphic 運行庫中高度優化過的代碼作為支撐,這讓這種方式出類拔萃,相比與上文提到的參考設備(reference device)模式更加優秀。WARP設備在配置不高的機器上面可以達到化腐朽為神奇的功效。在我們的硬件不支持實時應用程序(real-time application)的情況下,用WARP設備作為替補是一個明智的選擇,因為相比而言,參考設備(reference device)的執行效率實在是無法令人恭維。即便如此,WARP設備的執行效率還是不能和硬件設備同日而語,畢竟它依舊是對硬件的一種模擬,即使這種模擬是非常高效的。
注意:這不是對設備類型一個完整的列舉,還有很多細枝末節的設備類型,在這里沒必要一一列舉
Direct3D的特征等級用於指定需要設定的設備目標。在這個專欄之中,我們將針對三種設備,第一種當然是我們的Direct3D 11設備,第二種為Direct3D 10.1設備,第三種為Direct3D 10.0設備。再這三種設備都無法支持的情況下,我們再選擇WARP設備或者參考設備作為后援。
下面貼出來的代碼段1為后面我們需要用到的驅動類型和特征級別的一個聲明。通過創建各種類型的數組,我們可以使用循環來嘗試首先創建我們最需要的設備,然后若執行失敗則繼續創建其他的設備類型。淺墨記得我們之前提到過,Win32宏ARRAYSIZE能夠用來返回一個數組的大小,Win32函數GetClientRect可以用來計算應用程序客戶區的大小。算出來的值會用於設置之后的D3D設備渲染的寬度和高度。
另外,需要記住Win32應用程序是分客戶區和非客戶區的,我們僅能在客戶區上進行渲染。
代碼段1 指明驅動設備類型和特征等級
- RECT dimensions;
- GetClientRect( hwnd, &dimensions );
- unsigned int width = dimensions.right - dimensions.left;
- unsigned int height = dimensions.bottom - dimensions.top;
- D3D_DRIVER_TYPE driverTypes[] =
- {
- D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP,D3D_DRIVER_TYPE_SOFTWARE
- };
- unsigned int totalDriverTypes = ARRAYSIZE( driverTypes );
- D3D_FEATURE_LEVEL featureLevels[] =
- {
- D3D_FEATURE_LEVEL_11_0,
- D3D_FEATURE_LEVEL_10_1,
- D3D_FEATURE_LEVEL_10_0
- };
- unsigned int totalFeatureLevels = ARRAYSIZE( featureLevels );
RECT dimensions;
GetClientRect( hwnd, &dimensions );
unsigned int width = dimensions.right - dimensions.left;
unsigned int height = dimensions.bottom - dimensions.top;
D3D_DRIVER_TYPE driverTypes[] =
{
D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP,D3D_DRIVER_TYPE_SOFTWARE
};
unsigned int totalDriverTypes = ARRAYSIZE( driverTypes );
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0
};
unsigned int totalFeatureLevels = ARRAYSIZE( featureLevels );
三、設備與交換鏈的創建
下一步便是創建一個交換鏈,交換鏈在Direct3D中為一個設備渲染目標的集合。每一個設備都有至少一個交換鏈,而多個交換鏈能夠被多個設備所創建。一個交換目標可以為一個渲染和顯示到屏幕上的顏色緩存(在后面會討論),等等。
通常在游戲中有,有兩種顏色緩存,分別叫做主緩存和輔助緩存,他們一起被稱為前后台緩存組合。主緩存中的內容(前台緩存)會顯示在屏幕上,而輔助緩存(后台緩存)用於繪制下一幀(真是兩個好基友-o-)。
渲染的發生非常之快,屏幕的一部分可以在顯示器完成顯示更新之前,在先前的結果為基礎上進行繪制。緩存之間的切換,可以進行一個良性的運作,前台在顯示圖像,后台正在為前台准備下一刻將要顯示的圖像,這樣做可以避免很多棘手的問題,提高了效率。
這種技術在計算機圖形學中叫做雙緩沖(doublebuffering),或者叫頁面翻轉(page flipping)(這種技術我們之前的一系列Win32 GDI demo中使用得比較勤,研究了之前的demo的朋友們應該已經耳濡目染了吧)。一個交換鏈能擁有一個或者多個這樣的緩沖。
代碼段2中列出了創建一個交換鏈的代碼。一個交換鏈的描述用來定義和創建符合我們需要的交換鏈。
代碼段2 對交換鏈的設置
- DXGI_SWAP_CHAIN_DESC swapChainDesc;
- ZeroMemory( &swapChainDesc, sizeof( swapChainDesc ) );
- swapChainDesc.BufferCount = 1;
- swapChainDesc.BufferDesc.Width = width;
- swapChainDesc.BufferDesc.Height = height;
- swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
- swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
- swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
- swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
- swapChainDesc.OutputWindow = hwnd;
- swapChainDesc.Windowed = true;
- swapChainDesc.SampleDesc.Count = 1;
- swapChainDesc.SampleDesc.Quality = 0;
DXGI_SWAP_CHAIN_DESC swapChainDesc;
ZeroMemory( &swapChainDesc, sizeof( swapChainDesc ) );
swapChainDesc.BufferCount = 1;
swapChainDesc.BufferDesc.Width = width;
swapChainDesc.BufferDesc.Height = height;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.OutputWindow = hwnd;
swapChainDesc.Windowed = true;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
這個范例中定義了D3D的多種取樣屬性,多重取樣(Multisampling)是一種用於采樣和平衡渲染像素的創建亮麗色彩變化之間的平滑過渡的一種技術。
緩存的使用和交換鏈的描述有大量的成員需要設置,但這些設置都是非常簡單的。緩存的對交換鏈的使用是設置下DXGI_USAGE_RENDER_TARGET_OUTPUT,以便交換鏈能夠用於輸出,或者換句話說,它能被渲染。
下一步是創建渲染上下文,渲染設備,以及我們擁有的交換鏈描述。D3D設備一般都是設備本身和硬件之間的通信,而D3D上下文是一種描述設備如何繪制的渲染設備上下文,這也包含了渲染狀態和其他的繪圖信息。
正如我們討論過的,交換鏈是設備和上下文將要繪制的渲染目標。
創建設備上下文,渲染上下文和交換鏈所需的代碼在代碼段3中詳細列出了,.這段代碼為下次內容即將展示的Direct3D 11 BlankWindows Demo的一個片段。
代碼段3 Direct3D設備,設備上下文,以及交換鏈的創建
- ID3D11Device device_;
- ID3D11Context d3dContext_;
- IDXGISwapChain swapChain_;
- unsigned int creationFlags = 0;
- #ifdef _DEBUG
- creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
- #endif
- HRESULT result;
- unsigned int driver = 0;
- for( driver = 0; driver < totalDriverTypes; ++driver )
- {
- result = D3D11CreateDeviceAndSwapChain( 0, driverTypes[driver],0,
- creationFlags, featureLevels, totalFeatureLevels,
- D3D11_SDK_VERSION, &swapChainDesc, &swapChain_,
- &d3dDevice_, &featureLevel_, &d3dContext_ );
- if( SUCCEEDED( result ) )
- {
- driverType_ = driverTypes[driver];
- break;
- }
- }
- if( FAILED( result ) )
- {
- DXTRACE_MSG( "Failed to create the Direct3D device!");
- return false;
- }
ID3D11Device device_;
ID3D11Context d3dContext_;
IDXGISwapChain swapChain_;
unsigned int creationFlags = 0;
#ifdef _DEBUG
creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
HRESULT result;
unsigned int driver = 0;
for( driver = 0; driver < totalDriverTypes; ++driver )
{
result = D3D11CreateDeviceAndSwapChain( 0, driverTypes[driver],0,
creationFlags, featureLevels, totalFeatureLevels,
D3D11_SDK_VERSION, &swapChainDesc, &swapChain_,
&d3dDevice_, &featureLevel_, &d3dContext_ );
if( SUCCEEDED( result ) )
{
driverType_ = driverTypes[driver];
break;
}
}
if( FAILED( result ) )
{
DXTRACE_MSG( "Failed to create the Direct3D device!");
return false;
}
交換鏈,設備和渲染上下文可以在單獨的Direct3D函數調用中被創建,或者通過特定對象的Direct3D來調用(例如用CreateSwapChain函數來專門創建一個交換鏈)。
這個函數為D3D11CreateDeviceAndSwapChain。在代碼段2中我們在每個驅動類型中循環,試圖創建一個合適得設備,或為一個硬件設備,或為一個WARP設備,抑或一個參考設備(reference device)。因為如果創建失敗,我們就無法初始化我們的Direct3D。
D3D11CreateDeviceAndSwapChain函數中包含了特征等級作為其參數, 所以如果至少有一個這樣的特征等級存在,而且若我們的設備類型也存在,這個函數才會執行成功。
其中D3D11CreateDeviceAndSwapChain函數具有如下的函數原型:
- HRESULT D3D11CreateDeviceAndSwapChain(
- IDXGIAdapter *pAdapter,
- D3D_DRIVER_TYPEDriverType,
- HMODULE Software,
- UINT Flags,
- const D3D_FEATURE_LEVEL*pFeatureLevels,
- UINT FeatureLevels,
- UINT SDKVersion,
- const DXGI_SWAP_CHAIN_DESC *pSwapChainDesc,
- IDXGISwapChain **ppSwapChain,
- ID3D11Device **ppDevice,
- D3D_FEATURE_LEVEL*pFeatureLevel,
- ID3D11DeviceContext**ppImmediateContext
- );
HRESULT D3D11CreateDeviceAndSwapChain( IDXGIAdapter *pAdapter, D3D_DRIVER_TYPEDriverType, HMODULE Software, UINT Flags, const D3D_FEATURE_LEVEL*pFeatureLevels, UINT FeatureLevels, UINT SDKVersion, const DXGI_SWAP_CHAIN_DESC *pSwapChainDesc, IDXGISwapChain **ppSwapChain, ID3D11Device **ppDevice, D3D_FEATURE_LEVEL*pFeatureLevel, ID3D11DeviceContext**ppImmediateContext );
四、 創建渲染目標視圖
一個渲染目標視圖是一個由Output MergerStage讀取的D3D資源。為了output merger能渲染一個后台緩存的交換鏈,我們為其創建一個渲染目標視圖。
由於紋理的概念說來話長,目前我們將紋理理解為一副圖像就行了,后面中我們將展開討論紋理的很多細節內容,。交換鏈的主緩存和輔助緩存為彩色的圖像,為了獲得它們的指針,我們一般會調用交換鏈中的函數GetBuffer。
得到指向緩存的指針后,我們調用Direct3D中的函數CreateRenderTargetView,來創建一個渲染目標視圖(rendertarget view.)。渲染目標視圖含有ID3D11RenderTargetView類型,而CreateRenderTargetView函數將創建我們視圖的2D紋理,渲染目標描述,我們創建的ID3D11RenderTargetView的對象地址為其函數變量。將渲染目標描述變量設為空給我們所有的表面的MIP映射水平都為0級,MIP映射水平也將在后面進行詳細討論。
我們完成渲染目標的創建之后,就能夠釋放指針到交換鏈的后台緩存了。因為得到了COM對象的一個引用,我們必須調用COM中的Release函數來減少引用的數量。這樣做會避免內存的泄露,因為我們不想應用程序退出后,系統仍然保留着這里內存,這將導致系統資源的浪費,而這種浪費是不科學的。
在每次我們想渲染一個特定的渲染目標的時候,必須在所有的繪制的函數調用之前對它進行設置。這個重任就交給了我們的OMSetRenderTarget函數,這個函數隸屬於output merger,在之后會講到。
代碼段4 渲染目標視圖的創建和綁定
- ID3D11RenderTargetView* backBufferTarget_;
- ID3D11Texture2D* backBufferTexture;
- HRESULT result = swapChain_->GetBuffer( 0, __uuidof(ID3D11Texture2D ),
- ( LPVOID* )&backBufferTexture );
- if( FAILED( result ) )
- {
- DXTRACE_MSG( "Failed to get the swap chain backbuffer!" );
- return false;
- }
- result = d3dDevice_->CreateRenderTargetView(backBufferTexture, 0,
- &backBufferTarget_ );
- if( backBufferTexture )
- backBufferTexture->Release( );
- if( FAILED( result ) )
- {
- DXTRACE_MSG( "Failed to create the render targetview!" );
- return false;
- }
- d3dContext_->OMSetRenderTargets( 1, &backBufferTarget_, 0);
ID3D11RenderTargetView* backBufferTarget_;
ID3D11Texture2D* backBufferTexture;
HRESULT result = swapChain_->GetBuffer( 0, __uuidof(ID3D11Texture2D ),
( LPVOID* )&backBufferTexture );
if( FAILED( result ) )
{
DXTRACE_MSG( "Failed to get the swap chain backbuffer!" );
return false;
}
result = d3dDevice_->CreateRenderTargetView(backBufferTexture, 0,
&backBufferTarget_ );
if( backBufferTexture )
backBufferTexture->Release( );
if( FAILED( result ) )
{
DXTRACE_MSG( "Failed to create the render targetview!" );
return false;
}
d3dContext_->OMSetRenderTargets( 1, &backBufferTarget_, 0);
在代碼段4中你會注意到我們采用了一個叫做DXTRACE_MSG的宏。這個宏用作debugging來用。在之后將進行更詳細的講解。
五、 視口
Direct3D中 的一個重點同時也是難點在於創建和設置視口。
視口定義了我們渲染到屏幕上的面積。在單人或者非分割畫面的多人游戲中一般都為全屏,所以我們設置視口的寬度和高度即為交換鏈的寬度和高度。對於分屏游戲,我們可以創建兩個視口,一個視口定義在屏幕上方,另一個定義在屏幕下方。為了渲染分屏視口,我們可以分別以兩位不同玩家的角度來渲染。
視點的創建由填充D3D11_VIEWPORT函數和設置調用上下文的RSSetViewports函數將其設置到渲染上下文中來完成。RSSetViewports函數需要我們設置的視口數量和視口對象的列舉。全屏視口的創建和設置的相關代碼在代碼段五中有列舉,其中X和Y標明左側和頂部屏幕的位置,最小和最大深度是0到1之間的值,表明了視口深度的最小和最大值。
代碼段5 全屏視口的創建和設置
- D3D11_VIEWPORT viewport;
- viewport.Width = static_cast<float>(width);
- viewport.Height = static_cast<float>(height);
- viewport.MinDepth = 0.0f;
- viewport.MaxDepth = 1.0f;
- viewport.TopLeftX = 0.0f;
- viewport.TopLeftY = 0.0f;
- d3dContext_->RSSetViewports( 1, &viewport );
D3D11_VIEWPORT viewport;
viewport.Width = static_cast<float>(width);
viewport.Height = static_cast<float>(height);
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
d3dContext_->RSSetViewports( 1, &viewport );
六、清除與顯示屏幕
渲染到屏幕需要幾個不同的步驟。第一步通常是清除相關渲染目標的表面。在大部分游戲中這一步包含了深度緩存等一系列內容。在下一節即將呈現的demo中我們將在本章稍后實施,我們將清除渲染目標視圖的顏色緩沖區到一種特定的顏色。這由調用D3D中的ClearRenderTargetView函數來完成。ClearRenderTargetView擁有如下的函數原型:
- void ClearRenderTargetView( ID3D11RenderTargetView*pRenderTargetView,
- const FLOAT ColorRGBA[4] );
void ClearRenderTargetView( ID3D11RenderTargetView*pRenderTargetView, const FLOAT ColorRGBA[4] );
注:目前的大部分商業游戲中在渲染之前清除顏色緩存並不是必須的,因為像天空這樣的環境圖形要確保每個像素都會被顏色緩存所覆蓋着。
ClearRenderTargetView函數以將被清理的渲染目標視圖作為其變量。為了清除屏幕,我們設定某種顏色作為我們需要的背景陰影的顏色。這種顏色可以是紅色,綠色,藍色,和透明色Alpha數組中任意指定的0.0到1.0之間的顏色。這里0.0表示強度為0,而1.0表示完全飽滿的強度。若對應於字節,1.0對應255。如果為紅綠藍顏色組合都為1.0,則會得到純白的顏色。下一步就是繪制場景的幾何形狀了,最后一步是調用交換鏈的Present函數在屏幕上顯示渲染緩沖區的內容。
Present函數具有以下的聲明:
- HRESULT IDXGISwapChain::Present( UINT SyncInterval, UINT Flags);
HRESULT IDXGISwapChain::Present( UINT SyncInterval, UINT Flags);
對Present函數的參數一個簡單的理解:syncinterval 同步間隔,
flags 演示的標志。
在第n個垂直空白之后,Syncinterval能被設置為0,1,2,3,4來顯示。垂直空白是當前幀的最后一列更新時間與下一幀的第一列更新時間的時間差。像電腦顯示器這樣的設備顯示更新像素為垂直的,一列一列進行更新的。
Present函數的flags值可被設為0,表示輸出到每一個緩沖區,設為DXGI_PRESENT_ TEST時則表示測試時不進行輸出,或為DXGI_PRESENT_DO_ NOT_SEQUENCE表示不進行排序地利用垂直空白同步輸出來顯示輸出。為達到預期的目的,我們可以只是傳遞0到Present函數來顯示我們的渲染結果。
代碼段五 展示了一個清屏和顯示視圖的例子。在后面我們將深入探究顏色緩存,深度存,使畫面流暢無比的雙緩沖等等。
代碼段6 清除渲染目標然后顯示顯得渲染場景
- float clearColor[4] = { 0.0f, 0.0f, 0.25f, 1.0f };
- d3dContext_->ClearRenderTargetView( backBufferTarget_,clearColor );
- swapChain_->Present( 0, 0 );
float clearColor[4] = { 0.0f, 0.0f, 0.25f, 1.0f };
d3dContext_->ClearRenderTargetView( backBufferTarget_,clearColor );
swapChain_->Present( 0, 0 );
七、關於格式
有時候我們需要創建指定的DXGI格式。格式可以用於描述一張圖像的布局,每種顏色的位數,或者頂點緩存的布局(后面會講到)。大多數情況下,DXGI格式用於描述交換鏈中的頂點布局。
舉個例子,DXGI_FORMAT_R8G8B8A8_UNORM,它表示我們定義的每一個RGBA組成部分的數據都為8位。
沒指名類型的格式我們稱作無類型格式(typeless formats)。他們為每個部分保存相同的位數,但是並不注重包含了什么類型的數據。如DXGI_FORMAT_R32G32B32A32_TYPELESS。常用的清單類型在下面中列出了。
常用的數據格式類型清單:
DXGI_FORMAT_R32G32B32A32_TYPELESS 128位RGBA無類型格式
DXGI_FORMAT_R32G32B32A32_FLOAT 128位RGBA浮點型格式
DXGI_FORMAT_R32G32B32A32_UINT 128位RGBA無符號整型格式
DXGI_FORMAT_R32G32B32A32_SINT 128位RGBA帶符號整型格式
DXGI_FORMAT_R8G8B8A8_TYPELESS 32位RGBA無類型格式
DXGI_FORMAT_R8G8B8A8_UINT 32位RGBA無符號整型格式
DXGI_FORMAT_R8G8B8A8_SINT 32位RGBA帶符號整型格式
當定義頂點格式的時候,比如DXGI_FORMAT_R32G32B32_FLOAT格式,就是說RGB值都支持是32位的數據類型。有時候,我們會看到特殊的為每一部分指定相同位數的格式,但是他們有不同的擴展名。
舉個例子,DXGI_FORMAT_R32G32B32A32_FLOAT 和DXGI_FORMAT_R32G32B32A32_UINT類型的各個部分的位數都是相同的,不同的各個位數上一個是32位的浮點型,一個是32位的無符號整型。
八、 善后工作
Direct3D應用程序中要做的最后一件事情,就是清除和釋放我們創建的對象。舉個例子,在應用程序開頭,我們要創建一個D3D的設備,一個D3D的渲染上下文,一個交換鏈,以及一個要渲染的目標。當這個應用程序關閉的時候,我們需要釋放這些對象,以將這些資源返還給系統。
COM對象保持一個引用計數,告知系統什么時候從內存中移除這些對象是安全的。通過運用Release函數,我們減少了一個對象的引用數量。當引用數量達到0,系統便會回收這些資源。
下面是一個釋放D3D對象的范例。用首先用if條件句來確保對象不為null,然后調用Release函數。通常我們以和創建時相反的順序來釋放這些對象。
代碼段7 釋放Direct3D 11 main對象
- if( backBufferTarget_ )backBufferTarget_->Release( );
- if( swapChain_ ) swapChain_->Release( );
- if( d3dContext_ ) d3dContext_->Release( );
- if( d3dDevice_ ) d3dDevice_->Release( );
if( backBufferTarget_ )backBufferTarget_->Release( ); if( swapChain_ ) swapChain_->Release( ); if( d3dContext_ ) d3dContext_->Release( ); if( d3dDevice_ ) d3dDevice_->Release( );
心得:在釋放對象前,我們經常通過檢查來確保DirectX對象不為null。因為試圖釋放一個非法的指針是非常不科學的,這會使我們游戲程序的穩定性盪然無存,經常各種無故崩潰。
本篇文章到這里就結束了,謝謝欣賞。
感謝一直支持【Visual C++】游戲開發筆記系列專欄的朋友們。
【Visual C++】游戲開發 系列文章才剛剛展開一點而已,因為游戲世界實在是太博大精深了~
但我們不能着急,得慢慢打好基礎。做學問最忌好高騖遠,不是嗎?
淺墨希望看到大家的留言,希望與大家共同交流,希望得到睿智的評論(即使是批評)。
你們的支持是我寫下去的動力~
精通游戲開發的路還很長很長,非常希望能和大家一起交流,共同學習,共同進步。
大家看過后覺得值得一看的話,可以頂一下這篇文章,你們的支持是我繼續寫下去的動力~
如果文章中有什么疏漏的地方,也請大家指正。也希望大家可以多留言來和我探討相關的問題。
最后,謝謝你們一直的支持~~~
——————————淺墨於2012年7月1日
再分享一下我老師大神的人工智能教程吧。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智能的隊伍中來!https://blog.csdn.net/jiangjunshow
