とある都合でDirectX11でプログラムを組むことになりました。
…が,ここしばらくDirectXにはかなり久しくて,非常に不安です。そんなわけで,DirectX11を勉強していきます。
DirectX11 入門
★ 1.はじめに…
★ 2.まずはポリゴン表示から
一応,Windowsプログラムですが長年GLUTでプログラムを組んでいたせいか,コンソールウィンドウがあるとなぜか落ち着きます。
そんなわけで,wWinMainからウィンドウ生成ではなく,main関数からウィンドウを生成するようにしてみました。
今回は,ImmediateContext使っています。DeferredContextは,そのうちやります。今はまだやりません。
さて,中身の方の説明をちょろっとしていきます。
プログラムの構成ですが,大まかに分けると…
ウィンドウの生成と初期化に関しては,普通のWindowプログラムと同じなのですっ飛ばします。
デバイスの初期化の処理は下記のようになります。
D3D_DRIVER_TYPE_HARDWAREは,その名の通りハードウェア・ドライバ(HALドライバ)です。次の,D3D_DRIVER_TYPE_WARPは,高パフォーマンスのソフトウェア・ラスタライザを意味しています,D3D_DRIVER_TYPE_REFERENCEはリファレンス・ラスタライザ(REFドライバ)です。配列の要素として使いたい順に,一応記述してあります。
続いて,D3D_FEATURE_LEVELです。これは使用する機能レベルのことです。機能レベルとは,GPUがサポートする機能セットの厳密な定義です。基本的には,上位の機能レベルは下位の機能レベルの互換性があるようです。いまの所,機能レベルは下記のように6つあるようです。
次は,デバイスとスワップチェインの作成です。D3D11CreateDeviceAndSwapChain()関数により作成を行います。先程述べた,ドライバータイプや機能レベルは,この関数の入力引数として渡します。この関数は出力として,実行結果を返り値として渡し,作成されたスワップチェインのインタフェースと作成されたデバイスインタフェースと,サポートされている機能レベル,作成されたImmediateContextを出力引数として渡します。プログラムの方では,使いたい順にループ処理で関数を実行し,成功した時点でbreak文によりループ脱出する処理になっています。
デバイスとスワップチェインの生成に成功したら,次はバックバッファを取得して,描画対象となるビューを生成します。生成できたら,出力マネージャにビューを設定します。設定するには,ID3D11DeviceContext::OMSetRenderTargets()関数を使用します。
次に,ビューポートの設定をします。これも素直に数値を設定しているだけなので説明を省略します。
続いて,シェーダのコンパイルです。
シェーダのコンパイルにはD3DX11CompileFromFile()を使いました。処理は下記のようになります。
シェーダをコンパイルしたら,コンパイルしたバイトコードを渡してシェーダを生成します。ここまでは問題でしょう。
さて,面倒っちいのは入力レイアウトの設定です。なにが面倒っちいかというとシェーダごとに設定する必要があるからです。今回は,頂点シェーダに位置座標だけ送るので,下記のようなコードになっています。
あとは,ポリゴンを描画するための頂点バッファを設定します。 設定の仕方は,下記のようになります。コメントで書いてあるまんまです。
さて,いよいよ描画処理です。描画処理は以下のようになります。
あとは,Present()関数によりフリップ処理を行います。第一引数は,画面を更新するタイミングを指定します。上記例では0を指定しているので, 「同期を行なわず,直ぐに表示」という意味です。第二引数にはフラグを指定しますが,画面の更新を行うので0を指定しておきましょう。表示領域が存在するかチェックする場合にはDXGI_PRESENT_TESTを指定しますが,この時には画面更新は行われないそうです。
最後にデバイスのクリーンアップ処理です。各インタフェースのRelease()関数を呼び出して,解放処理を行いましょう。
一応,シェーダのコードも掲載しておきましょう。 単に,来たデータをそのまま流して,オレンジ色に塗りつぶすだけの簡単な処理です。
DirectX11でのポリゴン表示をやりました。
とりあえず,しょっぱななのでしょぼいプログラムであるのは勘弁してください。
そんなわけで,wWinMainからウィンドウ生成ではなく,main関数からウィンドウを生成するようにしてみました。
00079: //---------------------------------------------------------------------- 00080: //! @brief アプリケーションメインエントリーポイント 00081: //! @param [in] argc 引数の数 00082: //! @param [in] argv 引数の値 00083: //! @return システムへ値を返却する 00084: //---------------------------------------------------------------------- 00085: int main( int argc, char** argv ) 00086: { 00087: HINSTANCE hInst = GetModuleHandle( NULL ); 00088: 00089: // ウィンドウ初期化 00090: if ( FAILED( InitWnd( hInst, SW_SHOWNORMAL ) ) ) 00091: { 00092: printf( "InitWnd() Failed.\n" ); 00093: return 0; 00094: } 00095: 00096: // デバイス初期化 00097: if ( FAILED( InitDevice() ) ) 00098: { 00099: printf( "InitDevice() Failed.\n" ); 00100: return 0; 00101: } 00102: 00103: // メインループ 00104: MSG msg = { 0 }; 00105: while( WM_QUIT != msg.message ) 00106: { 00107: if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) 00108: { 00109: TranslateMessage( &msg ); 00110: DispatchMessage( &msg ); 00111: } 00112: else 00113: { 00114: // 描画 00115: Render(); 00116: } 00117: } 00118: 00119: // デバイスのクリーンアップ 00120: CleanupDevice(); 00121: 00122: return (int)msg.wParam; 00123: } 00124:プログラムの中身ですが,DirectX Sample BrowserにあるTutorialにジオメトリシェーダを付け足しただけの簡単なものです。
今回は,ImmediateContext使っています。DeferredContextは,そのうちやります。今はまだやりません。
さて,中身の方の説明をちょろっとしていきます。
プログラムの構成ですが,大まかに分けると…
(1)ウィンドウの生成 & 初期化 (2)デバイスの初期化 (3)メインループで描画 (4)デバイスのクリーンアップ処理というように4つから構成されています。
ウィンドウの生成と初期化に関しては,普通のWindowプログラムと同じなのですっ飛ばします。
デバイスの初期化の処理は下記のようになります。
00281: //----------------------------------------------------------------------- 00282: //! @brief デバイスの初期化 00283: //----------------------------------------------------------------------- 00284: HRESULT InitDevice() 00285: { 00286: HRESULT hr = S_OK; 00287: 00288: // ウィンドウサイズを取得 00289: RECT rc; 00290: GetClientRect( gDemoApp.hWnd, &rc ); 00291: UINT width = rc.right - rc.left; 00292: UINT height = rc.bottom - rc.top; 00293: 00294: UINT createDeviceFlags = 0; 00295: #if defined(DEBUG) || defined(_DEBUG) 00296: createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; 00297: #endif 00298: 00299: // ドライバータイプ 00300: D3D_DRIVER_TYPE driverTypes[] = { 00301: D3D_DRIVER_TYPE_HARDWARE, 00302: D3D_DRIVER_TYPE_WARP, 00303: D3D_DRIVER_TYPE_REFERENCE, 00304: }; 00305: UINT numDriverTypes = sizeof( driverTypes ) / sizeof( driverTypes[0] ); 00306: 00307: // 機能レベル 00308: D3D_FEATURE_LEVEL featureLevels[] = { 00309: D3D_FEATURE_LEVEL_11_0, 00310: D3D_FEATURE_LEVEL_10_1, 00311: D3D_FEATURE_LEVEL_10_0, 00312: }; 00313: UINT numFeatureLevels = sizeof( featureLevels ) / sizeof( featureLevels[0] ); 00314: 00315: // スワップチェインの設定 00316: DXGI_SWAP_CHAIN_DESC sd; 00317: ZeroMemory( &sd, sizeof(sd) ); 00318: sd.BufferCount = 1; 00319: sd.BufferDesc.Width = width; 00320: sd.BufferDesc.Height = height; 00321: sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 00322: sd.BufferDesc.RefreshRate.Numerator = 60; 00323: sd.BufferDesc.RefreshRate.Denominator = 1; 00324: sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 00325: sd.OutputWindow = gDemoApp.hWnd; 00326: sd.SampleDesc.Count = 1; 00327: sd.SampleDesc.Quality = 0; 00328: sd.Windowed = TRUE; 00329: 00330: // デバイスとスワップチェインを作成する 00331: for( UINT idx = 0; idx < numDriverTypes; idx++ ) 00332: { 00333: gDemoApp.driverType = driverTypes[ idx ]; 00334: hr = D3D11CreateDeviceAndSwapChain( 00335: NULL, 00336: gDemoApp.driverType, 00337: NULL, 00338: createDeviceFlags, 00339: featureLevels, 00340: numFeatureLevels, 00341: D3D11_SDK_VERSION, 00342: &sd, 00343: &gDemoApp.pSwapChain, 00344: &gDemoApp.pDevice, 00345: &gDemoApp.featureLevel, 00346: &gDemoApp.pDeviceContext ); 00347: 00348: if ( SUCCEEDED( hr ) ) 00349: { 00350: // 成功したらループ脱出 00351: break; 00352: } 00353: } 00354: if ( FAILED( hr ) ) 00355: { 00356: // 作成に失敗したら終了 00357: return hr; 00358: } 00359: 00360: // バックバッファ取得 00361: ID3D11Texture2D* pBackBuffer = NULL; 00362: hr = gDemoApp.pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (LPVOID*)&pBackBuffer ); 00363: if ( FAILED( hr ) ) 00364: { 00365: return hr; 00366: } 00367: 00368: // レンダーターゲットビューを生成 00369: hr = gDemoApp.pDevice->CreateRenderTargetView( pBackBuffer, NULL, &gDemoApp.pRenderTargetView ); 00370: pBackBuffer->Release(); 00371: pBackBuffer = NULL; 00372: if ( FAILED( hr ) ) 00373: { 00374: return hr; 00375: } 00376: 00377: // 出力マネージャにレンダーターゲットビューを設定 00378: gDemoApp.pDeviceContext->OMSetRenderTargets( 1, &gDemoApp.pRenderTargetView, NULL ); 00379: 00380: // ビューポートの設定 00381: D3D11_VIEWPORT vp; 00382: vp.Width = (FLOAT)width; 00383: vp.Height = (FLOAT)height; 00384: vp.MinDepth = 0.0f; 00385: vp.MaxDepth = 1.0f; 00386: vp.TopLeftX = 0; 00387: vp.TopLeftY = 0; 00388: gDemoApp.pDeviceContext->RSSetViewports( 1, &vp ); 00389: 00390: // 頂点シェーダをコンパイル 00391: ID3DBlob* pVSBlob = NULL; 00392: hr = CompileShaderFromFile( TEXT("Contents/Effects/Sample.fx"), "VSFunc", "vs_4_0", &pVSBlob ); 00393: if ( FAILED( hr ) ) 00394: { 00395: MessageBox( NULL, 00396: TEXT( "he FX file cannot be compiled. Please run this executable from the directory that contains the FX file." ), 00397: TEXT( "Shader Compile Error" ), 00398: MB_OK | MB_ICONERROR ); 00399: return hr; 00400: } 00401: 00402: // 頂点シェーダ生成 00403: hr = gDemoApp.pDevice->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &gDemoApp.pVS ); 00404: if ( FAILED( hr ) ) 00405: { 00406: pVSBlob->Release(); 00407: pVSBlob = NULL; 00408: return hr; 00409: } 00410: 00411: // 入力レイアウトの定義 00412: D3D11_INPUT_ELEMENT_DESC layout[] = { 00413: { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, 00414: }; 00415: UINT numElements = sizeof( layout ) / sizeof( layout[0] ); 00416: 00417: // 入力レイアウトを生成 00418: hr = gDemoApp.pDevice->CreateInputLayout( 00419: layout, 00420: numElements, 00421: pVSBlob->GetBufferPointer(), 00422: pVSBlob->GetBufferSize(), 00423: &gDemoApp.pVertexLayout ); 00424: pVSBlob->Release(); 00425: pVSBlob = NULL; 00426: if ( FAILED( hr ) ) 00427: { 00428: return hr; 00429: } 00430: 00431: // 入力アセンブラに入力レイアウトを設定 00432: gDemoApp.pDeviceContext->IASetInputLayout( gDemoApp.pVertexLayout ); 00433: 00434: // ジオメトリシェーダコンパイル 00435: ID3DBlob* pGSBlob = NULL; 00436: hr = CompileShaderFromFile( TEXT("Contents/Effects/Sample.fx"), "GSFunc", "gs_4_0", &pGSBlob ); 00437: if ( FAILED( hr ) ) 00438: { 00439: MessageBox( 00440: NULL, 00441: TEXT( "The FX file cannot be compiled. Please run this executable from the directory that contains the FX file." ), 00442: TEXT( "Shader Compile Error" ), 00443: MB_OK | MB_ICONERROR ); 00444: return hr; 00445: } 00446: 00447: // ジオメトリシェーダを生成 00448: hr = gDemoApp.pDevice->CreateGeometryShader( 00449: pGSBlob->GetBufferPointer(), 00450: pGSBlob->GetBufferSize(), 00451: NULL, 00452: &gDemoApp.pGS ); 00453: pGSBlob->Release(); 00454: pGSBlob = NULL; 00455: if ( FAILED( hr ) ) 00456: { 00457: return hr; 00458: } 00459: 00460: // ピクセルシェーダコンパイル 00461: ID3DBlob* pPSBlob = NULL; 00462: hr = CompileShaderFromFile( TEXT("Contents/Effects/Sample.fx"), "PSFunc", "ps_4_0", &pPSBlob ); 00463: if ( FAILED( hr ) ) 00464: { 00465: MessageBox( 00466: NULL, 00467: TEXT( "The FX file cannot be compiled. Please run this executable from the directory that contains the FX file." ), 00468: TEXT( "Shader Compile Error" ), 00469: MB_OK | MB_ICONERROR ); 00470: return hr; 00471: } 00472: 00473: // ピクセルシェーダ生成 00474: hr = gDemoApp.pDevice->CreatePixelShader( 00475: pPSBlob->GetBufferPointer(), 00476: pPSBlob->GetBufferSize(), 00477: NULL, 00478: &gDemoApp.pPS ); 00479: pPSBlob->Release(); 00480: pPSBlob = NULL; 00481: if ( FAILED( hr ) ) 00482: { 00483: return hr; 00484: } 00485: 00486: // 頂点の定義 00487: CustomVertex vertices[] = { 00488: XMFLOAT3( 0.0f, 0.5f, 0.5f ), 00489: XMFLOAT3( 0.5f, -0.5f, 0.5f ), 00490: XMFLOAT3( -0.5f, -0.5f, 0.5f ), 00491: }; 00492: 00493: // 頂点バッファの設定 00494: D3D11_BUFFER_DESC bd; 00495: ZeroMemory( &bd, sizeof(bd) ); 00496: bd.Usage = D3D11_USAGE_DEFAULT; 00497: bd.ByteWidth = sizeof( CustomVertex ) * 3; 00498: bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; 00499: bd.CPUAccessFlags = 0; 00500: 00501: // サブリソースの設定 00502: D3D11_SUBRESOURCE_DATA initData; 00503: ZeroMemory( &initData, sizeof(initData ) ); 00504: initData.pSysMem = vertices; 00505: 00506: // 頂点バッファ生成 00507: hr = gDemoApp.pDevice->CreateBuffer( &bd, &initData, &gDemoApp.pVertexBuffer ); 00508: if ( FAILED( hr ) ) 00509: { 00510: return hr; 00511: } 00512: 00513: // 入力アセンブラに頂点バッファを設定 00514: UINT stride = sizeof( CustomVertex ); 00515: UINT offset = 0; 00516: gDemoApp.pDeviceContext->IASetVertexBuffers( 0, 1, &gDemoApp.pVertexBuffer, &stride, &offset ); 00517: 00518: // プリミティブの種類を設定 00519: gDemoApp.pDeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); 00520: 00521: return S_OK; 00522: } 00523:まず,ドライバーレベルから行きましょう。ドライバーレベルはD3D11CreateDeviceAndSwapChain()の第2引数として設定します。
D3D_DRIVER_TYPE_HARDWAREは,その名の通りハードウェア・ドライバ(HALドライバ)です。次の,D3D_DRIVER_TYPE_WARPは,高パフォーマンスのソフトウェア・ラスタライザを意味しています,D3D_DRIVER_TYPE_REFERENCEはリファレンス・ラスタライザ(REFドライバ)です。配列の要素として使いたい順に,一応記述してあります。
続いて,D3D_FEATURE_LEVELです。これは使用する機能レベルのことです。機能レベルとは,GPUがサポートする機能セットの厳密な定義です。基本的には,上位の機能レベルは下位の機能レベルの互換性があるようです。いまの所,機能レベルは下記のように6つあるようです。
D3D_FEATURE_LEVEL_11_0 → Direct3D 11のGPUレベル D3D_FEATURE_LEVEL_10_1 → Direct3D 10.1のGPUレベル D3D_FEATURE_LEVEL_10_0 → Direct3D 10のGPUレベル D3D_FEATURE_LEVEL_9_3 → Direct3D 9.3のGPUレベル D3D_FEATURE_LEVEL_9_2 → Direct3D 9.2のGPUレベル D3D_FEATURE_LEVEL_9_1 → Direct3D 9.1のGPUレベル続いて,DXGI_SWAP_CHAIN_DESC構造体の設定です。はやい話がバックバッファとかの設定です。特別な設定は今回しないので,説明はスルーします。
次は,デバイスとスワップチェインの作成です。D3D11CreateDeviceAndSwapChain()関数により作成を行います。先程述べた,ドライバータイプや機能レベルは,この関数の入力引数として渡します。この関数は出力として,実行結果を返り値として渡し,作成されたスワップチェインのインタフェースと作成されたデバイスインタフェースと,サポートされている機能レベル,作成されたImmediateContextを出力引数として渡します。プログラムの方では,使いたい順にループ処理で関数を実行し,成功した時点でbreak文によりループ脱出する処理になっています。
デバイスとスワップチェインの生成に成功したら,次はバックバッファを取得して,描画対象となるビューを生成します。生成できたら,出力マネージャにビューを設定します。設定するには,ID3D11DeviceContext::OMSetRenderTargets()関数を使用します。
次に,ビューポートの設定をします。これも素直に数値を設定しているだけなので説明を省略します。
続いて,シェーダのコンパイルです。
シェーダのコンパイルにはD3DX11CompileFromFile()を使いました。処理は下記のようになります。
00226: //----------------------------------------------------------------------- 00227: //! @brief ファイルからシェーダをコンパイル 00228: //! @param [in] szFileName ファイル名 00229: //! @param [in] szEntryPoint エントリーポイント名 00230: //! @param [in] szShaderMode シェーダプロファイル 00231: //! @param [out] ppBlobOut コンパイルされたバイトコード 00232: //----------------------------------------------------------------------- 00233: HRESULT CompileShaderFromFile 00234: ( 00235: TCHAR* szFileName, 00236: LPCSTR szEntryPoint, 00237: LPCSTR szShaderModel, 00238: ID3DBlob** ppBlobOut 00239: ) 00240: { 00241: HRESULT hr = S_OK; 00242: 00243: DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS; 00244: #if defined(DEBUG) || defined(_DEBUG) 00245: dwShaderFlags |= D3DCOMPILE_DEBUG; 00246: #endif 00247: 00248: ID3DBlob* pErrorBlob; 00249: 00250: // シェーダをファイルからコンパイル 00251: hr = D3DX11CompileFromFile( 00252: szFileName, 00253: NULL, 00254: NULL, 00255: szEntryPoint, 00256: szShaderModel, 00257: dwShaderFlags, 00258: 0, 00259: NULL, 00260: ppBlobOut, 00261: &pErrorBlob, 00262: NULL ); 00263: if ( FAILED( hr ) ) 00264: { 00265: if ( pErrorBlob != NULL ) 00266: { 00267: // エラーメッセージ出力 00268: OutputDebugStringA( (char*)pErrorBlob->GetBufferPointer() ); 00269: } 00270: } 00271: 00272: if ( pErrorBlob ) 00273: { 00274: pErrorBlob->Release(); 00275: pErrorBlob = NULL; 00276: } 00277: 00278: return hr; 00279: }まぁ,単に垂れ流ししているだけですね。
シェーダをコンパイルしたら,コンパイルしたバイトコードを渡してシェーダを生成します。ここまでは問題でしょう。
さて,面倒っちいのは入力レイアウトの設定です。なにが面倒っちいかというとシェーダごとに設定する必要があるからです。今回は,頂点シェーダに位置座標だけ送るので,下記のようなコードになっています。
00411: // 入力レイアウトの定義 00412: D3D11_INPUT_ELEMENT_DESC layout[] = { 00413: { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, 00414: }; 00415: UINT numElements = sizeof( layout ) / sizeof( layout[0] ); 00416: 00417: // 入力レイアウトを生成 00418: hr = gDemoApp.pDevice->CreateInputLayout( 00419: layout, 00420: numElements, 00421: pVSBlob->GetBufferPointer(), 00422: pVSBlob->GetBufferSize(), 00423: &gDemoApp.pVertexLayout ); 00424: pVSBlob->Release(); 00425: pVSBlob = NULL; 00426: if ( FAILED( hr ) ) 00427: { 00428: return hr; 00429: } 00430: 00431: // 入力アセンブラに入力レイアウトを設定 00432: gDemoApp.pDeviceContext->IASetInputLayout( gDemoApp.pVertexLayout ); 00433:DX9とかと違って,セマンティクス名は勝手につけられるのですが長年親しんだ"POSITION"を一応設定しておきました。ここは"IN_POSITION"とか好き勝手に変えて問題ないです。レイアウトを定義したら,CreateInputLayout()関数で,シェーダへの入力レイアウトを生成します。生成したらIASetInputLayout()で入力アセンブラに生成された入力レイアウトを設定します。このようにすることで,POSITIONのセマンティクスがつけられたものにRGB各32ビットのfloatデータが各頂点ごとに送られるようになります。
あとは,ポリゴンを描画するための頂点バッファを設定します。 設定の仕方は,下記のようになります。コメントで書いてあるまんまです。
00486: // 頂点の定義 00487: CustomVertex vertices[] = { 00488: XMFLOAT3( 0.0f, 0.5f, 0.5f ), 00489: XMFLOAT3( 0.5f, -0.5f, 0.5f ), 00490: XMFLOAT3( -0.5f, -0.5f, 0.5f ), 00491: }; 00492: 00493: // 頂点バッファの設定 00494: D3D11_BUFFER_DESC bd; 00495: ZeroMemory( &bd, sizeof(bd) ); 00496: bd.Usage = D3D11_USAGE_DEFAULT; 00497: bd.ByteWidth = sizeof( CustomVertex ) * 3; 00498: bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; 00499: bd.CPUAccessFlags = 0; 00500: 00501: // サブリソースの設定 00502: D3D11_SUBRESOURCE_DATA initData; 00503: ZeroMemory( &initData, sizeof(initData ) ); 00504: initData.pSysMem = vertices; 00505: 00506: // 頂点バッファ生成 00507: hr = gDemoApp.pDevice->CreateBuffer( &bd, &initData, &gDemoApp.pVertexBuffer ); 00508: if ( FAILED( hr ) ) 00509: { 00510: return hr; 00511: } 00512: 00513: // 入力アセンブラに頂点バッファを設定 00514: UINT stride = sizeof( CustomVertex ); 00515: UINT offset = 0; 00516: gDemoApp.pDeviceContext->IASetVertexBuffers( 0, 1, &gDemoApp.pVertexBuffer, &stride, &offset ); 00517: 00518: // プリミティブの種類を設定 00519: gDemoApp.pDeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
さて,いよいよ描画処理です。描画処理は以下のようになります。
00575: //----------------------------------------------------------------------- 00576: //! @brief フレーム描画 00577: //----------------------------------------------------------------------- 00578: void Render() 00579: { 00580: // レンダーターゲットビューをクリア 00581: float clearColor[ 4 ] = { 0.3f, 0.3f, 1.0f, 1.0f }; 00582: gDemoApp.pDeviceContext->ClearRenderTargetView( gDemoApp.pRenderTargetView, clearColor ); 00583: 00584: // シェーダを設定して描画 00585: gDemoApp.pDeviceContext->VSSetShader( gDemoApp.pVS, NULL, 0 ); 00586: gDemoApp.pDeviceContext->GSSetShader( gDemoApp.pGS, NULL, 0 ); 00587: gDemoApp.pDeviceContext->PSSetShader( gDemoApp.pPS, NULL, 0 ); 00588: gDemoApp.pDeviceContext->Draw( 3, 0 ); 00589: 00590: // フリップ処理 00591: gDemoApp.pSwapChain->Present( 0, 0 ); 00592: }非常にすっきりしたコードです。バックバッファをクリアして,シェーダ設定してDraw()を呼ぶだけ。Draw()メソッドの第一引数は,描画する頂点数,第二引数には描画を開始する最初の頂点へのインデックスを指定します。今回は三角形を1枚表示するだけなので,Draw( 3, 0 )となっています。
あとは,Present()関数によりフリップ処理を行います。第一引数は,画面を更新するタイミングを指定します。上記例では0を指定しているので, 「同期を行なわず,直ぐに表示」という意味です。第二引数にはフラグを指定しますが,画面の更新を行うので0を指定しておきましょう。表示領域が存在するかチェックする場合にはDXGI_PRESENT_TESTを指定しますが,この時には画面更新は行われないそうです。
最後にデバイスのクリーンアップ処理です。各インタフェースのRelease()関数を呼び出して,解放処理を行いましょう。
00524: //----------------------------------------------------------------------- 00525: //! @brief デバイスのクリーンアップ 00526: //----------------------------------------------------------------------- 00527: void CleanupDevice() 00528: { 00529: if ( gDemoApp.pDeviceContext ) 00530: { 00531: gDemoApp.pDeviceContext->ClearState(); 00532: } 00533: if ( gDemoApp.pVertexBuffer ) 00534: { 00535: gDemoApp.pVertexBuffer->Release(); 00536: gDemoApp.pVertexBuffer = NULL; 00537: } 00538: if ( gDemoApp.pVertexLayout ) 00539: { 00540: gDemoApp.pVertexLayout->Release(); 00541: gDemoApp.pVertexLayout = NULL; 00542: } 00543: if ( gDemoApp.pVS ) 00544: { 00545: gDemoApp.pVS->Release(); 00546: gDemoApp.pVS = NULL; 00547: } 00548: if ( gDemoApp.pPS ) 00549: { 00550: gDemoApp.pPS->Release(); 00551: gDemoApp.pPS = NULL; 00552: } 00553: if ( gDemoApp.pRenderTargetView ) 00554: { 00555: gDemoApp.pRenderTargetView->Release(); 00556: gDemoApp.pRenderTargetView = NULL; 00557: } 00558: if ( gDemoApp.pSwapChain ) 00559: { 00560: gDemoApp.pSwapChain->Release(); 00561: gDemoApp.pSwapChain = NULL; 00562: } 00563: if ( gDemoApp.pDeviceContext ) 00564: { 00565: gDemoApp.pDeviceContext->Release(); 00566: gDemoApp.pDeviceContext = NULL; 00567: } 00568: if ( gDemoApp.pDevice ) 00569: { 00570: gDemoApp.pDevice->Release(); 00571: gDemoApp.pDevice = NULL; 00572: } 00573: }
一応,シェーダのコードも掲載しておきましょう。 単に,来たデータをそのまま流して,オレンジ色に塗りつぶすだけの簡単な処理です。
00007: //////////////////////////////////////////////////////////////////////// 00008: // VSInput structure 00009: //////////////////////////////////////////////////////////////////////// 00010: struct VSInput 00011: { 00012: float4 Position : POSITION; 00013: }; 00014: 00015: //////////////////////////////////////////////////////////////////////// 00016: // GSPSInput structure 00017: //////////////////////////////////////////////////////////////////////// 00018: struct GSPSInput 00019: { 00020: float4 Position : SV_POSITION; 00021: }; 00022: 00023: //---------------------------------------------------------------------- 00024: // Name : VSFunc() 00025: // Desc : Vertex Shader Entry Point 00026: //---------------------------------------------------------------------- 00027: GSPSInput VSFunc( VSInput input ) 00028: { 00029: GSPSInput output = (GSPSInput)0; 00030: 00031: // そのまま送る 00032: output.Position = input.Position; 00033: 00034: return output; 00035: } 00036: 00037: //---------------------------------------------------------------------- 00038: // Name : GSFunc() 00039: // Desc : Geometry Shader Entry Point 00040: //---------------------------------------------------------------------- 00041: [maxvertexcount(3)] 00042: void GSFunc( triangle GSPSInput input[ 3 ], inout TriangleStream<GSPSInput> stream ) 00043: { 00044: GSPSInput output; 00045: 00046: // 無加工 00047: for( int i=0; i<3; ++i ) 00048: { 00049: output.Position = input[ i ].Position; 00050: stream.Append( output ); 00051: } 00052: stream.RestartStrip(); 00053: } 00054: 00055: 00056: //---------------------------------------------------------------------- 00057: // Name : PSFunc() 00058: // Desc : Pixel Shader Entry Point 00059: //---------------------------------------------------------------------- 00060: float4 PSFunc( GSPSInput output ) : SV_Target0 00061: { 00062: // オレンジ色を出力 00063: return float4( 1.0f, 0.5f, 0.0f, 1.0f ); 00064: }
DirectX11でのポリゴン表示をやりました。
とりあえず,しょっぱななのでしょぼいプログラムであるのは勘弁してください。
★ Download
本ソースコードおよびプログラムを使用したことによる如何なる損害も製作者は責任を負いません。
本ソースコードおよびプログラムは自己責任でご使用ください。
プログラムの作成にはMicrosoft Visual Studio 2008 SP1 ProfessionalおよびMicrosoft DirectX SDK 2010(June)を用いています。
本ソースコードおよびプログラムは自己責任でご使用ください。
プログラムの作成にはMicrosoft Visual Studio 2008 SP1 ProfessionalおよびMicrosoft DirectX SDK 2010(June)を用いています。