モコモコフレンズの3Dモデルをレイトレーシングで全員集合

まとめ: http://d.hatena.ne.jp/mjt/20150422/p1

キャラクターデータ提供:見習い魔女とモコモコフレンズ

というわけでなんとなく始まった一日一モコモコ3DSソフトの見習い魔女とモコモコフレンズのキャンペーンで提供されるモデルデータを色々な方法で鑑賞しよう企画も本日最終日。


最終日の今日は、昨日使用したレンダラ akari2( https://github.com/githole/akari2 ) を改造してテクスチャマッピング機能を追加してレンダリングしてみる。昨日のエントリ ( http://d.hatena.ne.jp/mjt/20150418/p1 ) も参照のこと。

stb_imageによるテクスチャ読み込み

今回はテクスチャフォーマットとしてはPNGを採用する。というわけで読み取りはstb_imageで一発。

ptr = stbi_loadf(filename, &x, &y, &components, 0 /* req_comp: False */);

stbi_loadfで、LDRテクスチャ(0-255)からHDRテクスチャ(0-1.0)への変換も一撃でOK。LDRHDRの混在環境としては、FF零式の事例( http://hexadrive.jp/lab/case/1573/ )が面白い。

テクスチャサンプリング

akari2には作り掛のテクスチャマッピング実装が有るので、それを修正して使う。
Hitpoint構造体にはhittest後に重心座標系で表現されるヒット地点の座標 (b1,b2) が含まれているので、これをUV座標に変換する。UV座標を導出するには、単に3頂点に含まれているテクスチャのUV座標を線形補完するだけでOK。

m = *vt[0] + b1 * (*vt[1] - *vt[0]) + b2 * (*vt[2] - *vt[0]);

この式で、b1 と b2 にそれぞれ0とか1を代入するとちゃんとvt[1]やvt[2]になる。b1 = 1, b2 = 1はそもそも三角形の中に無いので考える必要は無い。

const float z = 0.0f;

今回は2Dテクスチャを使うので、頂点のテクスチャ座標 vt は2次元座標となる。というわけで、2次元座標を読むように修正。

投影マッピング

モコモコフレンズのモデルは、顔面からちょっと浮いた位置に目や口を描いている。これをそのままレイトレーシングに掛けてしまうと、口元目元に不自然な影が浮くことになる。

これを回避するために、レイを顔面に当たるまで延長し、顔面に"投影"する機能を追加する。
マテリアルに新フラグ projection を追加し、sendとreceiveの2値を設定可能にした。sendは投影側、receiveは投影を受ける側で、send側ではレイを透過させ、receive側にsend側の色を反映させる。

/* Skip this triangle and set in_projection states */
now_ray = rt::Ray(hp_position + 1e-3f * now_ray.dir, now_ray.dir);                  /* レイをちょっと進める */
t.fetchTextures(now_hp.b1, now_hp.b2, &projection_color, &projection_alpha, NULL);  /* projection_colorを後で合成する用に保存 */
in_projection = true; /* フラグ立てる */
continue;
  • 投影される側(顔面)
if (in_projection && material->projection_receive) {
    if(projection_alpha > 1e-4f){
        diffuse = projection_color; /* in_projectionで、projection receiveだったら色を置き換え */
    }
}
in_projection = false;

... これは物理的には全く正しくない(プラ板に目とか口を描いて、のっぺらぼうの顔に写しているようなものではあるが。。)。