2009年03月31日

vectexをマルチスレッドレンダリング対応にする(1)

Blenderのテクスチャプラグインをマルチスレッドレンダリングに対応させる方法が大体つかめてきましたので、今回からvectexをマルチスレッドレンダリングに対応させていきたいと思います。

ところで、実際にBlenderを起動してvectexに付属しているサンプルデータをスレッド数4などでレンダリングした場合にどうなるのかを確認してみると、vectexでのマルチスレッドレンダリングの問題はこれまで見てきたプラグインほど簡単ではないことに気づきます。

プラグインリポジトリにあるテクスチャプラグインでは、マルチスレッドでレンダリングした場合にノイズが発生することはあっても、レンダリングそのものは最後まで終了します。一方、vectexでは、マルチスレッドでレンダリングすると、ノイズがどうとかいう以前にレンダリングのプレビュー画面が真っ黒のままでフリーズしてしまいます。
このフリーズするという問題は、これまでのテクスチャプラグインでは見られなかった、全く別の原因で起こっていると考えるべきでしょう。
pic090331_01.jpg

vectexを使ってスレッド数を色々と変えてレンダリングをテストしていると、マルチスレッドでレンダリングしてもフリーズしないこともあるのが分かります。
一度スレッド数1でレンダリングをした後、カメラやレンダリングサイズなどの設定を変更せずにスレッド数を増やした場合、マルチスレッドでのレンダリング中にフリーズしないようです。

なぜ、こんなことが起こるのでしょうか。
vectexは内部的にミップマップという仕組みを使っているようです。ミップマップはオリジナルのマッピング画像より小さい解像度の画像を複数用意しておき、レンダリングの際に描画されるポリゴンの面積に合わせて最適なマッピング画像を使用することでレンダリング品質を高めるというものです。

スレッド数を1にしてレンダリングを行うと、必要な解像度のテクスチャ画像が作成されてキャッシュに保存されます。保存されたテクスチャ画像は、メモリが足りなくなると使用頻度の低いものから削除されていきますが、それまではずっと保存され続けます。
おそらく、vectexで初回のレンダリング時にマルチスレッドレンダリングを行うと、複数のスレッドがそれぞれに解像度別のテクスチャ画像を作成しようとするため、メモリ管理になんらかの問題が起こってレンダリングの途中でフリーズしてしまうようです。

あらかじめスレッド数を1にした状態でキャッシュにテクスチャ画像を用意しておけば、その後はマルチスレッドでレンダリングを行うことができるということであれば、
  1. AO(アンビエントオクルージョン)やレイトレースシャドー、SSSなど、比較的処理が重く、さらにvectexのキャッシュに影響がでないような設定をオフにした状態でスレッド数を1にしてレンダリングを行い、必要なテクスチャ画像を作成しておく。
  2. その後で必要な設定をすべてオンにし、マルチスレッドレンダリングを行う。
というようにすれば、レンダリングの重いデータの場合にレンダリング時間を少しは短縮できそうです。

ただし、現在の状態ではマルチスレッドにしてレンダリングを行うとノイズが出てしまいます。プラグインリポジトリのテクスチャプラグインに行ったのと同じ対処をしておけば、vectexでもノイズは出なくなるはずです。
pic090331_02.jpg

複数スレッドが解像度別のテクスチャを作成しようとしてフリーズが起こるという問題は、Blender本体の方でマルチスレッドでのレンダリングがどのように実装されているのかを調べないと、対応することは無理そうです。

通常、マルチスレッドプログラミングではこのような問題に対応するための様々な手段が用意されています。例えばmutexというものを使うと、一つのスレッドが処理している間、他のスレッドが干渉しないように処理が終わるまで待たせるというようなことができます。
Blenderの本体のソースコードの中でも、Jpegなどのビットマップ画像のテクスチャにミップマップ処理を行っている部分では何らかの対策を行っているはずですので、vectexでもそれを参考にして対応することができると思います。これについては次回以降で行う予定です。


ということで、ここからはマルチスレッドレンダリングでのノイズに対する対応を行っていきます。
vectexはagg、expatという2つの外部のライブラリを使用していますのでコンパイルに必要なソースファイルの数はかなり多いのですが、実際にテクスチャプラグインのためのソースコードとして書かれているのは「vectex.h」「vectex.c」「cectex_agg.cpp」の3つのファイルだけです。

Blenderのテクスチャプラグインで必要になるデータやplugin_tex_doit()などの関数は、vectex.cの中に書かれています。また、「blender」フォルダの中に、Blenderの「plugins」フォルダに入っているplugin.hなどのヘッダファイルが置かれています。今回、変更を行うのはこの2ヶ所となります。
pic090331_04.jpg pic090331_05.jpg

「blender」フォルダの中のplugin.hの39行目を見てみると、
#define B_PLUGIN_VERSION    5
となっていて、プラグインのバージョンは5として作成されていることが分かります。
pic090331_06.jpg

プラグインのバージョンが5となっているので、plugin_instance_init()関数はすでに使用されています。プラグインリポジトリのテクスチャプラグインはほとんどがバージョン3として作成されていたため、バージョン3からバージョン5への修正、バージョン5からバージョン6への修正の2つ分のバージョンアップを行う必要がありました。
vectexは約1年前に作成されていて比較的新しいこともあって、バージョンアップ自体の作業はむしろ他のテクスチャプラグインより簡単で、plugin_tex_doit()関数の引数にresult[]配列を追加するという作業だけでよさそうです。

まず、plugin_tex_doit()関数のプロトタイプ宣言の部分です。これは、vectex.cの111行目にあります。
...
/* Current frame number */
float cfra;

void plugin_init(void);
void plugin_callback(int);
void plugin_instance_init(Cast *);
int  plugin_tex_doit(int, Cast *, float *, float *, float *);
...
...
/* Current frame number */
float cfra;

void plugin_init(void);
void plugin_callback(int);
void plugin_instance_init(Cast *);
int plugin_tex_doit(int, Cast *, float *, float *, float *, float *);
...
次に、関数の本体の方です。こちらは579行目になります。
...
int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, float *dyt)
{
    stype = 0; /* prevent unused variable warning */

    if (! cast->enable)
    {
...
...
int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, float *dyt, float *result)
{
    stype = 0; /* prevent unused variable warning */

    if (! cast->enable)
    {
...
ソースコードの修正はこれだけです。
あとは、vectexのソースコードの「blender」フォルダの中身をまるごとBlender2.48aの「plugins」フォルダのものと入れ替えれば、コンパイルの準備が完了します。

ということで、とりあえずプラグインバージョン5からバージョン6へと更新したvectexができました。この時点での、修正したソースコード(vectex.c)とバイナリファイル(Windows 32bit、Linux 32/64bit)をここにまとめておきます。

vectex_modified090331.zip

(WindowsのバイナリファイルはVisusal C++ 2008 Expressで作成していますが、オリジナルのものとはバージョンの異なるexpatライブラリを使っています。オリジナルは1.95.8ですが、今回は2.0.1のwin32用のものを使っています。コンパイルは正常にできていますが、もしかすると実行時にバージョンの違いによる問題が起こる可能性があります。)

これで、初回のレンダリングでスレッド数1でレンダリングを行っておけば、キャッシュに残っているテクスチャ画像を使って、マルチスレッドレンダリングができるようになりました。
しかし、これではやはり不便なので、次回以降で初回のレンダリング時にフリーズする問題を解決したいと思います。
posted by mato at 22:00| Comment(0) | Blender | このブログの読者になる | 更新情報をチェックする
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。