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

catalinaの備忘録

ソフトウェアやハードウェアの備忘録。後で逆引きできるように。

HololensでMMDモデルをレンダリングしてみる[c++/UWP]

3Dモデルが出せたのでモチベーション上がり始めています。かたりぃなです。

環境 * HoloLens * Visual Studio 2015 * DirectX11 * C++/cx * UWP

とりあえずスクリーンショット f:id:Catalina1344:20170208220522p:plain やっぱりこうやって何かが出ると「アプリ作ってる」感でてきますね。 UWPでのDirectXの扱いに慣れていなかったので、詰まったポイントを整理していきます。 DirectX11そのものの扱いはほかにもっと詳しいサイトがありますし。

頂点シェーダが2種類存在している

vertex shaderですが、VisualStudio2015でHoloLens向けのテンプレートを生成すると、なぜかこれが2つ生成されます。

  • VertexShader.hlsl
  • VPRTVertexShader.hlsl

何者かというと、"VertexShader.hlsl"のほうがシミュレータで走らせるためのもののようです。"VPRTVertexShader.hlsl"はHoloLensで実行するものです。 しかしVPRTって何なのかよくわかっていません。あとで調べます。

なので、シミュレータで動くけど、実機で動かない(レンダリング周りの初期化でエラーになるとか)って時はこの2つのファイルの整合性を確認すると幸せになれそうです。

入力アセンブリの初期化で失敗する(CreateInputLayout)

先ほどのVertexShaderへの入力レイアウトの定義をもとにCreateInputLayoutするとシミュレータではうまくいくけど実機ではうまくいかないという罠にハマりました。 これもVertexShaderの入力が上記2種類で違いがあるために起きていました。 戻り値だけみても具体的に何が悪いのかわかりません(E_INVALIDARG)が、デバッグモードで起動していれ出力ウインドウに詳細を出してくれるので、よく読めばわかる問題でした。

実機でのレンダリング結果が壊れる(像がブレるなど)

HololensではDrawIndexedではなくDrawIndexedInstancedという関数を使います。 これは複数のインスタンスレンダリングするときに使うものです。

シェーダーでどちらのインスタンスを参照してレンダリングするかを決めています。(ここではCPUから渡された変換行列のどちらを参照するかを決めているだけ)

    int idx = input.instId % 2;
    pos = mul(pos, model);
    pos = mul(pos, viewProjection[idx]);
    output.pos = (min16float4)pos;

推測になりますが複数インスタンスとして左レンズと右レンズ用のインスタンスを作っていてそれを使い分けているのでしょう。

このあたりのインスタンスの参照先をうっかり書き換えてしまうと、像がブレる(というか、壊れて見える)ので要注意です。

あとは引数がやたら多いので、間違えないように注意です。

感想と今後の展望

とりあえず3Dモデルのレンダリングという基礎的な部分は作れるようになりました。モーションはシェーダの勉強と平行して実装していきたいところです。

あとHoloLensのSpatialMapping(空間認識)はちょっと独特(実際の物体よりも大きく空間を認識している)なので、アプリ側でもうちょっと改善できないか試してみたいところです。

最後にどうでもいいこと

HoloLensの空間認識は赤外線によるもの(Kinnectのような仕組み)だということなので調べてみました。 本当に赤外線出してるのかどうかスマホのカメラで見てみました。 アプリを起動していない状態では何も出ていないので、空間認識のサンプルアプリを起動した状態で撮影。 f:id:Catalina1344:20170207161543j:plain

写真のように光っています。これは一定のインターバルで点滅していました。やっぱり赤外線なんでしょうね。ほかのセンサがどう動いているかはこの写真ではわかりませんが。