…が,ここしばらくDirectXにはかなり久しくて,非常に不安です。そんなわけで,DirectX11を勉強していきます。



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にジオメトリシェーダを付け足しただけの簡単なものです。(1)ウィンドウの生成 & 初期化 (2)デバイスの初期化 (3)メインループで描画 (4)デバイスのクリーンアップ処理というように4つから構成されています。
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_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構造体の設定です。はやい話がバックバッファとかの設定です。特別な設定は今回しないので,説明はスルーします。
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 )となっています。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: }