メッシュを表示してみる! (1) Xファイル


 1.はじめに…
さすがにサンプルで,三角形ポリゴンを表示するだけなのもどうかと思うので,メッシュを表示してみました。
とりあえず,手っ取り早く作りたかったのでXファイルからデータを読み込んで表示するサンプルです。
今の時代に,Xファイルを使うのもどうかと思うのでゆくゆくはFBXとColladaに移行していく予定です。あくまでも予定…
あと,今回からDXUTをがっつり使っています。




 2.概要
OpenGLでサンプル作るときに,こういうこともあろうかと出来るだけグラフィックスAPIに依存しないようにローダーを作っておいたのです。はっはっはー。
そんなわけで,読み込み処理とかはOpenGLで使っていたやつと基本的に同じです。
一応,DirectX11側の実装について触れておきます。
今回やっている処理ですが…
(1) Xファイルをロードし,データを読み込む
(2) 読み込んだデータから頂点バッファ,インデックスバッファを生成.
(3) 作成したバッファを用いて描画
という内容です。やっていることはものすごくシンプルですが,コードは長くて面倒です。
設計思想ですが「サンプルだから,パフォーマンスなんか知ったこっちゃねぇ!表示できればいいじゃんか!」という思想のもと作成しています。
…というのも,データのあるなしを判別して,それによって入力レイアウトを作り直すのめんどいなぁ〜って思って,入力レイアウトを1つに固定しました。そのうちスキニングも扱う予定なので「頂点・法線・テクスチャ座標・スキンインデックス・スキンウェイト」の5つを入力とするレイアウトにしました。コードは下記のようになっています。
00269:      // メッシュ用入力レイアウトの生成
00270:      D3D11_INPUT_ELEMENT_DESC layout[] = {
00271:         { "POSITION",    0, DXGI_FORMAT_R32G32B32_FLOAT,    0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
00272:         { "NORMAL",      0, DXGI_FORMAT_R32G32B32_FLOAT,    0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
00273:         { "TEXCOORD",    0, DXGI_FORMAT_R32G32_FLOAT,       0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
00274:         { "SKIN_INDEX",  0, DXGI_FORMAT_R16G16B16A16_UINT,  0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0 },
00275:         { "SKIN_WEIGHT", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 40, D3D11_INPUT_PER_VERTEX_DATA, 0 },
00276:     };
00277:     uint32_t numElements = sizeof( layout ) / sizeof( layout[ 0 ] );
00278:  
00279:      // 入力レイアウト生成
00280:      hr = pDevice->CreateInputLayout(
00281:          layout,
00282:          numElements,
00283:          pVSBlob->GetBufferPointer(),
00284:          pVSBlob->GetBufferSize(),
00285:          &gGlobal.pInputLayout );
00286:      if ( FAILED( hr ) )
00287:      {
00288:          ELOG( "Error : ID3D11Device::CreateInputLayout() Failed." );
00289:          SAFE_RELEASE( pVSBlob );
00290:          SAFE_RELEASE( pPSBlob );
00291:          return false;
00292:      }
00293:  
頂点バッファやインデックスバッファを生成する処理は下記のようになっています。
00449:  //-----------------------------------------------------------------------------------
00450:  //! @brief バッファを生成する
00451:  //-----------------------------------------------------------------------------------
00452:  bool MeshData::CreateBuffer( ID3D11Device* pDevice, IMesh* pMesh )
00453:  {
00454:      // 頂点データが無い場合は即終了
00455:      if ( pMesh->GetNumPositions() == 0 )
00456:      {
00457:          ELOG( "Error : Position data is empty." );
00458:          return false;
00459:      }
00460:  
00461:      // 頂点データのメモリを確保
00462:      MeshVertex *pVertex = null;
00463:      try
00464:      {
00465:          pVertex = new MeshVertex[ pMesh->GetNumPositions() ];
00466:      }
00467:      catch( std::bad_alloc ba )
00468:      {
00469:          ELOG( "Error : Memory Allocate Faield. reason = %s", ba.what() );
00470:          return false;
00471:      }
00472:  
00473:      // データがあるかチェックしておく
00474:      bool isEmpty_N = ( pMesh->GetNumNormals() == 0 );
00475:      bool isEmpty_U = ( pMesh->GetNumTexCoords() == 0 );
00476:      bool isEmpty_I = ( pMesh->GetNumSkinIndices() == 0 );
00477:      bool isEmpty_W = ( pMesh->GetNumSkinWeights() == 0 );
00478:  
00479:      // 頂点データ構築
00480:      for( uint32_t i=0; i<pMesh->GetNumPositions(); ++i )
00481:      {
00482:          // データが無い場合はゼロで埋める
00483:          pVertex[ i ].Position   = pMesh->GetPosition( i );
00484:          pVertex[ i ].Normal     = ( !isEmpty_N ) ? pMesh->GetNormal( i )     : Vector3( 0.0f, 0.0f, 0.0f );
00485:          pVertex[ i ].TexCoord   = ( !isEmpty_U ) ? pMesh->GetTexCoord( i )   : Vector2( 0.0f, 0.0f );
00486:          pVertex[ i ].SkinIndex  = ( !isEmpty_I ) ? pMesh->GetSkinIndex( i )  : Short4( 0, 0, 0, 0 );
00487:          pVertex[ i ].SkinWeight = ( !isEmpty_W ) ? pMesh->GetSkinWeight( i ) : Vector4( 0.0f, 0.0f, 0.0f, 0.0f );       
00488:      }
00489:  
00490:      // 頂点バッファの設定
00491:      D3D11_BUFFER_DESC bufDesc;
00492:      memset( &bufDesc, 0, sizeof( bufDesc ) );
00493:      bufDesc.Usage = D3D11_USAGE_DEFAULT;
00494:      bufDesc.ByteWidth = sizeof( MeshVertex ) * pMesh->GetNumPositions();
00495:      bufDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
00496:      bufDesc.CPUAccessFlags = 0;
00497:  
00498:      // ストライドとオフセットの設定
00499:      mStride = sizeof( MeshVertex );
00500:      mOffset = 0;
00501:  
00502:      // サブリソースデータの設定
00503:      D3D11_SUBRESOURCE_DATA initData;
00504:      memset( &initData, 0, sizeof( initData ) );
00505:      initData.pSysMem = pVertex;
00506:  
00507:      // 頂点バッファ作成
00508:      HRESULT hr = pDevice->CreateBuffer( &bufDesc, &initData, &mpVB );
00509:      if ( FAILED( hr ) )
00510:      {
00511:          ELOG( "Error : ID3D11Device::CreateBuffer() Failed." );
00512:          SAFE_DELETE_ARRAY( pVertex );
00513:          return false;
00514:      }
00515:  
00516:      // メモリ解放
00517:      SAFE_DELETE_ARRAY( pVertex );
00518:  
00519:      // マテリアル用定数バッファの作成
00520:      memset( &bufDesc, 0, sizeof( bufDesc ) );
00521:      bufDesc.Usage = D3D11_USAGE_DEFAULT;
00522:      bufDesc.ByteWidth = sizeof( MeshMaterial );
00523:      bufDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
00524:      bufDesc.CPUAccessFlags = 0;
00525:      hr = pDevice->CreateBuffer( &bufDesc, NULL, &mpMB );
00526:      if ( FAILED( hr ) )
00527:      {
00528:          ELOG( "Error : ID3D11Device::CreateBuffer() Failed." );
00529:          return false;
00530:      }
00531:    
00532:      uint32_t *pIndices = null; 
00533:      try
00534:      {
00535:          pIndices = new uint32_t [ pMesh->GetNumIndices() ];
00536:      }
00537:      catch( std::bad_alloc ba )
00538:      {
00539:          ELOG( "Error : Memory Allocate failed. reason = %s", ba.what() );
00540:          return false;
 00541:     }
 00542:     for( uint32_t i=0; i<pMesh->GetNumIndices(); ++i )
00543:      {
00544:          pIndices[ i ] = pMesh->GetIndex( i );
00545:      }
00546:  
00547:      // インデックスバッファの設定
00548:      memset( &bufDesc, 0, sizeof( bufDesc ) );
00549:      memset( &initData, 0, sizeof( initData ) );
00550:      bufDesc.Usage = D3D11_USAGE_DEFAULT;
00551:      bufDesc.ByteWidth = sizeof( uint32_t ) * pMesh->GetNumIndices();
00552:      bufDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
00553:      bufDesc.CPUAccessFlags = 0;
00554:      initData.pSysMem = pIndices;
00555:  
00556:      // インデックスバッファ生成
00557:      hr = pDevice->CreateBuffer( &bufDesc, &initData, &mpIB );
00558:      if ( FAILED( hr ) )
00559:      {
00560:          ELOG( "Error : ID3D11Device::CreateBuffer() Failed." );
00561:          SAFE_DELETE_ARRAY( pIndices );
00562:          return false;
00563:      }
00564:      SAFE_DELETE_ARRAY( pIndices );
00565:  
00566:      // サブセットの構築
00567:      mSubsets.resize( pMesh->GetNumSubsets() );
00568:      for( uint32_t i=0; i<pMesh->GetNumSubsets(); ++i )
00569:      {
00570:          memset( &mSubsets[ i ], 0, sizeof( SubsetData ) );
00571:     
00572:          // 頂点カウント数設定
00573:          mSubsets[ i ].count = pMesh->GetSubset( i )->GetNumFace() * 3;
00574:          mSubsets[ i ].startIndex = pMesh->GetSubset( i )->GetFaceIndex() * 3;
00575:  
00576:          // マテリアルを格納
00577:          IMaterial* pMat = pMesh->GetMaterial( pMesh->GetSubset( i )->GetMaterialIndex() );
00578:          mSubsets[ i ].diffuse  = pMat->GetDiffuse();
00579:          mSubsets[ i ].specular = pMat->GetSpecular();
00580:          mSubsets[ i ].emissive = pMat->GetEmissive();
00581:          mSubsets[ i ].power    = pMat->GetPower();
00582:      }
00583:    
00584:      return true;
00585:  }
00586:  
上記のコードを見るとわかるように,実際にデータがないものは無理やりゼロで埋め合わせています。要するに,使わないデータを無駄にGPUに転送しています。あまりよろしくないコードです。パフォーマンスとか気になる方は上記処理のあたりを修正してください。使うデータが固定ならいらない部分を削除する感じですかね,汎用的なものを作りたい人は,いくつかフォーマットを用意しておいてデータのあるなしから一番近いフォーマットを選択するとそんな感じの造りになると思います。最初はフォーマット用意しようかなと思ったのですが,色々と組み合わせができてしまってガチで全部用意すると面倒なことに気づき挫折しました。結局ライブラリをつくるのがメインじゃないし,商用向けのものをつくるわけでもないので,一番実装がお手軽なものとして,上記コードに行きつきました。

あと,入力レイアウト作成するのにコンパイルされたシェーダのポインタと,コンパイルされたシェーダのサイズが必要なんですよね。そこで,シェーダも用意してみました。このデフォルトシェーダをコンパイルして,入力レイアウトを作成することにします。デフォルトで使う目的なので,そんなに変更しないだろうという見込みからシェーダファイルは用意せず,コードにシェーダコードを書きました。
シェーダコードの中身や,その他もろもろの処理は以下のような感じです。
00095:  //----------------------------------------------------------------------------------
00096:  //! @brief 初期化処理
00097:  //----------------------------------------------------------------------------------
00098:  bool ModelUtil::Initialize( ID3D11Device* pDevice )
00099:  {
00100:      HRESULT hr = S_OK;
00101:  
00102:      memset( &gGlobal, 0, sizeof( ModelUtilGlobal ) );
00103:    
00104:      const char *pShaderCode = 
00105:      "struct VSInput\n"
00106:      "{\n"
00107:      "    float3 Position   : POSITION;\n"
00108:      "    float3 Normal     : NORMAL;\n"
00109:      "    float2 TexCoord   : TEXCOORD;\n"
00110:      "    uint4  SkinIndex  : SKIN_INDEX;\n"
00111:      "    float4 SkinWeight : SKIN_WEIGHT;\n"
00112:      "};\n"
00113:      "struct VSOutput\n"
00114:      "{\n"
00115:      "    float4 Position : SV_POSITION;\n"
00116:      "    float2 TexCoord : TEXCOORD0;\n"
00117:      "    float3 Normal   : TEXCOORD1;\n"
00118:      "};\n"
00119:      "cbuffer VSMatrix : register( b0 )\n"
00120:      "{\n"
00121:      "    float4x4 World  : packoffset( c0 );\n"
00122:      "    float4x4 View   : packoffset( c4 );\n"
00123:      "    float4x4 Proj   : packoffset( c8 );\n"
00124:      "};\n"
00125:      "cbuffer PSMaterial : register( b1 )\n"
00126:      "{\n"
00127:      "    float3 Diffuse  : packoffset( c0 );\n"
00128:      "    float  Alpha    : packoffset( c0.w );\n"
00129:      "    float3 Specular : packoffset( c1 );\n"
00130:      "    float  Power    : packoffset( c1.w );\n"
00131:      "    float3 Emissive : packoffset( c2 );\n"
00132:      "};\n"
00133:      "cbuffer PSVector : register( b2 )\n"
00134:      "{\n"
00135:      "    float3 LightDir : packoffset( c0 );\n"
00136:      "    float3 ViewDir  : packoffset( c1 );\n"
00137:      "};\n"
00138:      "VSOutput VSFunc( VSInput input )\n"
00139:      "{\n"
00140:      "    VSOutput output = (VSOutput)0;\n"
00141:      "    float4 localPos = float4( input.Position, 1.0f );\n"
00142:      "    float4 worldPos = mul( World, localPos );\n"
00143:      "    float4 viewPos  = mul( View, worldPos );\n"
00144:      "    float4 projPos  = mul( Proj, viewPos );\n"
00145:      "    output.Position = projPos;\n"
00146:      "    output.TexCoord = input.TexCoord;\n"
00147:      "    output.Normal   = input.Normal;\n"
00148:      "    return output;"
00149:      "}\n"
00150:      "float4 PSFunc( VSOutput input ) : SV_TARGET\n"
00151:      "{\n"
00152:      "    float3 L = normalize( LightDir );\n"
00153:      "    float3 N = normalize( input.Normal );\n"
00154:      "    float3 E = normalize( ViewDir );\n"
00155:      "    float3 H = normalize( L + E );\n"
00156:      "    float3 diffuse  = Diffuse  * 0.85f * max( dot( L, N ), 0 );\n"
00157:      "    float3 specular = Specular * 0.75f * pow( max( dot( N, H ), 0 ), Power );\n"
00158:      "    float3 emissive = Emissive * 0.25f;\n"
00159:      "    float4 output   = float4( ( diffuse + specular + emissive ), Alpha );\n"
00160:      "    return output;\n"
00161:      "}\n";
00162:  
00163:  
00164:      // フラグの設定
00165:      DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
00166:  #if defined(DEBUG) || defined(_DEBUG)
00167:      dwShaderFlags |= D3DCOMPILE_DEBUG;
00168:  #endif
00169:  
00170:      ID3DBlob* pErrorBlob = NULL;
00171:      ID3DBlob* pVSBlob = NULL;
00172:      ID3D11VertexShader* pVS = NULL;
00173:  
00174:      // 頂点シェーダのコードをコンパイル
00175:      hr = D3DX11CompileFromMemory(
00176:          pShaderCode,
00177:          strlen( pShaderCode ),
00178:          NULL,
00179:          NULL,
00180:          NULL,
00181:          "VSFunc",
00182:          "vs_4_0",
00183:          dwShaderFlags,
00184:          0,
00185:          NULL,
00186:          &pVSBlob,
00187:          &pErrorBlob,
00188:          NULL );
00189:      if ( FAILED( hr ) )
00190:      {
00191:          ELOG( "Error : D3DX11CompileFromMeory() Failed. retcode = %d", hr );
00192:          if ( pErrorBlob != NULL )
00193:          {
00194:              ELOG( "Error : %s", (char*)pErrorBlob->GetBufferPointer() );
00195:              OutputDebugStringA( (char*)pErrorBlob->GetBufferPointer() );
00196:          }
00197:          SAFE_RELEASE( pErrorBlob );
00198:          return false;
00199:      }
00200:      SAFE_RELEASE( pErrorBlob );
00201:  
00202:      // 頂点シェーダ生成
00203:      hr = pDevice->CreateVertexShader( 
00204:          pVSBlob->GetBufferPointer(),
00205:          pVSBlob->GetBufferSize(),
00206:          NULL,
00207:          &pVS );
00208:      if ( FAILED( hr ) )
00209:      {
00210:          ELOG( "Error : ID3D11Device::CreateVertexShader() Failed." );
00211:          SAFE_RELEASE( pVSBlob );
00212:          return false;
00213:      }
00214:      assert( pVS != NULL );
00215:  
00216:  
00217:      ID3DBlob* pPSBlob = NULL;
00218:      ID3D11PixelShader* pPS = NULL;
00219:  
00220:      // ピクセルシェーダのコードをコンパイル
00221:      hr = D3DX11CompileFromMemory(
00222:          pShaderCode,
00223:          strlen( pShaderCode ),
00224:          NULL,
00225:          NULL,
00226:          NULL,
00227:          "PSFunc",
00228:          "ps_4_0",
00229:          dwShaderFlags,
00230:          0,
00231:          NULL,
00232:          &pPSBlob,
00233:          &pErrorBlob,
00234:          NULL );
00235:      if ( FAILED( hr ) )
00236:      {
00237:          ELOG( "Error : D3DX11CompileFromMeory() Failed. retcode = %d", hr );
00238:          if ( pErrorBlob != NULL )
00239:          {
00240:              ELOG( "Error : %s", (char*)pErrorBlob->GetBufferPointer() );
00241:              OutputDebugStringA( (char*)pErrorBlob->GetBufferPointer() );
00242:          }
00243:          SAFE_RELEASE( pVSBlob );
00244:          SAFE_RELEASE( pErrorBlob );
00245:          SAFE_RELEASE( pVS );
00246:          return false;
00247:      }
00248:      SAFE_RELEASE( pErrorBlob );
00249:  
00250:      // ピクセルシェーダ生成
00251:       hr = pDevice->CreatePixelShader( 
00252:          pPSBlob->GetBufferPointer(),
00253:          pPSBlob->GetBufferSize(),
00254:          NULL,
00255:          &pPS );
00256:      if ( FAILED( hr ) )
00257:      {
00258:          ELOG( "Error : ID3D11Device::CreatePixelShader() Failed." );
00259:          SAFE_RELEASE( pVSBlob );
00260:          SAFE_RELEASE( pPSBlob );
00261:          SAFE_RELEASE( pVS );
00262:          return false;
00263:      }
00264:      assert( pPS != NULL );
00265:  
00266:      gGlobal.pVS = pVS;
00267:      gGlobal.pPS = pPS;
00268:  
00269:      // メッシュ用入力レイアウトの生成
00270:      D3D11_INPUT_ELEMENT_DESC layout[] = {
00271:         { "POSITION",    0, DXGI_FORMAT_R32G32B32_FLOAT,    0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
00272:         { "NORMAL",      0, DXGI_FORMAT_R32G32B32_FLOAT,    0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
00273:         { "TEXCOORD",    0, DXGI_FORMAT_R32G32_FLOAT,       0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
00274:         { "SKIN_INDEX",  0, DXGI_FORMAT_R16G16B16A16_UINT,  0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0 },
00275:         { "SKIN_WEIGHT", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 40, D3D11_INPUT_PER_VERTEX_DATA, 0 },
00276:     };
00277:     uint32_t numElements = sizeof( layout ) / sizeof( layout[ 0 ] );
00278:  
00279:      // 入力レイアウト生成
00280:      hr = pDevice->CreateInputLayout(
00281:          layout,
00282:          numElements,
00283:          pVSBlob->GetBufferPointer(),
00284:          pVSBlob->GetBufferSize(),
00285:          &gGlobal.pInputLayout );
00286:      if ( FAILED( hr ) )
00287:      {
00288:          ELOG( "Error : ID3D11Device::CreateInputLayout() Failed." );
00289:          SAFE_RELEASE( pVSBlob );
00290:          SAFE_RELEASE( pPSBlob );
00291:          return false;
00292:      }
00293:  
00294:      // メモリ解放
00295:      SAFE_RELEASE( pVSBlob );
00296:      SAFE_RELEASE( pPSBlob );
00297:  
00298:      // 行列バッファの設定
00299:      D3D11_BUFFER_DESC bufDesc;
00300:      memset( &bufDesc, 0, sizeof( bufDesc ) );
00301:      bufDesc.Usage = D3D11_USAGE_DEFAULT;
00302:      bufDesc.ByteWidth = sizeof( MatrixBuffer );
00303:      bufDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
00304:      bufDesc.CPUAccessFlags = 0;
00305:  
00306:      // 行列バッファの生成
00307:      hr = pDevice->CreateBuffer( &bufDesc, NULL, &gGlobal.pMatrixBuffer );
00308:      if ( FAILED( hr ) )
00309:      {
00310:          ELOG( "Error : ID3D11Device::CreateBuffer() Failed." );
00311:          ELOG( "Error : Constant Buffer for Matrix Create Failed" );
00312:          /* NOT_RETURN /*
00313:      }
00314:  
00315:      // ベクトルバッファの設定
00316:      memset( &bufDesc, 0, sizeof( bufDesc ) );
00317:      bufDesc.Usage = D3D11_USAGE_DEFAULT;
00318:      bufDesc.ByteWidth = sizeof( VectorBuffer );
00319:      bufDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
00320:      bufDesc.CPUAccessFlags = 0;
00321:  
00322:      // ベクトルバッファの生成
00323:      hr = pDevice->CreateBuffer( &bufDesc, NULL, &gGlobal.pVectorBuffer );
00324:      if ( FAILED( hr ) )
00325:      {
00326:          ELOG( "Error : ID3D11Device::CreateBuffer() Failed." );
00327:          ELOG( "Error : Constant Buffer for Vector Create Failed" );
00328:          /* NOT_RETURN /*
00329:      }
00330:  
00331:      return true;
00332:  }
00333:  
さて描画の仕組みですが,今回は上記のようにデフォルトで使用するシェーダを用意しています。
まずは,デフォルトシェーダ側で定数バッファを3つ用意してあります。スロット0がワールド行列やビュー行列,射影行列を取り扱うものです。スロット1はマテリアル設定用の定数バッファです。スロット2はライトの方向ベクトルや視線ベクトルを設定するものになっています。スロット1はDrawSubuset()呼び出し時に設定される仕組みにしました。
powerは最初float単体で送っていたのですが,どうも不定値か何かよくわからない値が渡されてしまって,ライティング結果が正しくなく,うまい解決方法がわからなかったので,Specularのw成分に格納して送るようにしました。
00602:  //----------------------------------------------------------------------------------
00603:  //! @brief サブセットの描画処理
00604:  //----------------------------------------------------------------------------------
00605:  void MeshData::DrawSubset( ID3D11DeviceContext* pImmediateContext, const int index )
00606:  {
00607:      assert( pImmediateContext != NULL );
00608:      assert( index >= 0 );
00609:      assert( gGlobal.pInputLayout != NULL );
00610:  
00611:      MeshMaterial matData;
00612:  
00613:      for( uint32_t i=0; i<mSubsets.size(); ++i )
00614:      {
00615:          // マテリアルデータ設定
00616:          memset( &matData, 0, sizeof( MeshMaterial ) );
00617:          matData.Diffuse  = mSubsets[ i ].diffuse;
00618:          matData.Specular.x = mSubsets[ i ].specular.x;
00619:          matData.Specular.y = mSubsets[ i ].specular.y;
00620:          matData.Specular.z = mSubsets[ i ].specular.z;
00621:          matData.Specular.w = mSubsets[ i ].power;
00622:          matData.Emissive = mSubsets[ i ].emissive;
00623:  
00624:          // マテリアルバッファを更新し,slot:1の定数バッファに設定
00625:          pImmediateContext->UpdateSubresource( mpMB, 0, NULL, &matData, 0, 0 );
00626:          pImmediateContext->PSSetConstantBuffers( 1, 1, &mpMB );
00627:  
00628:          // インデックスバッファとプリミティブを設定
00629:          pImmediateContext->IASetIndexBuffer( mpIB, DXGI_FORMAT_R32_UINT, 0 );
00630:          pImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
00631:  
00632:          // 描画
00633:          UINT indexCount = mSubsets[ i ].count;
00634:          UINT startIndex = mSubsets[ i ].startIndex;
00635:          pImmediateContext->DrawIndexed( indexCount, startIndex, 0 );        
00636:      }
00637:  }
00638:  
スロット0とスロット2の定数バッファに値を設定するため,行列とベクトルのそれぞれを設定する関数を作りました。
00366:  //----------------------------------------------------------------------------------
00367:  //! @brief 定数バッファに行列を設定する
00368:  //----------------------------------------------------------------------------------
00369:  void ModelUtil::SetMatrix
00370:  (
00371:      ID3D11DeviceContext* pImmediateContext,
00372:      const D3DXMATRIX &world,
00373:      const D3DXMATRIX &view,
00374:      const D3DXMATRIX &proj
00375:  )
00376:  {
00377:      MatrixBuffer buffer;
00378:      memset( &buffer, 0, sizeof( MatrixBuffer ) );
00379:      buffer.World = world;
00380:      buffer.View = view;
00381:      buffer.Projection = proj;
00382:  
00383:      // slot:0の定数バッファに行列を設定
00384:      pImmediateContext->UpdateSubresource( gGlobal.pMatrixBuffer, 0, NULL, &buffer, 0, 0 );
00385:      pImmediateContext->VSSetConstantBuffers( 0, 1, &gGlobal.pMatrixBuffer );
00386:  }
00387:  
00388:  //----------------------------------------------------------------------------------
00389:  //! @brief 定数バッファにベクトルを設定
00390:  //----------------------------------------------------------------------------------
00391:  void ModelUtil::SetVector
00392:  (
00393:      ID3D11DeviceContext* pImmediateContext,
00394:      const D3DXVECTOR3 &lightDir,
00395:      const D3DXVECTOR3 &viewDir
00396:  )
00397:  {
00398:      VectorBuffer buffer;
00399:      memset( &buffer, 0, sizeof( VectorBuffer ) );
00400:      buffer.LightDir = lightDir;
00401:      buffer.ViewDir = viewDir;
00402:  
00403:     // slot:2の定数バッファにベクトルを設定
00404:      pImmediateContext->UpdateSubresource( gGlobal.pVectorBuffer, 0, NULL, &buffer, 0, 0 );
00405:      pImmediateContext->PSSetConstantBuffers( 2, 1, &gGlobal.pVectorBuffer );
00406:  }
この2つの関数をDraw()を呼び出す前にコールしてやります。
実際の使い方は下記のような感じです。
<00139:  //-----------------------------------------------------------------------
00140:  //! @brief 描画処理
00141:  //-----------------------------------------------------------------------
00142:  void SampleRenderer::OnRender
00143:  (
00144:  	ID3D11Device* pDevice, 
00145:  	ID3D11DeviceContext* pImmediateContext, 
00146:  	double time,
00147:  	float  elapsedTime
00148:  )
00149:  {
00150:  	// デフォルトシェーダを取得
00151:  	ID3D11VertexShader *pVS = ModelUtil::GetDefaultVertexShader();
00152:  	ID3D11PixelShader  *pPS = ModelUtil::GetDefaultPixelShader();
00153:  	assert( pVS != NULL );
00154:  	assert( pPS != NULL );
00155:  
00156:  	// シェーダを設定
00157:  	pImmediateContext->VSSetShader( pVS, NULL, 0 );
00158:  	pImmediateContext->PSSetShader( pPS, NULL, 0 );
00159:  
00160:  	// 定数バッファ設定
00161:  	ModelUtil::SetMatrix( pImmediateContext, mWorld, mView, mProjection );
00162:  	ModelUtil::SetVector( pImmediateContext, mLightDir, mViewDir );
00163:  
00164:  	// モデルを描画
00165:  	mModel.Draw( pImmediateContext );
00166:  }


 3.終わりに
一応,メッシュ表示をやりました。
やっていることは単純なのですが,描画するまでの設定が色々とあるので多少コードが見づらいのは仕方ないですね。


 Download
本ソースコードおよびプログラムを使用したことによる如何なる損害も製作者は責任を負いません。
本ソースコードおよびプログラムは自己責任でご使用ください。
プログラムの作成にはMicrosoft Visual Studio 2008 SP1 Professional, およびMicrosoft DirectX SDK (June 2010)を用いています。







Flashを利用するためにはPluginが必要です。 <!-- <div style="text-align: center;"><div style="display: inline-block; position: relative; z-index: 9999;"><script type="text/javascript" charset="utf-8" src="//asumi.shinobi.jp/fire?f=434"></script></div></div></body> -->