3Dディスプレイ用レンダリング(Unity編)

最終的に目指しているプロダクト「3Dディスプレイドングル」についてはこちら。
 3Dディスプレイドングルについて

 3Dディスプレイ用レンダリング(基本編)で、3Dディスプレイ用の画像がどんなものかを説明し、3Dディスプレイキャリブレーションツール制作で実際に画像を合成するプログラムを作ってみました。
 今回は、静止画だけでなく初音ミクを踊らせるためにUnityで実装していきます。

●まずはそのまま移植

 まずは順当に、キャリブレーションツールのロジックをそのまま移植しました。
マゼンタとイエローの画像だった部分は、12個のRenderTextureに変更しました。
12個のカメラのレンダリング結果を受ける寸法です。
しかし、まぁ遅い。すごく遅い。6FPS?くらい。
テレビが30FPS、映画が24FPSなので、映画の1/4です。
しかもダンスモーションは30FPSで作られているので、通常の1/5くらいのスピードで踊ります。カクカクです。
 その後、PITCHを掛け算するのではなく足し算にしたりとか、計算結果を配列に保持して使いまわしたりとか計算量を減らす工夫を施して施して、11FPS。限界です。通常の1/3のスピードで踊るミクさんです。
 休みが挟まったりしましたが、これだけで大体1年です。ファイルの最終更新日は2017/7/15まで来ました。この時点でカクツキはするものの、一応初音ミクを踊らせることには成功しました。動画、撮っておいたらよかったんですけどね。

●ComputeShaderを用いた性能改善

 次に30FPSを目指した性能改善です。
ここで私はComputeShaderに乗り出しました。
CPU処理に見切りをつけ、GPU処理を目指したわけです。
 両者の違いはざっくり言って、複雑な計算をこなせる代わりに同時に行えるタスク量は少ないCPU処理、簡単な計算しかできない代わりに同時に大量のタスクを行えるGPU処理、くらいの理解で大丈夫です。
 今回は1200*3*1920に毎フレームアクセスし続けるので、GPU処理の方が早くなると踏みました。
12個のRenderTextureでカメラのレンダリング結果を受けるのはそのままですが、開始直後にサブピクセル位置の計算をCPU処理ですべてやり切ります。
 コメントによるとこう。
 そしてこう。

ここで、さもわかっている風に解説しだすのは私という人物を知っていただくにおいてフェアではありません。私にも過去の私がなにをやりたかったのかさっぱりわかりません。
 少しソースを読んで、考えます。
……
………
ディスプレイピクセルに対する3次元ピクセルの図
 まず、3Dディスプレイで見えるピクセル(3次元ピクセル)に通し番号を振ります。
この番号ごとに、構成するRGBのディスプレイ上の位置(X,Y)を配列に格納します。
0であればR=(0,1),G=(1,3),B=(2,5)、1であればR=(0,0),G=(1,2),B=(2,4)となります。
 ここのポイントはPITCHが出てこない点です。
PITCHに関わらず、3次元ピクセルに対するディスプレイピクセルの対応を配列に格納しています。
これによって、PITCHの端数によってズレが生じてもこの配列の数字の繰り上げで対応できるようになります。

 次に、PITCHに従って3次元ピクセルに画像ピクセルを割り当てます。
 
 すると、先ほどの3次元ピクセルとディスプレイピクセルの対応配列を用いて、ディスプレイピクセルに対する画像ピクセルの対応配列を作れます。
例えばディスプレイピクセル(0,0)はR=1(0,0),G=3(0,0),B=5(0,0)となります。
ディスプレイピクセルに対する画像ピクセルの図

 ここまでやったら、GPUでタスクを1200*1920個起動し、このディスプレイピクセルー画像ピクセル対応配列とRenderTextureを渡します。
 
GPUで起動されたタスクは、配列を読んで、指定された画像ピクセルのRGBをRenderTextureから取り出して、合成して出力画像に格納して返します。
 例えば、0*0番目のタスクは配列の(0,0)番目を読みます。
そこで得られた(1(0,0), 3(0,0), 5(0,0))という情報を元に、1枚目の画像の(0,0)のR、2枚目の画像の(0,0)のG、3枚目の画像の(0,0)のBを合成して出力画像の(0,0)に格納して返します。
このタスクが1200*1920個あるので、画像全体が一気に合成されます。

 正直、GPU処理は奥が深すぎて入り口にちょっと足を入れて引っ込めたくらいでしかありません。多分、というより確実にもっと効率よく合成できるのでしょうが、どこまでできるのかわからないため、やっていません。
 そもそも12枚のRenderTextureを作る時点でGPUでピクセル単位に色を入れてるんだから、そのタイミングで出力画像にはできないのか?とかは常々思っていますが、やり方がわからないので、保留してあります。
 
 さて、この実装によって、40FPS程度出せるようになったので、レンダリング編は以上です。

●立体感の正体

 実はここでもうひとつ問題です。実は、あまり立体的に見えないのです。
これが後述といった部分です。
テストでは立体的に見えましたが、それとは違いがありすぎて原因を特定できていません。
1.ライティングが違うために立体感を覚えづらい
  →マシ。立体的なライティング方法を探す。
2.カメラ配置が違うために立体感を覚えづらい
  →まだマシ。レンチキュラー向けの撮影方法の情報を漁る必要がある。
3.ピクセル配置が設計と異なってしまっているため立体感が得られない
  →バグ潰し、ロジック直し。グロッキー。
4.立体感を得るために適切なピクセル配置がある
  →設計直し。絶望。
5.そもそも動くと立体感を覚えづらい
  →企画終了。

とりあえず、1、2だと思うことにして、保留中です。
そのあたりの細かい部分はコンテンツ編で。

コメント

このブログの人気の投稿

3Dディスプレイの仕組み(発展編)

20190804:成果報告

3Dディスプレイの仕組み(基本編)