ボリュームレンダリング
概要
ボリュームレンダリングは主に放射線の吸収量をコンピューターグラフィックスとして表現する医用画像や非破壊検査などの領域で使用されている手法である。ボリュームレンダリングではモデルの表面だけのポリゴンと異なり、モデルの中身まで描き出すことができる。大雑把に言えばマインクラフトで「何か」を作り上げたような感じである。
コンピューターおよびグラフィックボードの高性能化により、ゲームなどのポリゴン主体の3Dにおいても、雲の表現などの古くからビルボードという手抜き手法が使われていた部分を高画質化する手法として採用され始めている。
アルゴリズム
ボリュームレンダリングといっても様々な手法があるが、現在ではほぼレイキャスティングを用いたもの一色となっている。
ボリュームレイキャスティング
レイキャスティングは「ゲームの当たり判定」などのにも使われる汎用的なアルゴリズムであり、ボリュームレンダリングだけのアルゴリズムではない。これを明確にするために「ボリュームレイキャスティング」と呼ばれることも多い。
レイキャスティングは「ボクセル」と呼ばれる3次元のビットマップのようなデータ(配列)からデータを抽出する処理をいう。まず視点位置と描画対象ピクセルのベクトル(レイを伸ばす角度、方向)を求める。これが「レイ」であり、このレイをまっすぐ伸ばし、ボクセルを貫通した位置にあるデータが抽出対象となる。
このレイキャスティングで得られたデータ(配列)をもとに、最大値や最小値、平均値、中央値、単純に加算など、様々な方法により加工することで最終的な映像(1つのピクセル)を取得する。この加工方法が重要であり「加工方法≒アルゴリズム名」となっている。
- MIP (Maximum Intensity Projection) = 最大値
- MinIP (Minimum Intensity Projection) = 最小値
- RaySum (Ray Summation) = 単純加算、CT値などは相対値なので足し合わせると勝手に平均値になる
- Surface Rendering = 特定範囲の値、かつ最初に出現したもの
- Volume Rendering = 特定範囲の値、かつ不透明度マップを掛けたもの
これをひたすら繰り返す。すると最終的に1枚の画像になる。
並列処理
ボリュームレンダリングではアプリの表示領域のピクセル単位でレイキャスティングを行う。たとえば縦512x横512の解像度の画像を生成しようと思った場合、「512x512=262144回」のレイキャスティングを行うことになる。ちなみに「より高画質に」という要望の場合には目的の解像度の2倍から16倍程度の解像度の画像を一旦生成し、目的の解像度に縮小するという手法が用いられる。 いわゆる「MSAA」だね。
話は逸れたが「512x512=262144回」は凄い数だ。
ただこの処理は一方的なデータの「取得」である。データの「変更」は伴わない。出力先の画像も1ピクセル毎に処理しているので同じメモリ番地に重複して書き込まれることもない。つまり排他制御も何も考えずに並列化できる。
昨今のマルチコアなCPUが簡単に活かせる。また、GPUに搭載されるピクセルシェーダー(宗教上の理由によりOpenGLの世界ではフラグメントシェーダーと呼ばれる)とも非常に相性がよく、近年の壮大なGPUではそこそこ高速に処理できる。なお、GPUで処理する方法は後述のメモリ消費量が問題になることが多いので注意すること。一般的にメインメモリと異なりVRAMは仮想メモリをサポートしない。
メモリ消費量
ボリュームレンダリングでは3次元の点の集まりであるボクセルを扱う関係上、非常に多くのメモリを必要とする。
- メモリ消費量
- 512 * 512 * 512 * 2バイト = 256MB
- 1024 * 1024 * 1024 * 2バイト = 2GB
上記は単純にボクセルを保持するために必要な最低限のメモリ容量であり、実際にはここから計算した値を確保しておくためのメモリなども必要になる。このような巨大なデータはメインメモリからVRAMへの転送なども大きな負担となる。
ゲームなどに最適化されたグラフィックボードはVRAM上に一度データを転送したらシーンが変わるまで使い回す前提となっていることが多いため、メインメモリとVRAMの間で大量の転送を行うような用途ではシェーダーが遊んでしまうのである。
このためボリュームレンダリングではシェーダーの性能よりもメモリの容量や速度がボトルネックとなることが多く、安物のオンボードGPUでは厳しかったりする。なお、オンボードGPUでもPlayStation 4のようにGDDR5とhUMAのような技術を組み合わせればボリュームレンダリングも大きく前進する可能性がある。