DX11 遊戲開發筆記 (二) DX11 基礎框架 上

必須吐槽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)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章