必須吐槽csdn的排版,真的是對不起它的名字!
抱了很大的決心,才決定寫下這篇博文,筆者大三從其它專業轉行,學習c c++也就一年多,因爲入了遊戲這坑,
故選擇在遊戲引擎這塊泥濘的道路上前進,且行且開心吧。
不得不吐槽一句,國內想學遊戲開發還真是有點難度,幸好有前輩的發掘,我們現在纔好走一點。
前輩博客:https://blog.csdn.net/bonchoix?t=1 。
近來看了《大話設計模式》,覺得編者的講解方式真是新奇有趣又貼入主題,故此筆者模仿其寫法,試試能不能將DX11回顧的更有意思一些。
人物介紹:小白(熟悉win32,c++,c,數據結構與算法);
人物介紹: 老鳥(一名圖形與遊戲引擎大牛)。
小白:啦啦啦,(哼着歌開心的走進門)。
老鳥:發生什麼事了?這麼開心,是不是想請我吃飯啦。
小白:我今天開“阿卡麗神祕商店”開到了一折,而且裏面還有我最想要的“刀妹”的皮膚,
只需9.9元就可以買到它啦。
老鳥:切,我還以爲你漲工資,要請我吃飯了,原來是因爲要花錢買皮膚,真是:土豪,這麼有錢,
請我搓一頓怎麼樣? 不過3D遊戲還真是有吸引力,能讓你這麼開心。
小白:是呀,但我不只玩遊戲的,我還看它優異的畫質,流暢的動畫,精細的模型,打擊的真實感,
引人入勝的劇情關卡設計..........
老鳥:看樣子你對遊戲還有一番見解呀,那你知道3d遊戲底層是怎麼實現的嗎?你想不想一探
遊戲引擎這個新大陸呢?瞭解之後就可以跟室友吹噓啦。
小白:瞧你說的,我是顯擺的人嗎,你跟我講講唄,我也想開拓一下見識。
老鳥:3D遊戲通常是由引擎寫出來的,一個好的大型的遊戲往往有其自己的引擎,現在比較優秀的
是“虛幻引擎”,但所有引擎都 有最基本的構建,就拿windows這個平臺來說,我們最喜歡和
最該接觸的就是DX,通常,我們講到DirectX的時候,都是指的Direct3D,因爲Direct3D
作爲正面對抗OpenGL的重要武器,受到了微軟最多的關懷與多次針對性的更新。所以Direct3D
在DirectX的 陣營中的認知度最高,它的光芒完全掩蓋了其他DirectX API的發揮空間。DirectX
中其他的大多數 API有些被更新換代淘汰掉了,或者有輕微的變化,今天我們就來講DX11。
小白:哇,感覺好龐大的樣子。
老鳥:當然啦,不然怎麼能做出這麼多優秀的遊戲了,
我記得你剛剛學習完win32,寫一個簡單窗口應該沒問題吧。
小白:那當然了,我寫給你看看。
五分鐘後,小白寫的代碼如下:
#include <windows.h>
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
#define WINDOW_TITLE L"【D3D11初始化demo】"
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
{
WCHAR className[32] = L"D3D11_demo_01";
WNDCLASS Wnd;
Wnd.cbClsExtra = NULL;
Wnd.cbWndExtra = NULL;
Wnd.hCursor = NULL;
Wnd.style = CS_VREDRAW | CS_HREDRAW;
Wnd.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
Wnd.hIcon = NULL;
Wnd.hInstance = hInstance;
Wnd.lpfnWndProc = WndProc;
Wnd.lpszClassName = className;
Wnd.lpszMenuName = NULL;
if (!RegisterClass(&Wnd))
{
return -1;
}
int Posx = 200;
int Posy = 100;
HWND hWnd = CreateWindow(className, WINDOW_TITLE,
WS_SYSMENU | WS_OVERLAPPED | WS_MINIMIZEBOX,
Posx, Posy, SCREEN_WIDTH, SCREEN_HEIGHT,
NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nShowCmd);
UpdateWindow(hWnd);
MSG msg = { 0 };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
老鳥:嗯恩,不錯,看來你win32還是掌握好基礎了,學習DX也就需要這些,我先爲你介紹DX11這座大營:
ID3D11Device* md3dDevice:
D3D11設備指針,掌管DX11的生死大權,爲硬漢集團首領。
ID3D11DeviceContext* md3dImmediateContext:
D3D11設備上下文,即爲DX11的監軍(副帥),爲智囊團的代表。
IDXGISwapChain* md3dSwapChain:
D3D交換鏈,爲軍隊的兵器馬匹,爲戰爭需準備的資源。
DX11軍營統兵調度需此三樣,缺一不可。
但是我們第一步要做的只是指明這三人或物,即聲明,但不着急着用。
#define HR(X) {if(FAILED(X)) { MessageBox(0,L"Create Failed",0,0); return false;}}
ID3D11Device* md3dDevice;//D3D11設備
ID3D11DeviceContext* md3dImmediateContext;//D3D11設備上下文
IDXGISwapChain* md3dSwapChain;//D3D交換鏈
俗話說,兵馬未動,糧草先行,我們得先去要聖旨: IDXGIFactory* factory;
//創建一個Directx圖形接口factory
HR(CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory));
獲得聖旨的許可權了,我們需派一個總領:IDXGIAdapter* adpter;//適配器,
//使用factory來爲顯卡創建一個adapter
HR(factory->EnumAdapters(0, &adpter));
總領然後就開始點去糧倉的小弟:IDXGIOutput* adapterOutput;
//列舉主要的適配器輸出
HR(adpter->EnumOutputs(0, &adapterOutput));
小弟就去糧倉了,然後記錄並回報適合本次戰役的糧倉信息。
首先記錄符合初步規定糧倉的信息和數目: unsigned int numModes;
而後建立一個對應數量的記錄本:DXGI_MODE_DESC* displayModeList;
再把相應數目的糧倉信息記錄。
unsigned int numModes;
DXGI_MODE_DESC* displayModeList;
//獲取適應適配器DXGI_FORMAT_R8G8B8A8_UNORM顯示格式的模式數目
HR(adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_ENUM_MODES_INTERLACED, &numModes, NULL));
//創建一個顯示模式列表存放可能的顯示模式(顯卡,監視器)
displayModeList = new DXGI_MODE_DESC[numModes];
if (!displayModeList)
return false;
//填充顯示模式列表結構體
HR(adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_ENUM_MODES_INTERLACED, &numModes, displayModeList));
接下來計算最符合本次戰役糧倉運糧的效率:
fps = numerator / denominator;
分子numerator:時間t內刷新次數 (運糧量)
分母denominator:t(時間)
unsigned int numerator, denominator;
for (int i = 0; i<(int)numModes; i++)
{
if (displayModeList[i].Width == (unsigned int)SCREEN_WIDTH)
{
if (displayModeList[i].Height == (unsigned int)SCREEN_HEIGHT)
{
numerator = displayModeList[i].RefreshRate.Numerator;
denominator = displayModeList[i].RefreshRate.Denominator;
}
}
}
好了,這樣事情也就做完了,該覆命的覆命,該釋放的釋放。
//釋放顯示模式列表
delete[] displayModeList;
displayModeList = NULL;
ReleaseCOM(adpter);
ReleaseCOM(factory);
休息一下:
還記的筆者第一次玩lol選的就是寒冰,如今寒冰也從當年叢林小野貓變爲了源戰士,筆者更是度過了青春。
continue:
小白:挺有意思的,大哥,繼續呀。
老鳥:好噠,糧草事宜準備好後,我們應該去準備兵馬:
DXGI_SWAP_CHAIN_DESC sd;//交換鍊形容結構體
接下來就是配置屬性:
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory(&sd, sizeof(sd));
sd.BufferDesc.Width = SCREEN_WIDTH;
sd.BufferDesc.Height = SCREEN_HEIGHT;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
bool mVsyncEnable = true; //是否限幀渲染
if (mVsyncEnable) //限不限幀
{
sd.BufferDesc.RefreshRate.Numerator =60;
sd.BufferDesc.RefreshRate.Denominator = 1;
}
else
{
sd.BufferDesc.RefreshRate.Numerator = numerator;
sd.BufferDesc.RefreshRate.Denominator = denominator;
}
//關閉多重採樣
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
//是否進行全屏
bool fullscreen = false;
if (fullscreen)
{
sd.Windowed = false;
}
else
{
sd.Windowed = true;
}
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.BufferCount = 1; //背後緩存數量
sd.OutputWindow = g_hWnd; //交換鏈所屬的窗口
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
sd.Flags = 0;
老鳥:小白,聽說你英文不錯,翻譯翻譯一下上面sd的屬性唄。
小白:嘻嘻,那還不是手到擒來。
經老鳥修改後出爐:
sd.BufferCount = 1; 交換鏈下後臺緩存區數量。
sd.BufferDesc.Format: 交換鏈下緩衝區結構體下的像素格式。
sd.BufferDesc.ScanlineOrdering:交換鏈下緩衝區結構體下的排序掃描(光柵化)格式。
sd.BufferDesc.Scaling:交換鏈下緩衝區結構體下的縮放格式。
sd.SampleDesc.Count:交換鏈下采樣結構體下的每個像素的採樣數量。
sd.SampleDesc.Quality:交換鏈下采樣結構體下的像素採樣質量級別。
sd.OutputWindow = g_hWnd; 交換鏈所屬的窗口句柄。
sd.SwapEffect:交換鏈下顯卡驅動程序選擇的顯示模式。
sd.Flags:交換鏈下的全屏顯示模式的可選設置。
sd.BufferUsage:交換鏈下的後臺緩衝去的去處。
老鳥:這樣你基本上就能看懂了,
小白:完全不呀,我看不懂他們設置的意義。
老鳥:好吧,好吧,那我就把DX11的相關介紹給你貼上:
創建交換鏈,首先需要填充一個 DXGI_SWAP_CHAIN_DESC 結構體來描述,該結構體的定義如下:
typedef struct DXGI_SWAP_CHAIN_DESC {
DXGI_MODE_DESC BufferDesc;
DXGI_SAMPLE_DESC SampleDesc;
DXGI_USAGE BufferUsage;
UINT BufferCount;
HWND OutputWindow;
BOOL Windowed;
DXGI_SWAP_EFFECT SwapEffect;
UINT Flags;
} DXGI_SWAP_CHAIN_DESC;
DXGI_MODE_DESC 類型是另一個結構體,其定義如下:
typedef struct DXGI_MODE_DESC
{
UINT Width; // 後臺緩衝區寬度
UINT Height; // 後臺緩衝區高度
DXGI_RATIONAL RefreshRate; // 顯示刷新率
DXGI_FORMAT Format; // 後臺緩衝區像素格式
DXGI_MODE_SCANLINE_ORDER ScanlineOrdering;// display scanline mode
DXGI_MODE_SCALING Scaling; // display scaling mode
} DXGI_MODE_DESC;
注意:在下面的數據成員描述中,我們只涵蓋了一些常用的標誌值和選項,它們對於初學者來說
非常重要。對於其他標誌值和選項的描述,請參閱 SDK 文檔。
1.BufferDesc: 該結構體描述了我們所要創建的後臺緩衝區的屬性。我們主要關注的屬性有:
寬度、高度和像素格式;其他屬性的詳情請參閱 SDK 文檔。
2.SampleDesc: 多重採樣數量和質量級別。
typedef struct DXGI_SAMPLE_DESC {
UINT Count;
UINT Quality;
} DXGI_SAMPLE_DESC, *LPDXGI_SAMPLE_DESC;
3.BufferUsage: 設爲 DXGI_USAGE_RENDER_TARGET_OUTPUT,因爲我們要將
場景渲染到後臺緩衝區(即將它用作渲染目標)。
4.BufferCount: 交換鏈中的後臺緩衝區數量;我們一般只用一個後臺緩衝區來實現雙
緩存。當然,你也可以使用兩個後臺緩衝區來實現三緩存。
5.OutputWindow: 我們將要渲染到的窗口的句柄。
6.Windowed: 當設爲 true 時,程序以窗口模式運行;當設爲 false 時,程序以全屏
(full-screen)模式運行。
7.SwapEffect: 設爲 DXGI_SWAP_EFFECT_DISCARD,讓顯卡驅動程序選擇最高效
的顯示模式。
8.Flags : 可 選 的 標 志 值 ,如 果 設 爲DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH,
那麼當應用程序切換到全屏模式時,Direct3D 會自動選擇與當前的後臺緩衝區設置最匹配的顯示模式。
如果未指定該標誌值,那麼當應用程序切換到全屏模式時,Direct3D 會使用當前的桌面顯示模式。
我們在示例框架中沒有使用該標誌值,因爲對於我們的演示程序來說,在全屏模式下使用當前的
桌面顯示模式可以得到很好的效果。
老鳥:我不想貼出來的,以後這樣的文檔還是你自己去找纔有意義,龍書11的資源寫這篇博文的小主
上篇博文裏就有,你去找吧。
小白:辛苦你啦。
老鳥:嗯恩,我接受了,承接上文,DX11的兵馬糧草準備好了,我們的兩員大將也該帶着兵馬動身了,
D3D_FEATURE_LEVEL featureLevel;
featureLevel = D3D_FEATURE_LEVEL_11_0;
HR(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0,
&featureLevel, 1,D3D11_SDK_VERSION, &sd, &md3dSwapChain, &md3dDevice, NULL,
&md3dImmediateContext));
老鳥:下面是通過vs2013看函數源文件找到的,這是很常用的學習方法,跟查msdn一樣。
HRESULT WINAPI D3D11CreateDeviceAndSwapChain(
__in_opt IDXGIAdapter* pAdapter,//指定要爲哪個物理顯卡創建設備對象。當該參數設爲空值時,
//表示使用主顯卡。在本書的示例程序中,我們只使用主顯卡。
D3D_DRIVER_TYPE DriverType, //一般來講,該參數總是指定爲 D3D_DRIVER_TYPE_HARDWARE>
HMODULE Software,//----------//用於支持軟件光柵化設備(software rasterizer)。
//我們總是將該參數設爲0。
UINT Flags,//----------------//可選的設備創建標誌值。當以 release 模式生成程序時,
//該參數通常設爲 0。
//當以 debug 模式生成程序時,該參數應設爲:
//D3D11_CREATE_DEVICE_DEBUG:用以激活調試層。
__in_ecount_opt( FeatureLevels ) CONST D3D_FEATURE_LEVEL* pFeatureLevels,
UINT FeatureLevels,
UINT SDKVersion, //始終設爲 D3D11_SDK_VERSION。
__in_opt CONST DXGI_SWAP_CHAIN_DESC* pSwapChainDesc,
__out_opt IDXGISwapChain** ppSwapChain,
__out_opt ID3D11Device** ppDevice,
__out_opt D3D_FEATURE_LEVEL* pFeatureLevel,
__out_opt ID3D11DeviceContext** ppImmediateContext );
老鳥:這函數中FeatureLevels你可能看不懂,這裏我給你詳解一下:
Direct3D 11 提 出 了 特 徵 等 級 ( feature levels , 在 代 碼 中 由 枚 舉 類 型D3D_FEATURE_LEVEL 表示)的概念,
對應了定義了 d3d11 中定義瞭如下幾個等級以代表不同的 d3d 版本:
typedef enum D3D_FEATURE_LEVEL {
D3D_FEATURE_LEVEL_9_1 = 0x9100,
D3D_FEATURE_LEVEL_9_2 = 0x9200,
D3D_FEATURE_LEVEL_9_3 = 0x9300,
D3D_FEATURE_LEVEL_10_0 = 0xa000,
D3D_FEATURE_LEVEL_10_1 = 0xa100,
D3D_FEATURE_LEVEL_11_0 = 0xb000
} D3D_FEATURE_LEVEL;
特徵等級定義了一系列支持不同 d3d 功能的相應的等級(每個特徵等級支持的功能可參見 SDK
文檔),用意即如果一個用戶的硬件不支持某一特徵等級,程序可以選擇較低的等級。例如,
爲了支持更多的用戶,應用程序可能需要支持 Direct3D 11,10.1,9.3 硬件。程序會從
最新的硬件一直檢查到最舊的,即首先檢查是否支持 Direct3D 11,第二檢查 Direct3D 10.1,
然後是Direct3D 10,最後是 Direct3D 9。要設置測試的順序,可以使用下面的特徵等級數組。
(數組內元素的順序即特徵等級測試的順序):
D3D_FEATURE_LEVEL featureLevels [4] =
{
D3D_FEATURE_LEVEL_11_0, // First check D3D 11 support
D3D_FEATURE_LEVEL_10_1, // Second check D3D 10.1 support
D3D_FEATURE_LEVEL_10_0, // Next,check D3D 10 support
D3D_FEATURE_LEVEL_9_3 // Finally,check D3D 9.3 support
} ;
這個數組可以放置在 Direct3D 初始化方法中,方法會輸出數組中第一個可被支持的特徵等級。
例如,如果 Direct3D 報告數組中第一個可被支持的特徵等級是D3D_FEATURE_LEVEL_10_0,
程序就會禁用 Direct3D 11 和 Direct3D 10.1 的特徵,而使用 Direct3D 10 的繪製路徑。
老鳥:下面我們就來實際用下:
D3D_FEATURE_LEVEL features[3] ={D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3};
D3D_FEATURE_LEVEL myFeatureLevel;
HRESULT hr = D3D11CreateDevice(NULL,D3D_DRIVER_TYPE_HARDWARE,0,0,
features,3,D3D11_SDK_VERSION,&g_device,&myFeatureLevel,&g_deviceContext);
if(FAILED(hr))
{
MessageBox(NULL,L"創建d3d11設備失敗!",L"錯誤",MB_OK);
return FALSE;
}
本例採用的是D3D11CreateDevice,跟D3D11CreateDeviceAndSwapChain相比其實就少了交換鏈的部分,很容易就能理解。
ps:
(函數第5個參數)
__in_ecount_opt( FeatureLevels ) CONST D3D_FEATURE_LEVEL* pFeatureLevels:
就是特徵數組。
(函數第6個參數)
UINT FeatureLevels:數組元素個數。
(函數倒數第2個參數)
__out_opt D3D_FEATURE_LEVEL* pFeatureLevel:
返回 pFeatureLevels 數組中第一個支持的特徵等級
(如果pFeatureLevels 爲 null,則返回可支持的最高等級)。
老鳥:這樣我們的大將就準備開撥了,但是他們之間並不熟悉,我們只是把他們全配置好了,但還沒進行交互。
所以他們就有了第一次碰面,那是在軍營的後臺:
ID3D11RenderTargetView* md3dRenderTargetView; //D3D11渲染目標視圖
//--------------------------------------------------------------
//創建後臺緩存視圖
//--------------------------------------------------------------
ID3D11Texture2D*backBuffer;
ID3D11RenderTargetView* md3dRenderTargetView; //D3D11渲染目標視圖
md3dSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&backBuffer));
md3dDevice->CreateRenderTargetView(backBuffer, 0, &md3dRenderTargetView);
ReleaseCOM(backBuffer);
官方解釋:資源不能被直接綁定到一個管線階段;我們必須爲資源創建資源視圖,然後把資源視圖
綁定到不同的管線階段。尤其是在把後臺緩衝區綁定到管線的輸出合併器階段時
(使 Direct3D 可以在後臺緩衝區上執行渲染工作),
我們必須爲後臺緩衝區創建一個渲染目標視圖(render target view) )。
老鳥:第一次只是簡單會面,第二次就是要商談行軍佈陣事宜,更深一步的交流:
ID3D11DepthStencilView* md3dDepthStencilView; //D3D11深度(模板)視圖
//--------------------------------------------------------------
//填充2DTexture深度緩存(模板緩存)形容結構體,創建深度緩存(模板緩存)
//--------------------------------------------------------------
D3D11_TEXTURE2D_DESC depthStencilDesc;
ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));
depthStencilDesc.Width = SCREEN_WIDTH; //紋理的寬度,單位爲紋理元素(texel)。
depthStencilDesc.Height = SCREEN_HEIGHT; //紋理的高度,單位爲紋理元素(texel)。
depthStencilDesc.MipLevels = 1; //多級漸近紋理層(mipmap level)的數量。
depthStencilDesc.ArraySize = 1; //在紋理數組中的紋理數量。
depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;//一個DXGI_FORMAT枚舉類型成員,
//它指定了紋理元素的格式。
depthStencilDesc.SampleDesc.Count = 1;
depthStencilDesc.SampleDesc.Quality = 0;
depthStencilDesc.Usage = D3D11_USAGE_DEFAULT; //表示紋理用途的 D3D11_USAGE 枚舉類型成員。
depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; //指定該資源將會綁定到管線的哪個階段。
depthStencilDesc.CPUAccessFlags = 0; //指定 CPU 對資源的訪問權限。
depthStencilDesc.MiscFlags = 0; //可選的標誌值,與深度/模板緩衝區無關,所以設爲 0。
ID3D11Texture2D* md3dDepthStencilBuffer; //D3D11的“DepthStencil緩存”
ID3D11DepthStencilView* md3dDepthStencilView; //D3D11深度(模板)視圖
HR(md3dDevice->CreateTexture2D(
&depthStencilDesc,//已創建好的紋理的結構體
0,&md3dDepthStencilBuffer)); //指向深度緩存的指針
HR(md3dDevice->CreateDepthStencilView(
md3dDepthStencilBuffer, //我們基於這個深度模板緩存創建一個視圖
0,&md3dDepthStencilView));//指向深度模板緩存的指針
老鳥:接下來就是通力合作:
//把那些視圖綁定到輸出合併階段
md3dImmediateContext->OMSetRenderTargets(1, &md3dRenderTargetView, md3dDepthStencilView);
//第一個參數是我們將要綁定的渲染目標的數量;
”沆瀣一氣“,成爲一個人,
我們這裏只描述其眼睛(由智囊團指揮):D3D11_VIEWPORT viewport;
//第十,創建並設定視口
D3D11_VIEWPORT viewport;
viewport.Width = static_cast<float>(SCREEN_WIDTH);
viewport.Height = static_cast<float>(SCREEN_HEIGHT);
viewport.MinDepth = 0.0f; //MinDepth 表示深度緩衝區的最小值(0),
viewport.MaxDepth = 1.0f; //MaxDepth 表示深度緩衝區的最大值(1)。
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
md3dImmediateContext->RSSetViewports(1, &viewport);
老鳥:最後便是擺陣,蓄勢以待:
float color[4];
//設置清除緩存(backbuffer),設置每幀初始顏色
color[0] = 0.0f;
color[1] = 0.5f;
color[2] = 0.5f;
color[3] = 1.0f;
//用color清除背後緩存
md3dImmediateContext->ClearRenderTargetView(md3dRenderTargetView, color);
//清除深度緩存和模板緩存,設置每幀初始值
md3dImmediateContext->ClearDepthStencilView(md3dDepthStencilView,
D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
//因爲渲染已經完成,提交backbuffer到屏幕
bool mVsyncEnable = true; //是否限幀渲染
if (mVsyncEnable)
{
//限幀提交
md3dSwapChain->Present(1, 0);
}
else
{
//儘可能快提交
md3dSwapChain->Present(0, 0);
}
老鳥:至此,我們dx11軍形就擺好了,無論應對什麼樣的戰役我們都可以應對了,
小白,檢驗一下你的學習態度,就由你做個總結吧。
小白:yes,sir。
DX基本框架流程:(1)聲明大將與兵馬;
(2)準備好糧草;
(3)配置好兵馬;
(4)大將與兵馬合併;
(5)大將在後臺軍營第一次正式見面;
(6)大將之間深入詳談;
(7)通力合作,觀察敵情,擺陣。
老鳥:呀,總結的這麼好,看來你學的很不錯,孺子可教也。
鈴鈴鈴(我們一起學貓叫,一起喵喵喵),小白的電話響了,
小白:哦哦,5黑,好,我馬上來。 (掛掉電話)
小白:哥,我同學叫我玩遊戲去了,我先走了,嘻嘻,我要讓他們看看我的神級刀妹。
源碼鏈接:https://pan.baidu.com/s/1h7Zt_1bPAbgKpXdQzn8eYA
下節我們將以D3D11龍書的類組織形式回顧代碼。
當你打算放棄夢想的時候,告訴自己再多撐一天,一個星期,一個月,再多撐一年吧。
等到繁華落盡的時候,你會發現,拒絕退場的結果,是一種怎樣的美好。(轉自淺墨csdn)