• Direct3D 11のアルファブレンド設定

    2011年07月15日 22時43分
    前回の続き。

    ニーソ破れる問題がどうしてもわからず悩み続けました。
    悩みすぎて夢の中でもコードを書いている状態です。

    しかし、それ程苦しんだ甲斐があり、閃きが突然訪れました。




    「ぱんつのテクスチャ透明にすれば、ぱんつ脱げるんじゃね!?」




    はやる気持ちを抑え、ボクはテクスチャを編集しました。
    幸いテクスチャは解りやすく、容易くぱんつの部分を透明にすることに成功しました。

    圧倒的な達成感に包まれながらボクはプログラムでモデルを表示しました。


    しかし、待っていたのは思わぬ結果でした。
    なんの変化もありません。


    その後、アルファ値の設定を変えたりしてみて気づいたのですが、
    アルファブレンドの処理がされていないようです。

    そこで今回はアルファブレンドの設定方法です。

    ステータス設定はいつもの手順です。
    1. D3D11_BLEND_DESCにアルファブレンドの設定を入れる
    2. D3D11_BLEND_DESCをID3D11Device.CreateBlendStateに渡してID3D11BlendStateを生成
    3. ID3D11DeviceContext.OMSetBlendStateにID3D11BlendStateをセット
    4. ID3D11BlendStateは終了時にReleaseを忘れずに


    ちょっとはまった点。

    RenderTargetのSrcBlendとDestBlendはD3D11_BLEND_SRC_COLORとかを入れたくるのですが、
    通常はD3D11_BLEND_SRC_ALPHA等を入れるのが正解です。
    これらはRGBのブレンド設定ですが、ブレンドの係数自体はアルファ値を使うためです。


    アルファ値を設定して描画です。
    アルファ値設定済み


    体と足が表示されない!

    つまり、元々このモデルデータは体と足が透明になるのが正しいわけです。
    ということはこの状態で服も描画すれば正常な表示なる!


    アルファ値設定済み全部描画


    ならなかった。
  • Direct3D 11のZFUNC設定

    2011年07月15日 00時02分
    前回の続き。

    さらに表示を直して行きます。

    現在はニーソが破れたような感じになっています。
    また、よく見ると上着も穴が空いています。


    理由がよく解らないので、原因を切り分けようと服と体を別々に表示してみました。

    服のみを表示
    服のみ

    体のみを表示
    体のみ


    どちらも正常に表示されています。
    ということは、Z値が正常でないため、前後関係がおかしくなっていると予想されます。

    他の部分についてはZ値が正常に働いているように見えるので
    ほんのわずかな誤差のせいではないでしょうか。

    というわけで、試しにZバッファの精度を落としてみました。

    現在は32bitにしているところを
    1textureDesc.Format = DXGI_FORMAT.DXGI_FORMAT_D32_FLOAT;


    16bitにしてみます。
    1textureDesc.Format = DXGI_FORMAT.DXGI_FORMAT_D16_UNORM;


    微妙に破れた範囲が広がりました。


    あと思いつくのはZFUNCでしょうか。
    ちょっと比較式を変更してみましょう。

    Direct3D 11のZFUNCの設定ですが、例によってSetRenderStateを呼び出してはいオッケーでは無くなっています。
    次の手順が必要です。
    1. D3D11_DEPTH_STENCIL_DESCに深度ステンシルの設定を入れる
    2. D3D11_DEPTH_STENCIL_DESCをID3D11Device.CreateDepthStencilStateに渡してID3D11DepthStencilStateを生成
    3. ID3D11DeviceContext.OMSetDepthStencilStateにID3D11DepthStencilStateをセット
    4. ID3D11DepthStencilStateは終了時にReleaseを忘れずに

    また面倒ですが、このパターンにも慣れてきました。


    これで比較式を変更出来るので、色々な設定で試してみましたが全く改善されません。
    どうもZバッファの問題ではなさそうです。
  • Direct3D 11のカリング設定

    2011年07月13日 22時55分
    前回の続き。

    影が真っ黒になる問題がありましたが、結局原因は解らず諦めました。
    Specularの計算中powを使うのですが、これの結果がやたらとマイナスの値になるため、
    最終的に合算した色が真っ黒になるようです。

    ただ、powに渡している引数を何度確認してもそんな結果になるはずはなく、
    コンパイラかドライバの問題ではないだろうか・・・と思います。

    if文で切ったりすると、powの累乗数の方に渡している変数が0でおかしくなっているような気がするのですが、
    0を直接書くと正常に動いたりするのでもうわけわからんです。

    powの累乗数に0を指定すると不正なのでコンパイラが関数ごとカットしていたりするのかもしれません。
    コンパイル後のバイトコードを確認すればわかるかもしれませんが日曜プログラマがそこまで出来るわけありません。


    とりあえず回避は出来るのでそれで良しとしました。正常に表示されています。
    真っ黒修正版



    次に気になるのは髪の毛ですね。消えてしまっています。
    これはカリングのせいでしょう。MMDはカリングを無効化する必要があるようです。

    Direct3D 11でカリングを設定する方法ですが、
    Direct3D 9のように、SetRenderStateで設定してはい終わり。というわけには行きません。

    次の手順が必要です。
    1. D3D11_RASTERIZER_DESCにラスタライザの設定を入れる
    2. D3D11_RASTERIZER_DESCをID3D11Device.CreateRasterizerStateに渡してID3D11RasterizerStateを生成
    3. ID3D11DeviceContext.RSSetStateにID3D11RasterizerStateをセット
    4. ID3D11RasterizerStateは終了時にReleaseを忘れずに

    超面倒くさいです。
    予めID3D11RasterizerStateを複数生成しておいて、切り替えて使用することを想定した実装なのでしょうが、
    ちょいとカリング設定すっか!というノリで調べ始めたボクはくじけそうです。

    今回はカリング無しに設定しました。
    1D3D11_RASTERIZER_DESC rasterizerDesc;
    2rasterizerDesc.FillMode = D3D11_FILL_MODE.D3D11_FILL_SOLID;
    3rasterizerDesc.CullMode = D3D11_CULL_MODE.D3D11_CULL_NONE;
    4rasterizerDesc.DepthClipEnable = FALSE;
    5rasterizerDesc.MultisampleEnable = FALSE;
    6rasterizerDesc.DepthBiasClamp = 0;
    7rasterizerDesc.SlopeScaledDepthBias = 0;



    裏面がレンダリングされるようになったため、髪の毛が表示されています。
    カリング修正版
  • MMDのSpecular計算

    2011年06月12日 13時53分
    前回までのあらすじ
    • MMDのライティングよくわかんない。


    古雑誌をゴミ出ししようとしたところ、Windows100%が出てきました。
    つくもたんMMDモデルが付いてるやつです。

    未開封だったため、とりあえずパンツだけは見なければと思い
    昔自作したローダに突っ込んでみました。


    つくもたん
    思いっきり表示がおかしいです。


    直せるだけ直すかと思い、いくらか調べたので書き記しておこうと思います。



    まずは自作プログラムと一番差が出るSpecularから。

    MMDのSpecular計算は次の様になっています。
    1float4 Specula = pow(max(0,dot(normalize(N),normalize(-LightDir.xyz + normalize(Eye)))),SpcColor.w);
    2Specula *- SpcColor;
    3Specula.w = 0.0f;


    ポイントは、視線・光線・法線ベクトルを使って反射率を計算している箇所です。
    1dot(normalize(N), normalize(-LightDir.xyz + normalize(Eye)))


    自作プログラムは次のように計算していました。
    1dot(normalize(-Eye), normalize(reflect(LightDir, normalize(N))))


    現実のモデルを考えると自作プログラムの方の処理になったのですが、
    MMDの方はなにやらよく解らない計算をしています。


    そこで調べたのですが、これはBlinn-Phongという計算式で、
    reflectの計算が重い処理系において、簡単に処理するもののようです。

    MMDはあまりマシンパワーが必要ないように作っているようなので、
    こういった簡略化の処理になっているのではないでしょうか。


    しかしreflectはそんなに重い処理なのでしょうか。
    MSDNを見ると、内部で「v = i - 2 * n * dot(i?n) 」という計算をしているだけのようです。
    あと、計算結果の数値もわりと差が出る気がします。
  • D言語とDirectInputとゲームコントローラと

    2011年04月06日 00時43分
    アクションゲームですとキーボードでの操作は厳しいかと思います。
    なので、DirectInputでゲームコントローラの処理を書きました。

    基本的にC++と同様にやれば動くので
    例によって詳細はどこか他サイトを参照してください。


    ここではDから使うときのポイントだけ書いておこうと思います。


    DirectInputは複数のゲームコントローラを認識出来ますので、
    最初にデバイスを列挙することになります。

    このとき、IDirectInput8.EnumDevicesを使いますが、
    引数の関数ポインタで指定する関数は当然DirectInputから呼ばれますので、定義時に注意が必要です。

    具体的にはextern(Windows)を指定します。
    1extern (Windows)
    2static
    3BOOL enumerateDeviceCallback(const(DIDEVICEINSTANCE)* device, VOID* context)
    4{
    5    // なにがしかの処理
    6}


    軸の列挙に使用するIDirectInputDevice8.EnumObjectsに指定する関数も同様です。


    ちなみに、キーボードいっぱい刺さってたらどうなるんだろう?と思い調べたところ、
    全部のキーボードを1つのキーボードとして認識するそうです。(マウスも)
    DirectInput の使用方法(MSDN)