「 DirectX11 」一覧

DirectX11でMSAA


DirectX11でMSAA(Multi Sampling Antialias)を試してみました。
検索でよく見つかるのが、プライマリのバッファをMSAA使用する例はよくみかけるのですが、テクスチャレンダリングする場合においてMSAA有効でレンダリングするというサンプルを見つけることはできませんでした。
そんなに難しい話ではないのですが、サンプルプログラムが見つからなかったので今回作成してみました。

まずは結果です。テクスチャを描画先(レンダーターゲット)として三角形を描画しています。その結果をテクスチャとして取得して、四角形のポリゴンに貼り付けて表示しています。
result-msaa

結果を見てもよくわからないので、MSAA OFFの場合の結果を以下に表示します。

msaa-off

これでもよくわからないかもしれません。そこで両者を比較して拡大したものを示してみます。これならば違いがわかるでしょうか?MSAAが有効なものについては、ポリゴン境界がなめらかに見えるように色が補間された結果が見えています。

msaa-comp

手順について

レンダーターゲットとしてテクスチャを使う方法についてはここでは説明しません。
ここではMSAAテクスチャを作成する方法と、それをテクスチャとして使う方法の2つを説明したいと思います。

MSAAテクスチャの生成

描画先となるテクスチャを作成する際に、MSAA用のパラメーターを設定します。
D3D11_TEXTURE2D_DESC 構造体の SampleDesc内のパラメータが該当するのですが、ここにパラメータを指定します。

これらのパラメータの設定がよくわかりませんでしたが、下記に示すように CheckMultisampleQualityLevels から取得できる Quality値を指定しておけばよいようです。

この例だとおそらく 4x の MSAA が有効となるようです。

MSAAテクスチャとして使う

上記の pRenderTargetにたいして描画行われた後でテクスチャとして使用するためにはResolve処理を行わなくてはなりません。またこのときに、Resolve結果格納先として別のテクスチャが必要になります。
普通はこのResolveされたのテクスチャを他の描画で使用します(正確にはこのテクスチャのShaderResourceViewを、ですが)。

まずはそのResolveテクスチャの作成についてはこんな感じになります。

Resolve処理

簡単ですが、D3DDeviceContextについて以下のAPIを呼ぶだけです。

レンダーテクスチャを使う際の注意点といいますかお作法として、
レンダーテクスチャ(RenderTargetViewとして)セットする前に、そのテクスチャがShaderResourceViewとしてセットされていないか確認し、すでにセットされているならば解除しておくことが望ましいようです。
D3Dのデバッグレイヤー有効にするとわかるのですが、シェーダーリソースとして設定されているものをレンダーターゲットとして設定した際に、警告メッセージが表示されます。これはそのシェーダーリソースがシェーダーで使用されていなくても警告がでますので要注意です。

サンプルプログラム

今回のサンプルプログラム全体です。VisualStudio2012で作成しています。
SampleMSAA11サンプルプログラム(Zip)

まとめ

意外と使われないのか、テクスチャに対するMSAAをやってみました。


Draw Indirect 系を調べてみた (OpenGL vs DirectX)


OpenGL では Draw Indirect 系が充実しているとの情報があったので、DirectXとどのように違うのかを調べてみました。

DirectX 11 では、 DrawInstancedIndirect(), DrawIndexedInstancedIndirect() の2つの関数が DrawIndirect系として使用可能です。DirectX10では DrawAuto() という関数が存在して、DirectX11ではこれを汎用化して上記の関数群となったようです。

上記の関数はインデックスバッファ有・無しの違いで分かれているだけで、インスタンス描画を考慮するもののそれ以上の機能は持っていないようです。

一方で OpenGL の Draw Indirect 系は次の関数が用意されています。

  • glDrawArraysIndirect()
  • glDrawElementsIndirect()
  • glMultiDrawArraysIndirect()
  • glMultiDrawElementsIndirect()

ちなみに、glMultiDrawArraysIndirect() は、複数回の glDrawInstancedIndirect() を1回の呼び出しとするようなものです。また glDrawArraysIndirect() が DrawInstancedIndirect() に相当するようです。Indirectのバッファの中には、インスタンス数を指定する項目も含まれるようです。

複数回の描画を束ねられる glMultiDrawArraysIndirect ですが、結局のところ CPU 側に描画数を通知しておく必要があります。そこが何ともうまくないところですが、ARB_indirect_parameters という拡張でこの対策がおこなわれているようです。
 ARB_indirect_parameters では、インスタンス数を格納しておくためのバッファが追加サポートされるようになります。そのバッファが GL_PARAMETER_BUFFER というもので、GLsizei のデータを入れておく入れ物となっています。関数としては、glMultiDrawArraysIndirectCount, glMultiDrawElementsIndirectCount となっています。


DirectX11で旧シェーダーコード(HLSL)を使う


DirectX11(DX11) は DirectX9(DX9) に対応したハードでも一応動かすことが出来ます。このとき、DX9 にのみ対応ハードで動かす場合、DX11 の機能は当然使えません。シェーダーに関しても同様で、頂点シェーダー、ピクセルシェーダーのみを使用することになります。

fxcや関連するドキュメントをみると、そういった DX9 ハード用のシェーダープロファイルとして、次のものを使用するようになっています。

  • vs_4_0_level_9_0
  • vs_4_0_level_9_1
  • vs_4_0_level_9_3
  • ps_4_0_level_9_1
  • ps_4_0_level_9_3

確かに、DirectX11 の仕様を守って新規にシェーダーファイルを作って行く場合には何の問題も無いのですが、昔からのコードを現世代で動くようにと作業している場合、これだけの指定では足りないのです。

例えば、以下のようなシェーダーファイルのコードがあったとして、これを上記のプロファイルに従い、 vs_4_0_level_9_3 でコンパイルしたとします。

これをコンパイルすると次のようにエラーが表示されます。

fxc /T vs_4_0_level_9_3 vs.hlsl

error X4541: vertex shader must minimally write all four components of SV_Position
compilation failed; no code produced

これをエラー無く、かつ、シェーダーコードを修正することなくシェーダーコンパイルを成功させるためには、/Gec オプションを指定します。

fxc /T vs_4_0_level_9_3 /Gec vs.hlsl

これで vs_4_0 系のタイプでシェーダーをコンパイルすることが出来、DirectX11 のプログラム上で使用することが可能になります。
内部的には、出力セマンティクスのPOSITION を SV_POSITION として勝手に扱ってくれるようです。コマンドラインでコンパイルした結果を見るとそんな感じに見えます。

なお、D3DX11ShaderCompileFromFile で、この “Gec” オプションに相当するものは、 D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY となるようです。

感想

意外と DirectX11 で古いシェーダーコードをそのまま使うという話はないのかな?と思いました。
調べてみても情報はほとんど出てきませんでした。
確かにDirectX11 は初心者にはちょっと手間な部分も多いですし、ある程度までなら DirectX9 を使ってしまった方が楽で、やりたいことを実現できますし。
それでもどこかで、同じように悩んだ人に、この記事が役立ってくれるといいなと思います。


DirectX11とDirectX9比較


DirectX11(D3D11)はDirectX9ハードウェア上でも動きます。
そういう場合に、DirectX11とDirectX9ではどちらを選択すべきだろうか、と思ってちょっと比較をしてみようかと思います。

チェック環境

  • RADEON HD 5450(DX11対応ハード)
  • Geforce9600GT
  • Geforce6800GT

サンプルプログラムとしてBasicHLSL11というSDK付属の物を使います。
これを実行してFPSの計測を行います。

チェックしてみる項目は以下の通り

  • D3D11デバイスでD3D_FEATURE_LEVEL_11_0
  • D3D11デバイスでD3D_FEATURE_LEVEL_10_0
  • D3D11デバイスでD3D_FEATURE_LEVEL_9_3
  • D3D9デバイス

結果

それぞれの場合でFPSを計測すると以下のようになりました。
(解像度は800×600)

条件 FPS値(5450) FPS値(9800GT) FPS値(GF6800)
D3D11+D3D_FEATURE_LEVEL_11_0 1170
D3D11+D3D_FEATURE_LEVEL_10_0 3625
D3D11+D3D_FEATURE_LEVEL_9_3 1220 4183 1604
D3D9 965 1367 1201

D3D9 vs D3D11では、圧倒的にD3D11の方が高速に動作しているようです。
そして貧弱なハードウェアだからか、レベルを落とした方が若干高速でした。
この結果を見ると、DX9とDX11(9_3レベル)を悩むならDX11のほうがよいと言えます。


DirectX11始めました -第3回-


今回はプログラムを修正して4角形にしたうえで、テクスチャを貼ってみます。

今回のプログラムの流れ

準備段階

第2回のものに加え、以下の準備を行います。

  1. テクスチャの準備
  2. サンプラーオブジェクトの準備

また以下の修正を行います。

  1. 頂点データの修正
    1. TEXCOORDの追加
  2. シェーダーの変更
  3. 頂点入力レイアウトを変更

メッセージループ

画面クリア処理の後、以下の設定を行います。

  1. バッファのセット
    1. 頂点バッファのセット
    2. 入力頂点の情報オブジェクトをセット
  2. シェーダーのセット
  3. テクスチャのセット
  4. サンプラーオブジェクトのセット
  5. 描画命令を発行

テクスチャの準備

今回はD3DXの関数を使って楽にテクスチャを作成します。

シェーダーから使うテクスチャは ID3D11ShaderResourceViewとして表現されます。
D3DX11には便利な関数が用意されていて、D3DX11CreateShaderResourceViewFromFile というものを使うと、ファイル名を指定するとこのID3D11ShaderResourceViewを作成してくれます。

サンプラーオブジェクトの準備

D3D11_SAMPLER_DESCの構造体に値を代入し、CreateSamperStateメソッドにてサンプラーオブジェクトを作成します。

頂点バッファの修正

このような感じで、頂点データおよび頂点バッファの作成部分を修正します。

シェーダーの修正

テクスチャを使うようにシェーダーファイルを修正します。

頂点シェーダー

ピクセルシェーダー

頂点入力レイアウトの修正

TEXCOORDのセマンティクスが追加されているので、それにあうように修正します。

描画処理

シェーダーのセットしたあたりで、テクスチャとサンプラーオブジェクトをセットします。

感想

DirectX10のサンプルを書いていたときには、テクスチャの作成がもう少し手間でした。
一旦ID3D10Texture2D作って、そこからシェーダーリソースビューを作っていました。
今回は、D3DXのAPIの中に便利なものがあったのでそれを使ってみました。1行でシェーダーリソースビューが取得できてしまうので便利です。
とはいえ、DirectX9のときには、D3DXCreateTextureFromFileが使えたので、それと同じことだったりします。

HelloDX11_3 ソースコード


DirectX11始めました -第2回-


今回は画面に三角形1つを出すまでをがんばってみます。

今回のプログラムの流れ

準備段階

第1回のものに加え、以下の準備を行います。

  1. 頂点バッファの準備
  2. シェーダーの準備
  3. 頂点入力レイアウトオブジェクトを作成

メッセージループ

画面クリア処理の後、以下の設定を行います。

  1. バッファのセット
    1. 頂点バッファのセット
    2. 入力頂点の情報オブジェクトをセット
  2. シェーダーのセット
  3. 描画命令を発行

頂点バッファの作成

頂点バッファを指定サイズで作成し、
ある初期値をコピーするようにして初期化まで行います。

シェーダーの準備

ピクセルシェーダーもほぼ同様なのでここでは頂点シェーダーだけの説明にします。

まずHLSLで記述したファイルから読み込みコンパイルを行います。
その後、コンパイル後のバイトデータ列からシェーダーを作成します。

なお、頂点シェーダーのバイトデータ列はこの後の処理でも使うので、
即座に解放することは出来ません。

また、DirectX SDK 2009Augustのものでは、
D3D10Blobを使うようになっていました。
DirectX SDK 2010June版では、D3DBlobを使うようです。
新しいバージョンのSDKでは、どうやらD3D[10,11]の部分の番号が取れていく傾向にありそうです。
特に機能拡張のないデータに関してはそのようになるっぽいです。
シェーダーのコンパイルのフラグもD3D10となっていますが、新しいSDKではバージョン番号が取れている物を使用することが出来るので、
DirectX11なのにDirectX10の設定を使うことに関する違和感は軽減されるかと思います。

手元が2009Augのため、DirectX11RTM版のSDKでは~という話です。
こんな変更もあるし、開発に使用するSDKのバージョンも再検討したほうが良さそうです。

自分がDirectX SDK 2009Augなのは、Windows7環境でDirectX9が正しく動作する最低バージョンだからです。

頂点入力レイアウトの作成

従来でいう頂点宣言になります。
頂点データがどのような構造で入力されていくかを示すオブジェクトになります。
この情報を作成するのに、頂点シェーダーのバイトデータ列が必要になっています。
このあたりはDirectX10と変更は特にありません。

描画処理

画面のクリア後には、今まで作成したオブジェクトをセットしていきます。

この部分も例によって、ID3D11ImmediateContextに対して設定し、描画コールを行います。
デバイスのオブジェクトではなく、コンテキストに対する描画発行となっています。
また、シェーダーのセットでも若干引数が増えました。
今回は使用していないので、ゼロが設定してあります。

シェーダーコード

現在のシェーダーコードはこんな感じです。

頂点シェーダー

ピクセルシェーダー

感想

DirectX SDK 2009Augを使用しており、これはDirectX11 SDK RTM版といえます。
そのため、シェーダー部分を筆頭に、D3D10, D3D11と入り乱れた感じで初期化になっています。
新しいSDKならこのあたりは解消されているらしいので、プログラムの見やすさは良くなると思います。

あと、算術関連がD3DXではなくxnamath.hに入るようになっていました。
この部分は大きな変更と言えそうです。
“XNA Math”だからプレフィックスは XM*** ということっぽい(XMFLOAT3 とか)。

ソースコードと画面

今回のソースコードです。 HelloDX11_2ソースコード


DirectX11始めました


はじめに

Windows7 SP1やVisualStudio2010 SP1が出ている現在において、未だにDirectX11を扱うプログラムコードを作ったことがありませんでした。2011年4月と”11″繋がりで、ちょっとDirectX11を始めてみました。

いつものことですが、画面をクリアするまでの最小限サンプルをまずは作ってみようと思います。

昨年夏にDirectX10の記事も同じように書いたので、
DirectX10とDirectX11でどんなふうに変わったかも気付く範囲で書いてみます。

プログラムの流れ

手順としては以下のように実装をしていきます。

  1. スワップチェインとD3D11デバイスのセットアップ
  2. バックバッファを描画対象とするための設定
  3. バックバッファに対するデプス・ステンシルの準備
  4. 準備したデータを描画対象に設定
  5. メッセージループ
    1. バックバッファのクリア
    2. 表示バッファの更新

D3D11デバイスの作成

まずDXGIでスワップチェインの準備を行います。
DXGIはD3D11よりも低位に位置し、グラフィックスハードウェアの情報を扱うレイヤーになります。
スワップチェインはこのレイヤーに属します。
また、画面の解像度等を取得したいとき、フルスクリーン表示にしたいときにもDXGIにお世話になります。

このDXGIの設定についてはDirectX10のDXGIの設定をほぼ変わっていないようです。

続いて、機能レベルの設定です。
DirectX11では多くの環境で動作させることが出来るように設計されているので、
プログラムがハードウェアのサポート範囲をどこまでにするかを決めるために必要です。
ここでは以下のようにして、範囲を絞ってみました。

デバイスの作成

スワップチェインの設定と、機能レベルの設定を引数に設定して、
DirectX11のデバイスを作成します。
他の項目も色々とありますが、多くの場合はこのようなコードになると思います。

DirectX11からデバイス以外にも必要になるDirectXのオブジェクトがあります。
それは、上記のコードでいう pImmediateContext です。
どちらかというと、従来の環境でのデバイスはこのpImmediateContextが担当する感じです。

また、supportLevelの値を確認することで生成されたデバイスおよびコンテキストがどの機能レベルなのかを知ることが出来ます。

バックバッファの準備 -カラーバッファ設定-

DirectX11ではDirectX9と違い、バックバッファのカラーバッファの設定を自分でおこなう必要があります。
デバイス生成状態ではバックバッファは1つ存在します。
これを描画先とするために、ビュー(RenderTargetView)を作成します。

このビューを作成するまでのコードは以下のようになります。
この部分はDirectX10のときと全く同じです。

バックバッファの準備 -デプスステンシル設定-

カラー用はスワップチェインで用意されたバックバッファでしたが、
デプスやステンシルのバッファは自分で作成する必要があります。

  1. デプス&ステンシルのテクスチャを用意
  2. そのテクスチャをバックバッファとして扱えるようにビューを作成

このような手順で行います。

ビューを作成したら、テクスチャのインターフェースは解放しておきます。

描画先設定

今まで準備したバッファを描画対象として、デバイスに設定します。
デバイスに設定するのですが、pImmediateContext、すなわち、ID3D11DeviceContextインターフェースに対して設定します。

このID3D11DeviceContextに対して設定する部分が D3D10と違いますね。

画面のクリア

クリア処理は、デバイスに対して行うという感じではなく、
コンテキストに対して、クリアするビューを設定して行う、という感じになっています。

後始末

感想

DirectX10をやっていれば、そこまで大きく変わった感じはしないですね。
今までデバイスに指示していたのがデバイスコンテキストへ指示と変えたくらいです。

今回のソースコード

HelloDX11 ダウンロード


DirectX11ちょっと調べてみた


DirectX11環境でのDX9ハードウェア

DirectX11(D3D11)では、DX9ハードウェア上でも動作します。
正確には、DX9相当の機能を使う分には動作できるという感じです。

使用するAPIを変えなくてもDX9ハードウェアからDX11ハードウェアまで
動作できるというのは魅力ですが、何もしなくても動作するというのとはちがうようです。

新しい環境でも、古い環境でもそれぞれの出来る範囲で動作するということを考えたときには、
ハードウェアが備えているレベルに応じて処理を切り替えることが必要になります。

たとえば、DX10相当のハードとDX9のハードでは、使用できる定数レジスタのサイズが全く違います。軽く試してみたところ、vs_4_0_level_9_3のプロファイルで、大きな定数バッファを使用するHLSLシェーダーファイルはコンパイルに失敗します。

まぁ、そうなるだろうと予測していましたが、納得の症状です。

よって、ハードウェアを見ながら使用するシェーダーを変更する、ということが
それぞれの環境での最良のパフォーマンスを引き出すのには必要になります。


書籍かってきた ちょっとだけDirectX11


DirectX11に興味があってそろそろ触らなきゃなぁと思っていたところ、
”ちょっとだけDirectX11”という書籍が最近出たので購入してみました。早速ですが、ちょっと残念な点がいくつか。

統合型シェーダーアーキテクチャ

これ、GPUの部分についてのアーキテクチャなのですが、
本文中では、DirectX側の変更点のように読み取れました。

統合型シェーダーアーキテクチャを採用した DirectX10が登場しました

DirectX10で必要とする機能を効率よくハードウェアで実現するためには、
単に統合型シェーダーアーキテクチャを採用するほうが都合がよかっただけで。

また、DirectX9であっても、統合型シェーダーアーキテクチャのビデオボードであれば、
動くわけですし。

マルチサンプル

書籍の後半でこの単語があったので、読んでみるとどうやら思っていたのと違う。
やっていることとしては、”マルチテクスチャ”でした。
てっきりぼかしや何かのテクニックのために、1つのサンプラから複数点を取得する意味での
マルチサンプル(マルチサンプリング)かと思いきや・・・。

よかった点

Direct2Dについて説明してある部分と、
D3D11でのEffectがうまく動かなかったという記載はよかったと思います。
試そうとして、うまくいかないっていうことを1つ避けられたように思います。

でも、別にエフェクトファイルでやらなくてもいいのでは?と思ったり。
VS/GS/PSそれぞれシェーダーを設定するようにしても、
このくらいのサンプルなら複雑にならないような気がします。