読者です 読者をやめる 読者になる 読者になる

S.F. Page

Programming,Music,etc...

DirectX Tool KitのReadme.txt(Documents) を翻訳してみた。

DirectX

はじめに

DirectXTKがかなり有用そうなので、理解を深めるためにDirectXTKReadme.txtの勝手訳をしてみた。Readme.txtはほぼDocumentsと同じ内容である。英語力がないせいでうまく訳せないところもかなりある。でも概要はなんとなくわかった。コンポーネントによっては全然使用してもいないものもあるので的外れな訳もあると思う。理解が深まればおかしなところもわかると思うので都度修正していこうと思っている。

DirectXTK - the DirectX Tool Kit

Copyright (c) Microsoft Corporation. All rights reserved.

July 1, 2013

このパッケージはWindows Store アプリ・Windows 8.x Win32 デスクトップアプリ・Windows Phone 8 アプリ・Windows 7 ・Windows VistaにおいてDirect3D 11 C++コードを書くためのヘルパークラス のコレクションである"DirectX Tool Kit"を含んでいる。

このコードはVisual Studio 2010,2012,2013でビルドできるように設計されている。DirectXMathライブラリやオプションDXGI 1.2ヘッダーのような機能はWinodws 8.X SDKが必要である。Visual 2012,2013は必要なWindows SDKを含んでいるが、Visual 2010はWindows 8.x SDKを単独でインストールしなくてはならない。 VS2010でWindows 8.x SDKを使用するための詳細についてVisual C++ Team Blogに記載されている。

http://blogs.msdn.com/b/vcblog/archive/2012/11/23/using-the-windows-8-sdk-with-visual-studio-2010-configuring-multiple-projects.aspx

これらのコンポーネントはDirectX SDKを必要とせずに動作するように設計されている。詳細については「Where is the DirectX SDK? 」を確認すること。

ディレクトリ構造

Inc\
    共通ヘッダーファイル(DirectX名前空間に存在):

    SpriteBatch.h - シンプルで効率的な2Dスプライト描画
    SpriteFont.h - ビットマップベースのテキスト描画
    Effects.h - 共通描画タスクのためのビルトインシェーダーのセット
    PrimitiveBatch.h - シンプルで効率的なプリミティブの描画方法
    GeometricPrimitive.h - 立方体や球のような基本的な図形を描画する
    Model.h - .CMOや.SDKMESHファイルからロードし、簡単にメッシュを描画する。
    CommonStates.h - 一般的に使用されるD3D状態オブジェクトを提供するためのファクトリ
    VertexTypes.h - 一般的に使用される頂点データフォーマットのための構造体
    DDSTextureLoader.h - 軽量なDDSファイルテクスチャーローダー
    WICTextureLoader.h - WICベースのイメージファイルテクスチャーローダー
    ScreenGrab.h - 軽量なスクリーンショット保存
    SimpleMath.h - 簡素化されたDirectXMathのC++ラッパー

Src\
    DirectXTK ソースファイルおよび内部実装のためのヘッダー

MakeSpriteFont\
    SpriteFontライブラリを使用するためのバイナリ・リソースを生成するために使用するコマンドラインツール

パッケージのすべての内容物とソースコードはMicrosoft Public License(Ms-PL)により制限される。

最新のDirectXTK、さらに詳細なドキュメント、フォーラム、バグレポート、機能リクエストについては下記のCodeplexサイトに訪れてほしい。

http://go.microsoft.com/fwlink/?LinkId=248929

SpriteBatch

これはXNA Game Studioと同一の機能・APIを提供するSpriteBatchヘルパーのネイティブD3D11実装である。

初期化

    std::unique_ptr<SpriteBatch> spriteBatch(new SpriteBatch(deviceContext));

簡単な描画

    spriteBatch->Begin();
    spriteBatch->Draw(texture, XMFLOAT2(x, y));
    spriteBatch->End();

Drawメソッドはパラメータ制御のためたくさんのオーバーロードがある。

  • XMFLOAT2,XMVECTOR,RECTによる座標指定
  • スプライト・シートの部分を描画するためのソース矩形(オプション)
  • 色指定
  • 回転(ラジアン)
  • 原点(位置、スケーリング、回転)
  • スケーリング(拡大・縮小)
  • レイヤー深度(スプライト並び替えのための)

並び替え

SpriteBatch::Beginメソッドの最初の引数はSpriteSortMode列挙型である。最も効率的に描画をしたい場合、SpriteSortMode_Deferredを使用し(スプライトをバッチ処理し、Endメソッドが呼び出された時にGPUにすべてを転送する)、テクスチャの描画順ですべてを手動で描画する。もしテクスチャーの描画順で描画できない場合、2番目に効率的な方法としては、自動的にソートするSpriteSortMode_Textureを指定する。

複数の深度レイヤーでシーンを描画するとき、SpriteSortMode_BackToFrontもしくはSpriteSortMode_FrontToBackを指定することにより呼び出しのたびにlayerDepth引数によってソートする。

SpriteSortMode_Immediateはバッチ処理を無効化し、スプライトごとにD3D描画命令を分割して送信する。これは非常に高コストな処理だが、まれなケースだがスプライトごとに異なるシェーダー定数をセットする必要があるときに便利である。

複数のSpriteBatchインスタンスは軽量である。異なるソートモードで同時にBeginメソッドを呼び出し、シーン中に任意の順序で異なるバッチにスプライトを送信し、描画したいスプライトグループ順でEndメソッドを呼び出す場合にSpriteBatchインスタンスをいくつか作成することは合理的である。

アルファ ブレンディング

アルファブレンディングは事前乗算済みアルファを使用することが既定である。ストレート アルファ テクスチャを使用するにはオプションのコールバックを通じてブレンドモードをオーバーライドする。

    CommonStates states(deviceContext);

    spriteBatch->Begin(SpriteSortMode_Deferred, nullptr, nullptr, nullptr, nullptr, [=]
    {
        deviceContext->OMSetBlendState( states.NonPremultiplied(), nullptr, 0xFFFFFFFF);
    });

カスタム描画ステート

既定ではSpriteBatchは事前乗算済みアルファブレンドを使用し、深度バッファは使用せず、左回りでカリングし、テクスチャアドレス指定は線形補完を使用する。これらのステートはSpriteBatch::Beginメソッドにカスタムステートオブジェクトを渡すことで変更できる。既定のステートを使用するにはすべての引数にnullを渡す。

カスタムピクセルシェーダーかカスタム頂点シェーダーでSpriteBatchを使用する(ブルームやブラーのようなエフェクトを後処理したい場合)には、ステートを設定するコールバック関数をsetCustomShadersの引数に指定する。

    spriteBatch->Begin(SpriteSortMode_Deferred, nullptr, nullptr, nullptr, nullptr, [=]
    {
        deviceContext->PSSetShader(...);
        deviceContext->PSSetConstantBuffers(...);
        deviceContext->PSSetShaderResources(...);
    });

SpriteBatchは自動的にDraw呼び出しのたびに、記述されたテクスチャをピクセルシェーダーリソース#0にセットする。そのためカスタマイズされたシェーダーで追加テクスチャが必要な場合はPSSetResourcesメソッドを呼び出す必要がある。

SpriteBatch::BeginメソッドはtransformMatrixパラメータを持ち、シーン全体のスケーリング・移動のようなグローバル変換のために使用できる。

スレッド・モデル

生成はすべて非同期であるので、異なるスレッドで同時複数のSpriteBatchをインスタンス化することができる。それぞれのSpriteBatchインスタンスは同時に1つのスレッドからのみ描画をサポートしているが、もしD3D11遅延コンテキストごとにSpriteBatchを生成しているのであれば複数のスレッドでスプライト(描画)を同時に送信できる。

参考資料

http://www.shawnhargreaves.com/blogindex.html#spritebatch
http://blogs.msdn.com/b/shawnhar/archive/2010/06/18/spritebatch-and-renderstates-in-xna-game-studio-4-0.aspx
http://www.shawnhargreaves.com/blogindex.html#premultipliedalpha

SpriteFont

これはXNA Game StudioのSpriteFontの機能を倣い、ビットマップフォーマットでフォントを構築するMakeSpriteFontコマンドツールを追加した、ビットマップフォント描画のネイティブD3D11実装である。 Direct2DやDirectWriteよりも機能は十分でないが、簡単・軽量に描画したいときに使えるだろう。

ビルド時

    MakeSpriteFont.exe "Comic Sans" myfile.spritefont /FontSize:16

初期化

    std::unique_ptr<SpriteBatch> spriteBatch(new SpriteBatch(deviceContext));
    std::unique_ptr<SpriteFont> spriteFont(new SpriteFont(device, L"myfile.spritefont"));

フォントの描画

    spriteBatch->Begin();
    spriteFont->DrawString(spriteBatch.get(), L"Hello, world!", XMFLOAT2(x, y));
    spriteBatch->End();

Drawメソッドはカラー・回転・原点・スケーリング・縦横反転・レイヤー深度を制御するための引数を持ついくつかのオーバーロードを持つ。これらはSpriteBatch::Drawメソッドのパラメータと同様の働きをする。

SpriteFontは3つのコンストラクタを持つ。

  • MakeSpriteFontによって作成されたバイナリファイルを読むためのファイルネームを渡す。
  • 他の方法ですでに読み込みされたMakeSpriteFontバイナリのバッファを渡す。
  • MakeSpriteFontの使用を回避したい場合はGlyph構造体の配列を渡す。

フォントに含まれない文字をMeasureStringするか描画しようとした場合、既定では例外が発生する。見つからない場合自動的に代替表示する文字を指定するにはSetDefaultCharacterメソッドを使用すること。

この実装はスパース・フォントをサポートしているため、もし中国語、日本語、韓国語にローカライズしたい場合あなたのプログラムに必要な文字のみを含むspritefontを構築することができる。CJK文字はDirect3Dテクスチャーに収めるには文字数が多すぎるので、通常CJK言語には良いアイデアである(もしCJK文字がすべて必要なら、Direct2DかDirectWriteが良い選択である )。SpriteFont はRTLレイアウトもしくは文字の組み合わせはサポートしていないので、アラビア文字やタイのような 複合レイアウトを伴う言語では使えない。

MakeSpriteFontツールはシステムのインストールされているTrueTypeフォント(GDI+を使用してビットマップにラスタライズする)を処理するか、特別 にフォーマットされたビットマップファイルからグリフをインポートすることができる。オプションによりマルチカラーフォント、グリフテクスチャーにグラデーションか影付きエフェクトでの描画が可能である。文字は左上から右下整列されたグリッドで調整される。モノクロフォントは文字部分には白、透明部分には黒を使用する。マルチカラーキャラクターを含めるには、ビットマップにアルファチャネルを追加し、各々の文字を塗りつぶすように制御して使用するようにする。文字間のスペースとグリッドの協会は明るいピンクで塗りつぶされる(赤=255,緑=0,青=255)。もしグリッドがたくさんの空白を含んでいてもコンバーターが文字を再調整し、可能な限り小さくファイルに納めるするので気にする必要はない。

MakeSpriteFontツールのコマンドラインオプション

/CharacterRegion:<region>

フォントに含まれるUnicodeコードポイントを指定する。 1つ以上のリージョンを繰り返し指定できる。指定しない場合既定のASCII範囲(32-126)を使用する。

例:
/CharacterRegion:a-z
/CharacterRegion:0x1200-0x1250
/CharacterRegion:0x1234
/DefaultCharacter:<value>
フォントに含まれないコードポイントの代わりに使用する文字を指定する。      0の場合、「文字が見つからない」例外を投げる。
/FontSize:<value>
/FontStyle:<value>

TrueTypeフォントのサイズとスタイル(太字や斜体)を指定する。ビットマップフォントを変換する場合は無視される。

/LineSpacing:<value>
/CharacterSpacing:<value>

行間・文字間のスペース量を設定する。0は既定、負値は狭く、正値は広くなる。

/TextureFormat:<value>

テクスチャの出力形式を指定する。

Auto
既定値。モノクロかマルチカラーのフォントによりCompressedMonoかRgba32を自動的に選択する。
Rgba32

高品質でマルチカラーフォントをサポートするが、容量は大きくなる。

Bgra4444

このフォーマットはDirectX 11.1ランタイムとWDDM 1.2ドライバーを必要とするので、Windows StoreアプリやWindows Phone上でカラーフォントのための良い選択となる。

CompressedMono

最もデータ量の小さいフォーマットですべてのD3Dバージョンで動作するけれども、モノクロフォントデータしかサポートしない。この形式では特別なBC2エンコーダーを使用する。詳細はSpriteFontWriter.csのコメントを見ること。

/NoPremultiply

既定ではフォントテクスチャーは事前乗算済みアルファフォーマットを使用する。もしあなたが補完/直接アルファをかわりに使用したいのならこのフラグをセットする。

/DebugOutputSpriteSheet:<filename>

テクスチャーの生成結果をビットマップファイルに出力する(MakeSpriteFontツールをデバックするときに有用であるので、利用者がこのオプションを試してみる必要はない)。

参考情報

http://blogs.msdn.com/b/shawnhar/archive/2007/04/26/bitmap-fonts-in-xna.aspx
http://create.msdn.com/en-US/education/catalog/utility/bitmap_font_maker

Effects

これはXNA Game Studioと同一の機能とAPIを提供する5つのビルトインエフェクトのD3D11ネイティブ実装である。

  • BasicEffectはテクスチャマッピング・頂点カラー・方向ライティング・フォグをサポートする。
  • AlphaTestEffectはピクセルごとのアルファ・テストをサポートする。
  • DualTextureEffectは2階層のマルチテクスチャ(ライトマップもしくは詳細テクスチャのための)をサポートする。
  • EnvironmentMapEffectはキューブ環境マッピングをサポートする。
  • SkinnedEffectはスキン・アニメーションをサポートする。

初期化

    std::unique_ptr<BasicEffect> effect(new BasicEffect(device));

エフェクトパラメータの設定

    effect->SetWorld(world);
    effect->SetView(view);
    effect->SetProjection(projection);

    effect->SetTexture(cat);
    effect->SetTextureEnabled(true);

    effect->EnableDefaultLighting();

エフェクトの描画

    effect->Apply(deviceContext);

    deviceContext->IASetInputLayout(...);
    deviceContext->IASetVertexBuffers(...);
    deviceContext->IASetIndexBuffer(...);
    deviceContext->IASetPrimitiveTopology(...);

    deviceContext->DrawIndexed(...);

エフェクトの頂点シェーダーの入力に合う入力レイアウトの作成

    // First, configure effect parameters the way you will be using it. Turning
    // lighting, texture map, or vertex color on/off alters which vertex shader
    // is used, so GetVertexShaderBytecode will return a different blob after
    // you alter these parameters. If you create an input layout using a
    // BasicEffect that had lighting disabled, but then later enable lighting,
    // that input layout will no longer match as it will not include the
    // now-necessary normal vector.

    void const* shaderByteCode;
    size_t byteCodeLength;

    effect->GetVertexShaderBytecode(&shaderByteCode, &byteCodeLength);

    device->CreateInputLayout(VertexPositionNormalTexture::InputElements,
                              VertexPositionNormalTexture::InputElementCount,
                              shaderByteCode, byteCodeLength,
                              pInputLayout);

座標系システム

ビルトインエフェクトは右手座標系かつ左手座標系の両方で動作する。

違いはフォグの開始と終了の設定を左手座標系では反転させる必要がある(例:右手座標系でSetFogStart(6), SetFogEnd(8)であれば左手座標系ではSetFogStart(-6), SetFogEnd(-8)となる )。

スレッド・モデル

生成は完全に非同期で行われるので、異なるスレッドで同時に複数のエフェクトインスタンスを作成することができる。おのおののインスタンスは同時に一つのスレッドからの描画のみサポートしているが、もしD3D11遅延コンテキストごとにエフェクトインスタンスを作成しているのであれば複数のスレッドで同時に描画することは可能である。

参考情報

http://blogs.msdn.com/b/shawnhar/archive/2010/04/28/new-built-in-effects-in-xna-game-studio-4-0.aspx
http://blogs.msdn.com/b/shawnhar/archive/2010/04/30/built-in-effects-permutations-and-performance.aspx
http://blogs.msdn.com/b/shawnhar/archive/2010/04/25/basiceffect-optimizations-in-xna-game-studio-4-0.aspx
http://blogs.msdn.com/b/shawnhar/archive/2008/08/22/basiceffect-a-misnomer.aspx
http://blogs.msdn.com/b/shawnhar/archive/2010/08/04/dualtextureeffect.aspx
http://blogs.msdn.com/b/shawnhar/archive/2010/08/09/environmentmapeffect.aspx

PrimitiveBatch

これは簡単かつ効率的に線や三角形のような動的に生成された図形を描画するためのヘルパーである。それは古いD3D9 APIのDrawPrimitiveUP と DrawIndexedPrimitiveUPと同じ役割を満たしている。動的送信は手続き的な図形描画にとっては高い効果(を発揮する)パターンで描画をデバッグするにも便利であるが、静的頂点バッファほど効率的ではない。過度の動的送信はアプリケーション中のパフォーマンス問題の共通の原因となる。

PrimitiveBatchはGPUパイプラインのストールを避けるためにDISCARD とNO_OVERWRITE ヒントを使用して頂点およびインデックスバッファを管理する。 それは隣接の描画リクエストにマージされるので、もし1度に100回のDrawLineを呼び出した場合でも1回のGPU描画呼び出しが生成されるのみとなるだろう。

PrimitiveBatchは最終的な描画呼び出しを発行するとき、頂点バッファ・インデックスバッファ・プリミティブ トポロジーの設定に責任を持つ。高レベルなSpriteBatchヘルパーと異なり、それはシェーダーを提供せず、入力レイアウトを設定するか、いくつかの状態オブジェクトを設定する。PrimitiveBatchはしばしばBasicEffectとVertexTypes.hの構造体と共に使用されるが、他のシェーダーもしくはユーザー定義の頂点フォーマットでも動作可能である。

VertexPositionColorデータで描画するためにPrimitiveBatchを初期化するには

To initialize a PrimitiveBatch for drawing VertexPositionColor data:
    std::unique_ptr<PrimitiveBatch<VertexPositionColor>> primitiveBatch(new PrimitiveBatch<VertexPositionColor>(deviceContext));

既定では最大バッチサイズは2048三角形に配列された2048頂点である。もし大きなバッチを使用したいのであれば、追加コンストラクタパラメータを指定する必要がある。

適切なBasicEffectと入力レイアウトを設定するには

    std::unique_ptr<BasicEffect> basicEffect(new BasicEffect(device));

    basicEffect->SetProjection(XMMatrixOrthographicOffCenterRH(0, screenHeight, screenWidth, 0, 0, 1));
    basicEffect->SetVertexColorEnabled(true);

    void const* shaderByteCode;
    size_t byteCodeLength;

    basicEffect->GetVertexShaderBytecode(&shaderByteCode, &byteCodeLength);

    ComPtr<ID3D11InputLayout> inputLayout;

    device->CreateInputLayout(VertexPositionColor::InputElements,
                              VertexPositionColor::InputElementCount,
                              shaderByteCode, byteCodeLength,
                              &inputLayout);

線を描画するには

    basicEffect->Apply(deviceContext);
    deviceContext->IASetInputLayout(inputLayout.Get());

    primitiveBatch->Begin();
    primitiveBatch->DrawLine(VertexPositionColor(...), VertexPositionColor(...));
    primitiveBatch->End();

PrimitiveBatchは5つの描画メソッドを提供する。

  • DrawLine(v1, v2)
  • DrawTriangle(v1, v2, v3)
  • DrawQuad(v1, v2, v3, v4)
  • Draw(topology, vertices, vertexCount)
  • DrawIndexed(topology, indices, indexCount, vertices, vertexCount)

最適化

最大のパフォーマンスのためにはBegin/Endブロックを可能な限り少なくする。これはオーバーヘッドを縮小しバッチの能力を最大化する。

PrimitiveBatchのコンストラクタは確保するインデックスと頂点バッファを確保するために記述することを許可する。あなたは処理負荷に応じてこれらの値をいじるかインデックスのない図形の描画を意図しているのであればインデックスバッファの生成をスキップするためにmaxIndicesの値を0にする。

スレッドモデル

おのおののPrimitiveBatchインスタンスは同時に一つのスレッドからの描画のみサポートしているが、もしD3D11遅延コンテキストごとにPrimitiveBatchインスタンスを作成しているのであれば複数のスレッドで同時に描画することは可能である。

GeometricPrimitive

これは、簡単な幾何図形を描画するためのヘルパーである。

  • 立方体(別名 六面体)
  • 多角形の面で構成された球
  • 円柱
  • 円錐
  • トーラス
  • 四面体
  • 八面体
  • 十二面体
  • 二十面体
  • ティーポット

初期化

std::unique_ptr<GeometricPrimitive> shape(GeometricPrimitive::CreateTeapot(deviceContext));

簡単な描画

shape->Draw(world, view, projection, Colors::CornflowerBlue);

描画命令はオプションのテクスチャーパラメータ、ワイヤーフレームフラグ、既定の描画ステートをオーバーライドして使用することができるコールバックファンクションを受け付ける。

shape->Draw(world, view, projection, Colors::White, catTexture, false, [=]
{
   deviceContext->OMSetBlendState(...);
});

これはデバイスコンテキスト上で描画される幾何プリミティブによって共有されるBasicEffect を使用する。

拡張描画

IEffect* myeffect = ...

Microsoft::WRL::ComPtr<ID3D11InputLayout> inputLayout;
shape->CreateInputLayout( myeffect, &inputLayout );

shape->Draw( myeffect, inputLayout.Get() );

座標システム

Coordinate Systems:

これら幾何学的プリミティブ(XNA Game Studioの慣習により)は右手座標系を使用する。ファクトリメソッドのrhcoordsパラメータにfalseをセットし並び替えを反転することにより左手座標系を使用することができる。

アルファブレンディング

アルファブレンディングは事前乗算済みアルファを使用することが既定である。ストレートアルファテクスチャを使用したい場合はオプションのコールバックを通じてブレンディングモードをオーバーライドする。

Alpha blending defaults to using premultiplied alpha. To make use of 'straight' alpha textures, override the blending mode via the optional callback:
CommonStates states(deviceContext);
    
shape->Draw(world, view, projection, Colors::White, catTexture, false, [=]
{
    deviceContext->OMSetBlendState( states.NonPremultiplied(), nullptr, 0xFFFFFFFF);
});

Model

これはVisual Studio スターターキットの.CMOファイルや古いDirectX SDK の.SDKMESHファイルから剛体モデルを読み込むためのサポートを含む簡単なメッシュの描画を行うための階層構造クラスである。 ModelはXNA Game StudioのModel・ModelMesh・ModelMeshPartの設計に類似したメッシュ描画の実装である。

注意:現在のModelは剛体モデルのみサポートしている。アニメーション、スキニング、フレーム階層構造のサポートはまだ実装されていない。

Modelは1つ以上のModelMeshインスタンスで構成される。ModelMeshインスタンスは複数のModelインスタンス間で共有することが可能である。1つのModelMeshインスタンスは1つ以上のModelMeshPartインスタンスで構成されている。

おのおののModelMeshPartはインデックスバッファ、頂点バッファ、入力レイアウト、エフェクトインスタンス、図形を描画するためのさまざまなメタデータを参照している。それぞれのModelMeshPartは同時に描画されるための1つのマテリアルを表現している(サブメッシュとも呼ばれる)。

初期化

Initialization:

Modelインスタンスは.CMOファイル、.SDKMESHファイル、カスタムファイルフォーマットのいずれかより読み込むことが出来る。ModelローダーはModel間でエフェクトおよびテクスチャーを共有するEffectFactoryインスタンスより得る。簡素化のためにModelローダーはいつもビルトインのエフェクトインスタンスを返すようになっている。メッシュファイル中に記述されたシェーダーへの参照はすべて無視される。

EffectFactoryはEffects.hヘッダーで定義されている。

Visual Studio 2012,2013はビルドプロセスでさまざまなビットマップファイルフォーマットをDDSファイルに変換するのと同様にAutodesk FBXから.CMOファイルを生成することのできるビルトインのコンテントパイプラインを含んでいる。詳細は Visual Studio 3D スターターキットを参照すること。

EffectFactory fx( device );
auto teapot = Model::CreateFromCMO( device, L"teapot.cmo", fx );

古いDirectX SDKにはAutodesk FBXファイルから.SDKMESHファイルを生成するエクスポータがあった。最新バージョンのエクスポーターツールはhttp://go.microsoft.com/fwlink/?LinkId=226208から得ることができる。

auto tiny = Model::CreateFromSDKMESH( device, L"tiny.sdkmesh", fx );

Modelインスタンスはアプリケーションロジックを追跡するための名前(ワイド文字の文字列)を含んでいる。Modelは新しいModelインスタンスの生成時にコピー元のModelMeshインスタンスの参照を共有して複製することができる(浅いコピーと呼ばれる)。

簡単な描画

Model::Draw関数は高機能で簡単にモデルを描画する方法を提供する。

CommonStates states(device);

XMMATRIX local = XMMatrixTranslation( 1.f, 1.f, 1.f );
local = XMMatrixMultiply( world, local );
tiny->Draw( context, states, local, view, projection );

ワイヤーフレーム描画やカスタムステートのオーバーライドのコールバックを提供するためのオプションパラメータがある。

拡張描画

標準のModel::Drawを使うかわりに、ModelMesh::DrawメソッドをModel::meshesコレクション内のリストされた順番にメッシュごとに描画するために使用することができる。 ModelMesh::Drawは不透明部分もしくは透明部分をすべて個々に描画するために使用できる。ModelMesh::PrepareForRenderingメソッドは共通描画ステートをセットアップするためのヘルパーとして使用することはできる。もしくはModelMesh::Drawを呼び出す前に直接ステートをセットアップすることができる。

ModelMeshPart::Drawを選択し、Model::Draw と ModelMesh::Drawの使用をスキップすることによって描画上のさらに詳細な制御を行うことができる。それぞれのModel::meshesコレクションはModelMeshPartインスタンスをすべて列挙するためのModelMesh::meshPartsコレクションを走査することができる。このバージョンの描画のために、ModelMeshPart::effectおよびModelMeshPart::inputLayoutが使用されるか、カスタムエフェクトのオーバーライドが使用される(必ず前もってModelMeshPart::CreateInputLayoutを使用してカスタムエフェクトのため適切な入力レイアウトを作成すること)。

エフェクト制御

Modelローダーはメッシュ中のModelMeshPartのインスタンスごとに適切なエフェクトインスタンスを生成する。一般的にメッシュ中のすべてのエフェクトは同じライティングとフォグ設定を使用すべきであり、これはModel::UpdateEffectsメソッドの実行によって容易に可能である。これはModelMesh中の固有のエフェクトについて一度だけコールバックされる。

tiny->UpdateEffects([&](IEffect* effect)
{
    auto lights = dynamic_cast<IEffectLights*>(effect);
    if ( lights )
    {
        XMVECTOR dir = XMVector3Rotate( g_XMOne, quat );
        lights->SetLightDirection( 0, dir );
    }
    auto fog = dynamic_cast<IEffectFog*>(effect);
    if ( fog )
    {
        fog->SetFogEnabled(true);
        fog->SetFogStart(6); // assuming RH coordiantes
        fog->SetFogEnd(8);
        fog->SetFogColor(Colors::CornflowerBlue);
    }
});

ModelMeshPart::ModifyEffectを呼び出すことによって与えられた部分(モデルローダーにより準備された既定のエフェクトをオーバーするような場合)によって使用されるエフェクトインスタンスを変更することが可能である。

必ず UpdateEffects が使用するキャッシュが正しく更新されるように、影響を受ける ModelMesh インスタンスを参照するすべてのモデルインスタンスで Model::Modified を呼び出すこと。これは適切なModelMeshPart::inputLayoutを再生成する。

前述のように、ModelMeshPart::effect によって直接参照される効果を変更するのではなく、オーバーライドとしてカスタム エフェクトを使用して、モデルのすべてまたは一部をレンダリングすることが可能である。

アルファ・ブレンディング

Alpha blending:

アルファブレンドモデルの適切な描画は複雑な手続きになりがちである。ModelMeshPartは関連した部分が不透明かどうかを示すbool値(isAlpha = false)を持っているか、いくつかの透明度の値を持っている(isAlpha = true)。Model::Drawルーチンは最初に不透明部分を描画し、それからアルファ部分を描画するための基本的なロジックを実行する。詳細な制御は最初にすべてのメッシュのすべての不透明部分を描画し、次に最初に戻りすべてのアルファ部分を描画するために使用できるModelMesh::Drawによって提供される。

事前乗算済みアルファモードかストレートアルファモードを示すために、 ModelMesh::pmalphaが既定のパラメーター(既定ではテクスチャーファイルがストレートアルファである場合はfalseを示す)によって制御されているさまざまなローダー関数によって設定される。もしDirectXTexのtexconv ツールで-pmalphaオプションを指定してテクスチャーを作成した場合、pmalphaにはtrueを設定すべきである。

カスタム描画ステート

Custom render states:

すべての描画メソッドは図形が描画されるときにステートを変更するために使用することができるsetCustomState コールバックを提供している。

 
tiny->Draw( context, states, local, view, projection, false, [&]()
{
    ID3D11ShaderResourceView* srv = nullptr;
    context->PSSetShaderResources( 0, 1, &srv );
});

座標システム

メッシュは通常反時計回りの順で作成される。

Meshes are authored in a specific winding order, typically using the standard counter-clockwise winding common in graphics. The choice of viewing handedness (right-handed vs. left-handed coordinates) is largely a matter of preference and convenience, but it impacts how the models are built and/or exported.

Visual Studio 3D スターターキットの.CMOファイルは開発者は右手座標系を使用することを想定する。DirectXTKの既定ではパラメータは右手座標系を想定しているので、ccwパラメータの規定はtrueである。もし.CMOファイルが左手座標系を使用しているのであれば代わりに時計回りとなるようにccwパラメータにfalseを渡すべきである。これは図形を表示させるが、U軸で反転させたモデル上のテクスチャーを作成する。

古いDirectX SDKの.SDKMESHファイルは左手座標系を想定している。DirectXTKの既定のパラメータは右手座標系を想定しているので時計回りで使用するようにccwパラメータにfalseを設定し、潜在的にU座標反転問題を有している。もし左手座標系を使用したい場合はccwパラメータにtrueを渡すべきである。

フィーチャーレベルに関する注意

もしModelMeshPart16ビットインデックス(DXGI_FORMAT_R16_UINT)ではなく、32ビットインデックス(ModelMeshPart:: indexFormatがDXGI_FORMAT_R32_UINT等)を使用する場合、DirectX11のフィーチャーレベルは9.2以上を必要とする。

もしModelMeshPartがadjacency(ModelMeshPart::primitiveTypeがD3D_PRIMITIVE_TOPOLOGY_*_ADJである等)の場合、DirectX11のフィーチャーレベルは10.0以上を必要とする。もしテッセレーションを使用する(D3D_PRIMITIVE_TOPOLOGY_?_CONTROL_POINT_PATCHLISTなど)場合、DirectX11のフィーチャーレベルは11.0以上を必要とする。

ModelMeshPart中のプリミティブの最大数はフィーチャーレベルに依存している(フィーチャーレベル9.1の場合65535,9.2か9.3の場合1048575,10.0以上の場合4294967295 )ことに留意すること。

スレッド・モデル

Threading model:

ModelMeshPartはデバイスコンテキストではなくデバイスに結びついている。これはモデルの生成/ロードがフリースレッドであることを意味する。描画はイミディエイトコンテキストか遅延コンテキスト上お香ことができるがデバイスコンテキストはスレッドフリーではないことに留意すること。

CommonStates

CommonStatesクラスはよく使われるD3D描画ステートの組み合わせを簡単に設定するためのファクトリである。

初期化

During initialization:
std::unique_ptr<CommonStates> states(new CommonStates(device));

デバイスステートセットするヘルパーをセットするには

deviceContext->OMSetBlendState(states->Opaque(), Colors::Black, 0xFFFFFFFF);
deviceContext->OMSetDepthStencilState(states->DepthDefault(), 0);
deviceContext->RSSetState(states->CullCounterClockwise());

auto samplerState = states->LinearWrap();
deviceContext->PSSetSamplers(0, 1, &samplerState);

使用できる状態

    ID3D11BlendState* Opaque();
    ID3D11BlendState* AlphaBlend();
    ID3D11BlendState* Additive();
    ID3D11BlendState* NonPremultiplied();

    ID3D11DepthStencilState* DepthNone();
    ID3D11DepthStencilState* DepthDefault();
    ID3D11DepthStencilState* DepthRead();

    ID3D11RasterizerState* CullNone();
    ID3D11RasterizerState* CullClockwise();
    ID3D11RasterizerState* CullCounterClockwise();
    ID3D11RasterizerState* Wireframe();

    ID3D11SamplerState* PointWrap();
    ID3D11SamplerState* PointClamp();
    ID3D11SamplerState* LinearWrap();
    ID3D11SamplerState* LinearClamp();
    ID3D11SamplerState* AnisotropicWrap();
    ID3D11SamplerState* AnisotropicClamp();

VertexTypes

VertexTypes.hは共通に使用される頂点データフォーマットを定義している

  • VertexPositionColor
  • VertexPositionTexture
  • VertexPositionNormal
  • VertexPositionColorTexture
  • VertexPositionNormalColor
  • VertexPositionNormalTexture
  • VertexPositionNormalColorTexture

おのおののタイプは適合する入力レイアウトを生成するために使用することができるD3D11_INPUT_ELEMENT_DESC配列を提供する。

例:
device->CreateInputLayout(VertexPositionColorTexture::InputElements,
                          VertexPositionColorTexture::InputElementCount,
                          vertexShaderCode, vertexShaderCodeSize,
                          &inputLayout);

DDSTextureLoader

DDSTextureLoader.hは簡単で軽量な.ddsファイルローダーである。1D・2Dテクスチャー、テクスチャー配列、キューブマップ、ボリュームマップ、MIPマップレベルをサポートしている。このバージョンは古いバージョンの変換は行わないので、.ddsファイルは直接DXGI_FORMATにマップされなければならない(例えば古い24ビットマップ.ddsファイルはロードに失敗する)。.ddsファイルのlegacyとDX10の拡張ファイルヘッダーフォーマットをサポートしている。

フル機能のDDSファイルリーダー、ライター、テクスチャープロセッシングパイプラインはTexconvサンプルとDirectXTexライブラリを参照すること

CreateDDSTextureFromFileとCreateDDSTextureFromMemoryは'texture'リソースのみ(textureViewがnull)の要求、シェーダーリソースビューのみ(textureがnull)の要求、両方の要求の呼び出しが可能である。

CreateDDSTextureFromFile and CreateDDSTextureFromMemory can be called requesting only a 'texture' resource (i.e. textureView is null), requesting only a shader resource view (i.e. texture is null), or both.

maxsizeがゼロでない場合、ファイル中で示されるmaxsizeより大きいmipmapレベルは無視され、(もし示されているいる場合)小さいmipmapレベルのみが使用される。これはロード時にコンテントをスケールするときに使用される。これは.ddsファイルが小さいサイズでリトライするためのmipmapが含まれていることが必要であることに注意すること。

もしmaxsizeが0でテクスチャー生成の最初の試行が失敗した場合、デバイスのフィーチャーレベルで与えられている必要最小サイズより大きいmipmalレベルに切り取ることを試行する。これは.ddsファイルが小さいサイズでリトライするためのmipmapを含んでいる必要がある。

DDSTextureLoaderはBGR 5:6:5とBGRA 5:5:5:1のDDSファイルをロードするが、 DirectX 11.0ランタイム上では生成に失敗する。DXGI 1.2バージョンのDDSTextureLoaderはBGRA 4:4:4:4のDDSファイルをDXGI_FORMAT_B4G4R4A4_UNORMを使用してロードする。DirectX 11.1 ランタイム、 DXGI 1.2ヘッダ、WDDM 1.2ドライバがすべてのフィーチャーレベル上で16bppのピクセルフォーマットをサポートするために必要である。

スレッド・モデル

Direct3D 11でのリソース生成はスレッド・セーフである。CreateDDSTextureFromFileはファイルデータを読み出し中は他のスレッドからの呼び出しをブロックする。CreateDDSTextureFromMemoryは非同期読出しを実装するために使用することができる。

参考情報

http://go.microsoft.com/fwlink/?LinkId=248926
http://blogs.msdn.com/b/chuckw/archive/2011/10/28/directxtex.aspx
http://blogs.msdn.com/b/chuckw/archive/2010/02/05/the-dds-file-format-lives.aspx

WICTextureLoader

WICTextureLoader.hはBMP, JPEG, PNG, TIFF, GIF, HD Photo,その他WICがサポートしているイメージフォーマットのローダーである。これはWICを使用してロード時に必要なイメージのリサイズ処理やピクセルフォーマット変換処理を実行する。

注意:WICTextureLoaderはWindows Phone 8プラットフォームではWICが公開されていないため、サポートされていない。

NOTE: WICTextureLoader is not supported on Windows Phone 8, because WIC is not available on that platform.

注意:WICTextureLoaderはもしサードパーティーのコーデックがインストールされていなければ.TGA をロードする事はできない。もしWICコーデックに依存しないでTGAファイルを使用したい場合はDirectXTexライブラリを使用しなければならない。

CreateWICTextureFromFileとCreateWICTextureFromMemoryはテクスチャーリソースのみの要求(textureViewがnull)、シェーダーリソースのみの要求(textureがnull)、両方の要求で呼び出すことができる。

maxsizeが0でない場合、maxsizeより大きいイメージの場合maxsizeに合う(面積はオリジナルイメージの縦横比を維持するように)もっとも大きい面積にリサイズされる。

もしmaxsizeが0の場合、maxsizeは暗黙的にデバイスのフィーチャーレベル上でサポートされている最少のテクスチャーサイズ(2k, 4k, 8k, 16k)にセットされる

もしDirect3D 11 コンテキストが提供されシェーダーリソースビューが要求された場合(textureViewがnullでない場合)、テクスチャーは自動生成されたmipmapをサポートするように生成され、それを返される前にGenerateMipsが呼び出される。もしコンテキストがない場合(d3dContextがnull)もしくはピクセルフォーマットが現在のデバイスによって自動生成されたmipmapがサポートされていない場合は、シングルレベルのみを持つテクスチャーが結果として返される。

このローダーはテクスチャー配列、1Dテクスチャー、3Dボリュームテクスチャー、キューブマップをサポートしていない。これらのシナリオには.ddsファイルフォーマットかつDDSTextureLoader を使用すること。

WICTextureLoader のDXGI 1.2バージョンでは32bpp RGBAではなく、5:6:5か5:5:5:1の16bpp のピクセルイメージでロードされる。すべてのフィーチャーレベルで16bppピクセルフォーマットを使用するためには、DirectX 11.1ランタイム、DXGI 1.2ヘッダー、WDDM 1.2ドライバーが必要である。

スレッドモデル

Direct3D 11でのリソース生成はスレッドセーフである。CreateWICTextureFromFileはファイルデータを読み出している間は他のスレッドからの呼び出しをブロックする。もしmipmapの自動生成をサポートするためにID3D11DeviceContextを使用する関数の使用はいずれもスレッド・セーフではない。

さらに理解を進めるには

http://go.microsoft.com/fwlink/?LinkId=248926
http://blogs.msdn.com/b/chuckw/archive/2011/10/28/directxtex.aspx

ScreenGrab

ScreenGrab.hはテクスチャー、通常描画ターゲットを.ddsファイルもしくはWICがサポートしているビットマップファイル(BMP, JPEG, PNG, TIFF, etc.)に出力するルーチンである。

SaveDDSTextureToFileとSaveWICTextureToFileはテクスチャーをファイルに保存する。描画ターゲットテクスチャーに対して使用するときはスクリーンショットとなる。2Dテクスチャーのみサポートされ、1Dや3Dテクスチャー(別名ボリュームマップ)に対しては失敗する。2Dテクスチャー配列やキューブマップの場合は最初のイメージのみがディスクに書き込まれる。Mipmapレベルは両方のルーチンで無視される。MSAAテクスチャーは書きこまれる前に解析される。

注意:すべての次元、配列、キューブマップ、mipmapをサポートする完全な.DDSテクスチャーダンプルーチンについてはDirectXTexライブラリを使用する。

SaveDDSTextureToFileは元のリソースのフォーマット(つまり変換なしで)でデータを保存するが、ツールのサポートのためにDX10ヘッダー拡張を可能とするとき古い.dds ファイルを使用することを望むかもしれない。DXGI 1.2バージョンは16bppピクセルフォーマットの書き込みをサポートする。

SaveWICTextureToFileはもし必要かつアルファなしフォーマット(描画ターゲットのアルファチャネルはスクリーンショットと異なる奇妙な結果となることがある)を望むのであればピクセルデータを変換する。呼び出し側は同様にピクセルターゲットフォーマットGUIDを提供することができる。呼び出し側は使用するファイルフォーマットのコンテナのGUIDを提供する。

注意:SaveWICTextureToFileはWICがWindows Phone 8では利用できないのでサポートされていない。

NOTE: SaveWICTextureToFile is not supported on Windows Phone 8, because WIC is not available on that platform.

スクリーンショットをキャプチャーする

WRL::ComPtr<ID3D11Texture2D> backBuffer;
hr = pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )&backBuffer );
if ( SUCCEEDED(hr) )
{
    hr = SaveWICTextureToFile( pContext, backBuffer, GUID_ContainerFormatBmp, L"SCREENSHOT.BMP" ) );
}

スレッドモデル

これらの関数はID3D11DeviceContextを使用するため、スレッドセーフではない。

Since these functions use ID3D11DeviceContext, they are not thread-safe.

参考資料

http://go.microsoft.com/fwlink/?LinkId=248926
http://blogs.msdn.com/b/chuckw/archive/2010/02/05/the-dds-file-format-lives.aspx

SimpleMath

SimpleMath.hはDirectXMath SIMD ベクトル/行列計算APIをC++インターフェースで簡単に利用できるようにするためのラッパーである。それはXNA Game Studio math APIに似たオペレータ・オーバーロード、メソッド、名前の型を提供している、

  • Vector2
  • Vector3
  • Vector4
  • Matrix
  • Quaternion
  • Plane
  • Ray
  • Color

なぜDirectXMathをラップしたのか?

Why wrap DirectXMath?

DirectXMathはX86/X64でコンパイルされるときはSSE SIMDイントリンシック、Windows RTやWindows PhoneのようなARMプラットフォームでコンパイルされるときはARM NEON 命令セットを使用する高度に最適化されたベクトルと行列の演算関数を提供している。効果的にSIMDを使用するように設計されている欠点としては幾分取扱いが難しくなっていることである。開発者は正しい型の使い方を把握しなければならず(XMVECTORのようなSIMDレジスター型とXMFLOAT4のようなメモリストレージ方の違いを理解する)、SIMDのためのヒープ配置のアラインメントを正しく調整するように気を付けなければならず、SIMDレジスターから個々の構成にアクセスすることのないように慎重にコードを実装したりしなければならない。 この複雑さはSIMDのパフォーマンスを最適化するために必要なのであるが、そんなに手間をかけずに作業したいときもある。

SimpleMathを導入しよう

これらの型はDirectXMathのメモリーストレージ型(Vector3のインスタンスはXMFLOAT3を継承している)なので、それらはSIMDのアラインメントを気にすることなしに任意の位置に保存することができ、そして個々のコンポーネントはSIMDアクセサ関数の呼び出しに悩まされることなしにアクセスできる。しかしXMFLOAT3と異なり、Vector3型はたくさんのメソッドとオーバーロードオペレータが定義されており、XMVECTORに値を最初にロードすることなしに直接操作することが可能である。Vector3 はXMVECTORに自動的に変換するオペレータが定義されているので、低レベルのDirectXMathの型で書かれたメソッドに直接値を渡すことができる。

もしそれがひどくわかりにくく聞こえるなら、短くいうとSimpleMath型はあなたが想像しているものとだいたい同じ作業ととなる。

今あなたは落とし穴はどこだ?と不思議がらねばならない。そしてもちろんある。SimpleMathは前後でメモリーとSIMDレジスター間を自動的に変換することによってSIMDプログラミングの複雑さを隠すために、追加ロード・ストア命令を生成する傾向がある。これはSIMDのロードおよびストアがプログラマーの明確なコントロールのもとで行われる低レベルなDirectXMathのアプローチと比較してかなりのオーバーヘッドがある。

あなたは下記のときにSimpleMathを使用すべきである。

  • C# XNA型に似たC++の演算ライブラリをさがしている。
  • C#からC++にXNAコードを移植する。
  • 実行時効率を費やしプログラマーの効率(簡素、可読性、開発スピード)を最適化したいとき

下記のようなときはDirectXMath APIの基礎に進むべきである。

You should go straight to the underlying DirectXMath API if you:
  • 可能な限り高速なコードを生成したい。
  • SIMDでアルゴリズムを表現するために必要な水平思考を楽しみたいとき

これはどちらかを決定する必要はない。SimpleMath型は自身でDirectXMath型にそれらを変換する方法を知っているので、それらを混ぜたり合わせるのは容易である。SimpleMath型を可読性や開発時間を重要視するような部分に使用し、実行時の効率が重要であるパフォーマンスのホットスポットのためにDirectXMathを使用することができる。

RELEASE HISTORY

この部分は省略。。