2009年03月22日

テクスチャプラグインのマルチスレッドレンダリング

Blenderの公式マニュアルでこちらのページを見ると、テクスチャプラグインはBlender2.46からマルチスレッドレンダリングに対応していることがわかります。そして、以前のバージョンのプラグインをマルチスレッドでレンダリングすると、レンダリング結果にノイズのようなものが発生するので、その場合はシングルスレッドでレンダリングするようにと書かれています。

プラグインリポジトリで公開されているテクスチャプラグインを調べてみると、プラグインの種類によっては目立たないものもありますが、ほとんどのものでノイズのようなものが確認できます。
pic090321_01.jpg pic090321_02.jpg

前回の記事で作成したテスト用のプラグインは、実はマルチスレッドに対応したものになっています。スレッド数を「4」とかにしてもノイズがでたりすることはありません。Blender2.46以降の「plugins」フォルダのサンプルをコンパイルすると、その結果できあがるプラグインはマルチスレッドレンダリングに対応したものになります。
プラグインリポジトリで公開されているファイルの中には、Blenderの「plugins」フォルダに付属しているサンプルと同じ「clouds2」「tiles」もあります。そちらは古いバージョンとしてコンパイルされているので、マルチスレッドでレンダリングするとノイズが出ます。この違いはどこにあるのでしょうか。
pic090321_03.jpg pic090321_05.jpg

プラグインリポジトリにあるソースコード「clouds2.c」「tiles.c」と最新版の「plugins」フォルダの中のソースコードとを比べることで、古いバージョンのテクスチャプラグインをマルチスレッドレンダリングに対応させるための方法がわかりそうです。
このくらいの行数のファイルであれば、両方をテキストエディタで見比べることで違いを確認することもできますが、Linuxのツール「Diff」というものを使うとより確実に調べることができます。「Diff」自体はコマンドラインから使用するものですが、Gnome、KDEなどのデスクトップ上で使えるような派生ツールがいくつも作られていて、Windowsでも同じようなものはたくさんみつかります。Ubuntuの「アプリケーションの追加と削除」を見てみると、以前Vectexのソースを調べるのに使ったMeldの他にTkDiff、Kompareなどがありました。今回は「Meld差分ビュワー」を使って「clouds2.c」の新旧のバージョンの違いを調べてみたいと思います。
pic090321_06.jpg

どちらを比較元にするかで若干表示が変わってくると思いますが、とりあえず普通に古い方をオリジナル(画面左)として、新しいバージョン(画面右)との違いを表示させてみます。
pic090321_07.jpg

まず、冒頭のコメント部分が違っています。とりあえず動作には関係ないので無視していいでしょう。
pic090321_08.jpg

この「Meld」というツールではツールバーの「下へ」「上へ」というボタンを押すと、ファイルの中の内容が違っている部分に画面を移動させることができます。次に見つかったのはPlugin_tex_doit()、plugin_instance_init()の2つの関数のプロトタイプ宣言の部分です。
pic090321_09.jpg

plugin_tex_doit()関数には、新しいバージョンでは引数が一つ追加されています。結果から言いますと、テクスチャプラグインをマルチスレッドに対応させるために変更されたのは、まさにこの部分となります。
前回の記事を見ていただくとわかりますが、この引数はresult[]配列へのポインタになります。複数のスレッドがplugin_tex_doit()関数を呼び出している場合、古いバージョンではresult配列に書き込まれた計算結果を別のスレッドが上書きしてしまうことがあります。本来渡されるべき値が変更されてしまったピクセルは、周辺のピクセルとは全然別の色として表示され、点状、線状のノイズのようになります。
新しいバージョンでは各スレッドにそれぞれ自分用のresult[]配列を引数として与えることで、この問題が解決されています。
プロトタイプ宣言が変更されているので、当然それと対応する関数本体のコードも同じように変更されています。この関数の本体はソースコードの最後の方にあります。
もう一方のplugin_instance_init()関数は古いバージョンにはなかったものが、新しいバージョンで追加されたようです。

次の変更箇所です。
pic090321_10.jpg

まず、plugin_instance_init()関数の本体が追加されています。
そして、plugin_getinfo()関数の中身で最後の方が2ヶ所ほど変更されています。一つ目は、"info->tex_doit="と"(TexDoit) plugin_tex_doit;"の間のスペースが一つ余分だったのが修正されています。これは無視していいような内容ですね。
二つ目はplugin_instande_init()関数が追加されたことに関連して、Blender本体からこの関数にアクセスするための情報がここに追加されているようです。

次に、plugin_tex_doit()関数の本体の部分です。
pic090321_11.jpg pic090321_12.jpg

関数の前の部分のコメントが削除されていますが、これは無視していいでしょう。
そして、先ほどのプロトタイプ宣言の変更に対応して、関数名に続く引数の記述部分に「float *result」が追加されています。
元々、result[]配列はグローバルなデータとして同じ名前でplugin_tex_doit()関数の中で使われていたものです。そのため、result[]配列に関しては、この関数内部のコードはまったく変更されていません。

最後の変更部分です。
pic090321_13.jpg

これは関数の戻り値を「0」「1」「2」というような数値ではなく、「TEX_INT」「TES_RGB」「TES_NOR」というマクロを使った定数の表記に変えているようです。「plugins」フォルダの「include」にあるplugin.hの86行目あたりを見てみると、以下のように記述があります。

/* return values (bitfield like) for textures (DNA_texture_types.h) */
#define TEX_INT         0
#define TEX_RGB         1
#define TEX_NOR         2

前回のサンプルプラグインでは直接「0」を返してしまいましたが、本来はこのように「TEX_INT」という定数を使うべきだったようです。(とりあえず、そのままでも動作には問題なさそうなので放置しておきます。まずいかな...。)

ということで、ざっと新旧のバージョンの変更内容を見てきました。
plugin_tex_doit()関数の引数にresult[]配列を渡すようにすること、plugin_instance_init()関数が新しく追加されたこと、基本的にはこの2点が変わっただけで、プラグインの動作に直接関わる部分には変更はないようです。これらの部分を修正してコンパイルし直せば、プラグインリポジトリにあるたくさんのプラグインもマルチスレッドでレンダリングできるようになりそうな感じがします。
次回は、プラグインリポジトリのテクスチャプラグインのソースコードを修正して、実際に動作するか試してみるつもりです。
posted by mato at 00:14| Comment(0) | Blender | このブログの読者になる | 更新情報をチェックする

2009年03月18日

テクスチャプラグインを作ってみる

今回はこちらのページを参考にして、テクスチャプラグインを作ってみたいと思います。

一応、Blenderの公式ユーザーマニュアルの中のページなのですが、一番上の部分を見ると「Blender Version 2.31」となっていて、内容がBlenderの最新バージョンに対応していないようです。このページ以外にBlenderプラグインリポジトリなどにもBlenderのテクスチャプラグインのサンプルコードが掲載されていますが、いずれも現在のBlenderに付属するプラグイン作成用のヘッダファイルとバージョンが違っていて、そのままではコンパイルしてもきちんと動作しないようです。

そのため、今回はBlender2.48aの「plugins」フォルダに入っているサンプルファイル「clouds2.c」のソースファイルを元にして、オリジナルのプラグインを作るにはどこを修正すればいいのか、という形で話を進めたいと思います。ただし、上記の参考ページの解説内容については、ほとんどの部分が現在も有効です。今回は最低限の内容に話を絞っていますので、もしこの内容に興味を持たれた場合は、そちらのページの方をご参照ください。
pic090318_01.jpg

まず、「clouds2.c」を複製して「test.c」と名前を変更してください。そして、以下の手順でこのファイルの内容を作り替えていきます。
一応、サンプルデータsample_data090318.zipにソースファイルとWindows(32bit)、Linux(32/64bit)のバイナリファイルを用意してあります。私は現在のところ、Windows64bit、Mac OSなどのバイナリファイルを作ることができません(将来的にもできなさそうです)。ご了承ください。

○コメント
サンプルファイルには冒頭にライセンスについての記述があります。
本来は、きちんとライセンスの内容を確認した上でコードの管理者などを明記する必要があると思いますが、今回はとりあえず冒頭のファイル名の部分を変更してあります。
/**
 * $Id: test.c $
 *

○インクルードファイル
#include "plugin.h"

テクスチャプラグインを作成するには、必ずこの「plugin.h」をインクルードする必要があります。サンプルファイルではこの他に「math.h」をインクルードしていますが、今回は使用しませんので削除してあります。

○プラグイン名の設定
char name[24]= "Test";

とりあえずダブルクォートで囲まれた部分(" ")を変更しています。
参考のページでは、「Texture Buttons Windowでtexture's titleとして表示される」と書かれていますが、現在のバージョンではプラグインファイルのパスが表示されていて、ここで設定した名前は表示されていないようです。

○サブタイプの設定
#define NR_TYPES    1
char stnames[NR_TYPES][16]= {"Default"};

サブタイプというのは、プラグインの使われ方を切り替えるスイッチのようなものです。今回は簡単にするために一つだけに修正しています。「cluds2.c」では、「強度」「カラー」「バンプ」の3種類の使い方ができるようになっていて、「NR_TYPES」が「3」に、「stnames」が「{"Intens","Col","Bump"}」となっています。
pic090318_02.jpg pic090318_03.jpg

○VarStruct構造体 ボタンの設定
VarStruct varstr[]= {
{    NUM|FLO,    "value",    0.0,    -1.0,    1.0,    "test value"},
};

「plugin」パネルに表示するボタン類をここで定義します。ここでは「value」という数値を変更できる数値ボタンを、デフォルト値「0.0」、最小値「-1.0」、最大値「1.0」として設定しています。
VarStructという構造体には「type」「name」「def」「min」「max」「tip」を指定します。
  1. type ここで数値設定用のボタン(数値ボタン、数値スライダ、トグルボタン)、テキストラベルなどのタイプを指定します。数値ボタンの場合数値のフォーマット(INT,FLO)とボタンタイプ(NUM,NUMSLI,TOG)を「|(OR)」で組み合わせて指定します。
  2. name ボタンに表示される名前です。15文字までです。
  3. 数値の範囲 デフォルト、最小、最大の値を指定します。トグルボタンでは「min」が押された状態、「max」が押されていない状態に対応します。
  4. tip ボタン上にマウスポインタを置いたときに表示されるテキストです。80文字までです。

pic090318_04.jpg pic090318_05.jpg

○Cast構造体 ボタンで設定する変数の本体
typedef struct Cast {
    float val;
} Cast;

VarStructでは、ボタンの表示に関する設定だけを行っていて、実際に描画のための処理を行う関数(plugin_tex_doit)で使用するための変数については何も書かれていません。Cast構造体には、VarStructで指定した順番通りに、それぞれのボタンに対応する変数を記述します。今回はボタンが一つだけなので、それに合わせてfloat型の「val」という名前の変数を一つだけ記述してあります。

○変更の必要ない部分
以下、実際のソースコードではplugin_tex_doit()関数まで、基本的には内容を変更する必要のないコードが書かれています。変更していないのでブログの記事上では内容を省略しますが、コンパイルするために必要なコードが書かれていますので、実際のソースコードでは省略しないでください。

○プラグインの描画処理
int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, float *dyt, float *result)
{
    if (texvec[0] <= cast->val) {
        result[0] = 0;
    } else {
        result[0] = 1;
    }
   
    return 0;
}

この部分がレンダリングの際に、各ピクセルに対して毎回Blenderから呼ばれるプラグインの本体となる部分です。参考のページのもの、pluginsフォルダのサンプル、どちらもそれなりに複雑な計算をする処理が書かれているので、ちょっと見ただけでは内容がわかりにくいように思いました。そこで、このサンプルでは思いっきり簡単にしてみました。

plugin_tex_doit()関数に渡される引数

  1. stype どのサブタイプが有効になっているかが渡されます。今回はサブタイプが一つなので関係ありませんが、 2つ以上設定している場合はこの値に応じて(強度、カラー、バンプなど)処理を分けることになります。
  2. *cast ボタンに応じた変数を格納したCast構造体のポインタです。
  3. *texvec レンダリングされているピクセルで使用されているテクスチャ座標を「float」型の3つの数値で渡しています。texvec[0]がX座標、texvec[1]がY座標、texvec[2]がZ座標となります。
  4.  *dxt,*dyt OSAがオンで、アンチエイリアスが正しく計算されているとき(それ以外はNULLとなりますので確認が必要です)3つのfloat値の配列のポインタが渡されます。アンチエイリアスの計算で使用されるようなのですが、正直なところ私にはまだよく理解できていません。
  5. *result この配列を使って計算結果をBlenderに返します。つまり、このresult[]をなんらかの値に設定することが、この plugin_tex_doit()関数の目的になります。result配列は、float型のresult[0]からresult[7]までの8つの値が渡されます。その中に入れる内容はあらかじめ決まっていて、result[0]は強度、result[1]からresult[4]まではRGBA値、 result[5]からresult[7]までがnormalのXYZ値となります。result[0]の強度は必ず返す必要があります。それ以外はオプションとなります。RGBA、normalの値を返す場合は、plugin_tex_doit()関数の戻り値でそれぞれ「1(RGB)」「2(Normal)」「3(全て)」を返すように設定する必要があります。強度のみの場合は「0」です。
プラグインの描画処理の内容についてです。
このプラグインでは「plugin」パネルで数値ボタン「value」の値を変えることができ、テクスチャ座標のX座標がそれより小さければテクスチャ強度「0」、大きければテクスチャ強度「1」になります。

テクスチャプラグインの描画処理は、基本的に「texvec」からテクスチャ座標(X,Y,Z)を取り出して、その場所でのテクスチャの強度を計算し、結果を「result[0]」に格納する、という感じになります。このサンプルでは「texvec[0]」でテクスチャ座標のX座標についてだけ調べています。

プラグインのパネルに設定したボタンからは、Cast構造体の変数を通して値を受け取ることができます。このサンプルでは「cast->val」の部分で、プラグインパネルの数値ボタンの現在の設定値を調べています。

if文の条件式の部分は、(texvec[0] <= cast->val)となっています。「val」変数にはデフォルト値で「0.0」を指定してあり、テクスチャ座標は、「-1.0」から「1.0」の範囲の値が渡されるようです。
例として、あるピクセルが描画される際、plugin_tex_doit()関数に渡されるテクスチャ座標Xの値が「-0.5」であったとします。このとき「val」の値がデフォルトのままであればif文の条件判定は「-0.5 <= 0.0」でTRUEとなりますから、result[0] = 0がレンダラに渡されます。結果として、そのピクセルはテクスチャ強度「0」となり、テクスチャプレビュー表示では黒になります。
実際にこのプラグインをロードした状態(「Val」が0.0になっている)でテクスチャの「Preview」パネルを見ると、左半分が黒で右半分が白になっています。
pic090318_06.jpg

プラグインパネルの「Value」の値を変更すると、それに応じてプレビューの表示の白い部分と黒い部分の境目が左右に動くのが確認できると思います。
pic090318_08.jpg pic090318_09.jpg

最後の部分で、plugin_tex_doit()関数の戻り値は、result[0]以外を使用していないので「return 0;」としています。
はっきりいって、実用性ゼロのプラグインができてしまいましたが、他のサンプルと比べてかなり内容が分かりやすくなったと思いますが...どうでしょうか。

このブログ、ソースコードのインデントが表示できないことに、今頃気づきました。プログラミングの記事を書くのには向いてなかったようです...。
※追記
スタイルシートとかを変えれば表示できそうなので、少し調べてみたいと思います。 ->スタイルシートは変更できなかったのですが、記事の本文を書く際に「リッチテキストエディタを使用する」というのを選択したら、とりあえずインデントが反映されるようになりました。
posted by mato at 22:50| Comment(0) | Blender | このブログの読者になる | 更新情報をチェックする

2009年03月15日

テクスチャプラグインをWindowsでコンパイルする

前回は付属のサンプルコードをコンパイルするだけで終わってしまったので、今回はオリジナルのプラグインを作ってみよう...と思ったのですが、前回できなかったWindowsでのコンパイルがようやくできるようになったので、その方法を書いておこうと思います。

まず、今回参考にしたインターネットのページです。
BlenderArtists.orgのフォーラムで検索してこちらのスレッドにたどり着きました。
そして、その中で紹介されていたのが、こちらのサイトです。

以下に、簡単に手順を説明します。基本的に上のサイトの手順そのままです。
ちなみに使用するコンパイラはMicrosoftのVisual C++ 2008 Express Editionのものです。

1.コマンドプロンプトを立ち上げます。Windowsのスタートメニューの「アクセサリ」とかにあります。
pic090314_01.jpg

2.Visual C++の機能をコマンドプロンプトから使えるようにします。具体的には、Visual C++に付属する「vcvars32.bat」というバッチファイルを実行します。

"\Program Files\Microsoft Visual Studio 9.0\VC\bin\vcvars32.bat"

インストールの仕方によってファイルの場所は、違っていたりするかもしれません。
pic090314_03.jpg pic090314_04.jpg

3.「cd」コマンドで、Blenderのインストールフォルダにある「Plugins」ディレクトリに移動します。
あらかじめ「Plugins」フォルダだけを、どこかわかりやすい場所にコピーしておいた方がいいかもしれません。

cd \blender\plugins

今回は「C:\」直下に「blender」というフォルダを作って、そこに「Plugins」フォルダをコピーしてあります。
pic090314_05.jpg pic090314_06.jpg

4.コンパイルに必要な「lib」ファイルを作成します。
詳しいことは上記のサイトで説明されていますが、プラグインのソースファイルでBlenderの用意している関数を使うために必要なようです。サンプルの「tiles.c」と「clouds2.c」では、「plugins」-「include」フォルダの「plugin.h」に記述されているhnoise()関数が使われています。
そのためのコマンドは以下のようなものになります。

link /lib /nologo /MACHINE:X86 /DEF:include\plugin.def /NAME:blender.exe

これで、「plugin.lib」「plugin.exp」という2つのファイルが作成されます。
pic090314_07.jpg pic090314_08.jpg

5.プラグインをコンパイルします。

cl /nologo -Iinclude /LD texture/tiles.c plugin.lib /link /EXPORT:plugin_getinfo /EXPORT:plugin_tex_getversion

2行に分かれて表示されていますが、実際には1行にまとめて入力します。
上の例では、「texture」フォルダに入っている「tiles.c」を指定しました。
このコマンドを実行すると、コマンドプロンプトにずらっとメッセージが表示され、「tiles.obj」「tiles.dll」「tiles.lib」「tiles.exp」の4つのファイルが作成されます。このうち、「tiles.dll」がプラグイン本体となります。
pic090314_09.jpg pic090314_10.jpg

pic090314_11.jpg

Blenderの「plugin」パネルの「Load Plugins」ボタンで、今作ったプラグインファイルを開いてみます。
pic090314_12.jpg pic090314_13.jpg

無事、プラグインとして使用できました。


実は、今回参考にさせていただいた上記のサイト以外に、LCC、MinGWを使ってWindowsでテクスチャプラグインをコンパイルする方法が書かれているサイトがあって、最初はそちらを参考にしてコンパイルを試していたのですが、私の環境ではなぜかうまくいきませんでした。
そちらでは、今回の「4.」の「lib」ファイルを作成する部分に相当する手順が省かれているようですので、そのあたりを工夫すればLCCやMinGWでもコンパイルできるのかもしれません。
posted by mato at 00:21| Comment(0) | Blender | このブログの読者になる | 更新情報をチェックする
×

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