2016年8月18日木曜日

C#でレンダリング(深さ情報を扱う)




上が前回のレンダリング結果、下が今回のレンダリング結果。
データは同じだが、見た目的には黒の輪郭線の太さを1から3へ太くしたこと、1面毎に色を設定したことが違いとなる。

表示結果は似たようなものだが、プログラムとしては全く別物となってしまった。

まずBitmapの使用を増やしたこと。
前回はBitmap1枚にどんどん書き加えていたが、今回は出力バッファの他にDepthを管理するための画像や、現在のポリゴンのレンダリングバッファと、その深さを描くためのバッファを用意した。
前者2枚はレンダリング開始から終了まで常に開きっぱなしだが、後者2枚についてはポリゴン1個毎に動的に生成している。

深度管理の画像は予めColorと深さ値(今回はintを使用し24bitで管理)を相互に変換する関数を作成しておく。次に出力Depthを最遠でクリアしておく。
ポリゴンを書く場合は画像1枚にポリゴンの画像を、もう1枚にDepth値を書き込む。
その後でDepth値と深さ値画像を比較し、Depth値が深い場合はアルファを0にして透過させ、すべてのピクセルでこの処理を行った後に、バッファとDepthをそれぞれDrawImageで出力バッファに書き加える、という処理になる。

Depth値は1ピクセル毎に計算しているのではなく、ポリゴンの各頂点の平均値を使用している。そのため1ピクセルごとの位置を計算する手間は必要ないが、それでも上の画像を作るだけでかなり時間がかかる(0.8秒程)。
一般的なレンダリングエンジンではGPUの数千コアで並列処理するが、CPUの1コアだけで処理しているために非常に時間が掛かる。

400x400ピクセルの画像で、6面を表示し、辺も含めると12枚の画像となる。それぞれレンダリングとDepthがあるから、24枚の画像をforネストで操作していることになる。それでも3.84Mピクセル程度なので2000x2000ピクセルの画像1枚分程度なのだけど。



このくらいの処理であればCUDAで書くのはそんなに大変ではない気もする。ウチのグラボはGeF 970なので、1000コアくらいで並列処理できるのかな。
でもそこまでやるならレンダリングエンジン探してこいよ、という話になってしまう。

とりあえず、平行投影とはいえ前後に重なったポリゴンを適切に表示できるモノを作っただけでも満足かな。

0 件のコメント:

コメントを投稿