• 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) 」という計算をしているだけのようです。
    あと、計算結果の数値もわりと差が出る気がします。