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 | このブログの読者になる | 更新情報をチェックする

2009年03月28日

テクスチャプラグインのLCCでのコンパイル

前回、プラグインリポジトリのソースファイルを修正して、マルチスレッドレンダリングに対応するようにしてみました。
Ubuntu 8.10 64bit上ではすべてそのままコンパイルできていますが、Windows Vista 32bit上と、Ubuntu 8.10 32bitではいくつかのプラグインで問題が起こりました。今回はこれらの問題のあったプラグインをどのようにコンパイルしたかについて見ていこうと思います。

○Windows Vista 32bitでの問題
まず、Windowsの方です。ほとんどのプラグインは少し前の記事で書いたVisual C++ 2008 Express Editionでの手順で問題なくコンパイルできるのですが、circdots_rgb、fixnoiseという2つのプラグインではコンパイルエラーが起こります。
pic090327_01.jpg

circdots_rgb.c
   ライブラリ circdots_rgb.lib とオブジェクト circdots_rgb.exp を作成中
circdots_rgb.obj : error LNK2019: 未解決の外部シンボル _roundf が関数 _punkt_abstand で参照されました。
circdots_rgb.dll : fatal error LNK1120: 外部参照 1 が未解決です。

fixnoise.c
   ライブラリ fixnoise.lib とオブジェクト fixnoise.exp を作成中
fixnoise.obj : error LNK2019: 未解決の外部シンボル _srandom が関数 _plugin_initで参照されました。
fixnoise.dll : fatal error LNK1120: 外部参照 1 が未解決です。

エラーの内容はこんな感じです。それぞれソースコードの中で使われている「roundf()」「srandom()」という関数が問題になっているようです。これらのソースファイルは、roundf()またはsrand()が「math.h」の中で定義されていることが前提で書かれていますが、Visual C++ 2008でインクルードされるmath.hにはこれらの関数が見当たりません。

このような場合、他にも対応する方法があると思いますが、私は別のコンパイラでコンパイルすることで、とりあえずこの問題を回避しました。もともと、Blender.orgのプラグインの解説ページでは、LCCというコンパイラを使うようにすすめています。

このLCCというコンパイラを使ってテクスチャプラグインのコンパイルを行う場合、Blenderが用意しているhnoise()などの関数を使っていると、プラグインがうまく動作しません。(追記:以下の手順でコンパイルする場合、についての話です。リンクの仕方とかを工夫することでなんとかできるのかもしれません。)
また、古いBlenderに付属する「plugins」フォルダにあるインクルードファイルであればそのままでコンパイルできるのですが、最新版の「plugins」フォルダのものを使うとコンパイル時にエラーが出ます。

ちなみに、LCCコンパイラを使うためには、インストールを行った後でLCCの実行ファイルのある場所「C:\lcc\bin」をOSの環境変数「path」に追加する必要があります。
また、プラグインのDLLファイルがエクスポートするシンボル定義ファイル「tex.def」というファイルを用意する必要があります。こちらは上記のプラグインの解説ページにも書かれていますが、
EXPORTS
LibMain@12
plugin_but_changed
plugin_getinfo
plugin_init
plugin_tex_doit
plugin_tex_getversion
これだけの内容の普通のテキストファイルとなります。

ここから先は、以下のような状況を想定して話を進めていきます。
  1. Blender2.48aの「plugins」フォルダを「C:\blender」というフォルダにコピーします。
  2. 前回用意した修正済みの「circdots_rgb.c」「fixnoise.c」をその中の「texture」フォルダに入れます。
  3. 上記のtex.defファイルを「include」フォルダに置きます。
pic090327_06.jpg pic090327_04.jpg

この状態で、LCCを使用してプラグインをコンパイルするには、コマンドプロンプトから以下のようにコマンドを実行します。

cd \blender\plugins\texture
lcc -Ic:\blender\plugins\include circdots_rgb.c
lcclnk -dll -nounderscores circdots_rgb.obj c:\blender\plugins\include\tex.def

そうすると、いくつかのエラーが表示されます。
Specified export _callocN is not defined
Specified export _callocT is not defined
Specified export _freeN is not defined
Specified export _freeT is not defined
Specified export _mallocN is not defined
Specified export _mallocT is not defined
Specified export _plugin_seq_getversion is not defined

pic090327_05.jpg

この状態でも「circdots_rgb.dll」が作成されますが、Blenderにロードしようとするとエラーが出ます。
pic090327_07.jpg pic090327_08.jpg

同じことを古いバージョンのBlenderの「plugins」フォルダで行えば、エラーが出ずにDLLファイルができます。Blenderにも当然のように正常にロードできます。
pic090327_09.jpg pic090327_10.jpg

ここで、ちょっとBlenderのプラグインのバージョンについての補足です。「plugins」-「include」フォルダの中の「plugin.h」の39行目を見ると、
#define B_PLUGIN_VERSION    6
と書かれています。
pic090327_13.jpg

この部分の数字がプラグインをコンパイルするときにバイナリファイルの「.so」「.dll」ファイルの中に保持されることで、Blenderはプラグインのバージョンを識別しているようです。
Blenderの過去のバージョンのplugin.hを調べてみると、プラグインのバージョンとBlenderのバージョンとの対応は、以下のようになります。

ver.3    2.40 - 2.42
ver.5    2.43 - 2.45
ver.6    2.46 - 2.48

エラーが出るようになったのは「ver.6」以降からのようで、Blender 2.46以降では「plugins」-「include」フォルダの中のヘッダファイルに、どこか問題がありそうな感じです。
エラーの内容を見ると、callcN()、freeN()など、プラグインから利用できるようにBlenderが用意している関数名が並んでいますが、hnoise()、turbulence()などの関数の名前はありません。「include」フォルダの中で、これらのエラーの出ている関数名が記述されているのは「util.h」、一方のhnoise()、turbulence()については「plugin.h」です。

plugin.hの中の記述は、こうなっています。
ver.5
LIBEXPORT float hnoise(float noisesize, float x, float y, float z);
LIBEXPORT float hnoisep(float noisesize, float x, float y, float z);
LIBEXPORT float turbulence(float noisesize, float x, float y, float z, int depth);
LIBEXPORT float turbulence1(float noisesize, float x, float y, float z, int depth);
ver.6
LIBIMPORT float hnoise(float noisesize, float x, float y, float z);
LIBIMPORT float hnoisep(float noisesize, float x, float y, float z);
LIBIMPORT float turbulence(float noisesize, float x, float y, float z, int depth);
LIBIMPORT float turbulence1(float noisesize, float x, float y, float z, int depth);
util.hの方は、こうなっています。
ver.5
LIBEXPORT          void *mallocN(int len, char *str);
LIBEXPORT          void *callocN(int len, char *str);
LIBEXPORT          short freeN(void *vmemh);  
LIBEXPORT          void *mallocT(int len, char *str);
LIBEXPORT          void *callocT(int len, char *str);
LIBEXPORT          void freeT(void *vmemh);  
ver.6
LIBEXPORT          void *mallocN(int len, char *str);
LIBEXPORT          void *callocN(int len, char *str);
LIBEXPORT          short freeN(void *vmemh);  
LIBEXPORT          void *mallocT(int len, char *str);
LIBEXPORT          void *callocT(int len, char *str);
LIBEXPORT          void freeT(void *vmemh);  
コメント、スペースなどを省略した上、行頭のマクロの部分を色分けして強調してみました。
LIBEXPORT、LIBIMPORTというのは「externdef.h」で定義されているマクロで、プラグインのver.5とver.6とで内容は以下のように変わっています。
ver.5
#ifdef WIN32
 #ifdef PLUGIN_INTERN
  #define LIBEXPORT    __declspec(dllexport)
 #else
  #define LIBEXPORT    extern __declspec(dllimport)
 #endif
#elif !defined(WIN32)
    #define LIBEXPORT extern
#endif
ver.6
#ifdef WIN32
 #ifdef PLUGIN_INTERN
  #define LIBEXPORT    __declspec(dllexport)
  #define LIBIMPORT    __declspec(dllexport)

 #else
  #define LIBEXPORT    __declspec(dllexport)
  #define LIBIMPORT    extern __declspec(dllimport)
 #endif
#elif !defined(WIN32)
    #define LIBEXPORT extern
    #define LIBIMPORT extern

#endif
ifdef文では、まずWindowsとそれ以外で処理内容を分けていて、さらに「PLUGIN_INTERN」という定数で処理内容を分けています。
「plugins」-「include」にあるヘッダファイルは、プラグインの作成時に使用していますが、Blender本体の方でプラグインを処理する部分でも同じ内容のものが使われています。
「PLUGIN_INTERN」はそのどちらかを区別するのに使われていますが、プラグイン作成時には「else」以下の方が有効となるようです。

これを見ると、ver.5ではLIBEXPORTのみだったものがLIBIMPORT、LIBEXPORTの2種類に分けて処理されるようになったようです。そして、マクロがどのように展開されるのかを見ると、

Blenderが公開している関数をプラグインが使うための記述:LIBIMPORT
プラグインが公開している関数をBlenderが使うための記述:LIBEXPORT

ということだと思います。
以上のことから、「util.h」のLIBEXPORTをLIBIMPORTに修正してみます。
util.h line:94-101
LIBIMPORT          void *mallocN(int len, char *str);
LIBIMPORT          void *callocN(int len, char *str);
LIBIMPORT          short freeN(void *vmemh);  

LIBIMPORT          void *mallocT(int len, char *str);
LIBIMPORT          void *callocT(int len, char *str);
LIBIMPORT          void freeT(void *vmemh);  

コンパイル時に表示されたエラーの最後には、plugin_seq_getversion()関数についてのエラーも表示されていました。この関数については、plugin.hの70行目あたりに記述があります。
ver.5
int plugin_tex_getversion(void);
int plugin_seq_getversion(void);
void plugin_getinfo(PluginInfo *);
ver.6
LIBEXPORT int plugin_tex_getversion(void);
LIBEXPORT int plugin_seq_getversion(void);
LIBEXPORT void plugin_getinfo(PluginInfo *);
ここで、plugin_tex_get_version()、plugin_getinfo()は実際にプラグインで使用されていますが、使われていないplugin_seq_getversion()にまでLIBEXPORTを加えているのがエラーの原因のようです。

ということで、この部分はこんな感じに修正してみます。
plugin.h line:70-72
LIBEXPORT int plugin_tex_getversion(void);
int plugin_seq_getversion(void);
LIBEXPORT void plugin_getinfo(PluginInfo *);
これでエラーが出ずに、コンパイルが完了しました。
Blenderにロードすることもできて、スレッド数:4でレンダリングしてもノイズが出ていないようです。
pic090327_11.jpg pic090327_12.jpg


○Ubuntu 8.10 32bitでの問題

Ubuntu 8.10 32bitで問題があったプラグインですが、こちらはsarah0というプラグインです。普通にコンパイルできたのですが、Blenderにロードすることができませんでした。マルチスレッドレンダリング対応に修正していないものでも同じようにBlenderにロードできない「.so」ファイルができてしまいます。
ldコマンドで調べてみると、
mato@ubuntu:~/programing/pr_245/texture$ ld sarah0.so
ld: warning: cannot find entry symbol _start; not setting start address
sarah0.so: undefined reference to `__stack_chk_fail_local'
sarah0.so: undefined reference to `sqrt'
sarah0.so: undefined reference to `__fprintf_chk'
sarah0.so: undefined reference to `fflush'
sarah0.so: undefined reference to `turbulence'
sarah0.so: undefined reference to `__strncat_chk'
sarah0.so: undefined reference to `turbulence1'
sarah0.so: undefined reference to `hnoise'
sarah0.so: undefined reference to `fopen'
sarah0.so: undefined reference to `fclose'
sarah0.so: undefined reference to `fputc'
sarah0.so: undefined reference to `fwrite'
sarah0.so: undefined reference to `floorf'
sarah0.so: undefined reference to `hnoisep'

というように表示されました。
プラグインリポジトリからダウンロードしたバイナリファイルでは、
mato@ubuntu:~/Download/blender/plugin$ ld sarah0.Linux.so
ld: warning: cannot find entry symbol _start; not setting start address
sarah0.Linux.so: undefined reference to `sqrt'
sarah0.Linux.so: undefined reference to `floor'
sarah0.Linux.so: undefined reference to `fflush'
sarah0.Linux.so: undefined reference to `turbulence'
sarah0.Linux.so: undefined reference to `turbulence1'
sarah0.Linux.so: undefined reference to `fprintf'
sarah0.Linux.so: undefined reference to `hnoise'
sarah0.Linux.so: undefined reference to `strncat'
sarah0.Linux.so: undefined reference to `fopen'
sarah0.Linux.so: undefined reference to `memset'
sarah0.Linux.so: undefined reference to `fclose'
sarah0.Linux.so: undefined reference to `fputc'
sarah0.Linux.so: undefined reference to `fwrite'
sarah0.Linux.so: undefined reference to `hnoisep'

このように表示されます。
fprintf()、strncat()などの関数で問題が起こっているようですが、そもそもテクスチャプラグインではテキスト処理の関数は必要なさそうです。sarah0プラグインではsarah0.c以外に、2つのヘッダファイルsarahplugins.h、sarahutil.hが使われています。このうち、sarahutil.hの中にプラグインの動作をデバッグするための関数debug_log_inputs()があり、fprintf()、strncat()はそこでだけ使われているようです。
デバッグ用の関数はとりあえずなくてもOKということで、debug_log_inputs()関数をまるごとコメントアウトした状態でコンパイルすると、正常に動作するようになりました。
posted by mato at 00:37| Comment(0) | Blender | このブログの読者になる | 更新情報をチェックする

2009年03月25日

プラグインリポジトリのテクスチャプラグインをマルチスレッド対応に

前回でテクスチャプラグインをマルチスレッドレンダリングに対応させるために必要なことが大体分かりましたので、プラグインリポジトリにあるテクスチャプラグインをマルチスレッドに対応できるかを試してみました。結果を先に言うと、ほとんどのものが前回の記事で書いた修正内容だけでマルチスレッドレンダリングできるようになりました。

プラグインリポジトリにあるプラグインの多くは GPL、Public Domainなどの再配布、改変を許可するライセンスで公開されていますが、一部そうなっていないものもあります。ライセンス上問題ないものについて、修正済みのソースコード、コンパイル済みのバイナリファイル(Windows 32bit、Linux 32/64bit)をまとめてみました。

texture_plugins_modified.zip

この中に含まれるのは、brick、brick1、circdots_rgb、dots2、led、pattern、pie、r_weave、refract、rings2、rtilings、sarah0、scales、sinus、spirals、t_bricks、t_clouds、t_marble、t_marble_terrain、t_terrain、t_wood、trellis、water、wbricks の24のテクスチャプラグインになります。
各プラグインのソースファイルが入っているフォルダに、「changes.txt」という名前のファイルを入れてあります。これは、オリジナルのソースコードと今回修正したソースコードの内容の違いを記述した差分ファイルで、前回使ったMeldというツールで作成しています。このファイルを見ていただくと、どこをどう修正したのかが一目でわかると思います。
pic090324_01.jpg pic090324_02.jpg

ほとんどのものは、
  1. plugin_tex_doit()関数の引数にresult[]配列へのポインタを追加し、プロトタイプ宣言もそれに合わせて変更
  2. plugin_instance_init()関数とそのプロトタイプ宣言を追加し、plugin_getinfo()関数の中に関連するコードを追加
という修正内容だけで済んでいますが、一部にはそれだけではうまくいかないものがありました。ここから先は、それら問題の起こったプラグインにどのような修正をしているかを見ていきたいと思います。

実際に問題が起こったプラグインは、dots2、led、trellis、ceramictilesの4つですが、このうちceramictilesはライセンスの関係で今回は外してあります。ちなみに修正後に起こった問題の具体的な内容ですが、dots2、ledの2つのプラグインでは修正後にプレビュー画面が真っ黒になり、プラグインが正常に動作しなくなりました。trellis、 ceramictilesの2つのプラグインのでは、上記の修正を行った後もノイズがなくならないという感じになります。もしかすると、私が気づいていないだけで、これ以外にもまだノイズが発生するものがあるかもしれません。

まず、問題が起こったプラグインのうちのdots2、ledについてです。
このdots2のソースファイル「dots2.c」を見ると、plugin_tex_doit()関数の中から別の関数calc_dot_value()を呼び出して、計算処理をそちらで行っています。
void calc_dot_value(Cast *cast,float x,float y)
{
  ....
}

int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, float *dyt)
{
  ...
  calc_dot_value(cast,x,y);
  ...
}

プラグインリポジトリにあるプラグインでは、plugin_tex_doit()関数から別の関数を呼び出すということはごく普通に行われています。問題が起こったプラグインではすべてこのような構造になっていて、さらにdots2、ledの2つのプラグインでは、この呼ばれている関数の中でresult[]配列が使われているという点が共通しています。ただし、ledの方では関数内に直接result[]配列の記述があるのではなく、呼ばれている関数内で使われているマクロの中にresult[]配列の記述があります。
pic090324_03.jpg pic090324_04.jpg

plugin_tex_doit()関数の引数にresult[]配列へのポインタを追加する修正をした場合、そのままだとplugin_tex_doit()関数内のresult[]配列と、呼び出されている関数内のresult[]配列は名前は同じでもまったく別のものとなっています。
このため、本来の計算処理が行われずにプレビュー画面が真っ黒になってしまいます。

void calc_dot_value(Cast *cast,float x,float y)
{
  ....
 result[0]=0.;
  ....
}

int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, float *dyt, float *result)
{
  ...
  calc_dot_value(cast,x,y);
  ...
}
plugin_tex_doit()関数以外の関数についても、result[]配列を使用している関数すべてにresult[]配列へのポインタを引数で渡すようにすればこの問題は解決します。
void calc_dot_value(Cast *cast,float x,float y, float *result)
{
  ....
 result[0]=0.;
  ....
}

int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, float *dyt, float *result)
{
  ...
  calc_dot_value(cast,x,y, result);
  ...
}

次にtrellis、ceramictilesについてです。
この2つのプラグインで問題になるのはグローバル変数を使っていることです。 trellisのソースコード「trellis.c」を見てみると、126行目あたりに次のような記述があります。
/* We use globals to avoid passing lots of float args around every call */
float x, y, z;            /* Normalised coordinates */
float t;            /* thickness */
float t2;            /* 1/2 thickness */
int multi;            /* Use multi-colours? */
これらのグローバル変数は、plugin_tex_doit()関数から呼ばれるcalc_trellis()とcalc_cube()という2つの関数の中で何度も使われています。これらの変数は、result[]配列のようにBlenderに渡される強度、色などのデータそのものを保持するわけではありませんが、複数のスレッドがこれらのデータを上書きし合う状況では計算結果が本来のものと全く違ったものになってしまい、結果としてノイズのようなものが起こることになります。
int plugin_tex_doit(int stype, Cast * cast, float *texvec, float *dxt, float *dyt) {
    ...
        result[0] = calc_trellis(cast->pattern);
    ...
        result[0] = calc_cube((float) rand() / (float) RAND_MAX);
    ...
}
今回は、これらのグローバル変数をplugin_tex_doit()関数内のローカル変数に修正し、calc_trellis()とcalc_cube()の両関数の引数としてこれらの全ての値を渡すようにしてみました。
int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, float *dyt, float *result)
 {
    float x, y, z;            /* Normalised coordinates */
    float t;            /* thickness */
    float t2;            /* 1/2 thickness */
    int multi;            /* Use multi-colours? */


    ...
        result[0] = calc_trellis(cast->pattern, x, y, z, t, t2, multi);
    ...
       
        result[0] = calc_cube((float) rand() / (float) RAND_MAX, x, y, z, t, t2, multi);
    ...
}
私がソースコードに対して行った修正は、以上のような感じです。
ところが、実はソースコード自体に問題がなくても、コンパイル時に問題が起こったものがいくつかあります。そのため、今回修正したソースファイルを使ってコンパイルを行う場合、いくつかのプラグインでコンパイルに失敗する可能性があります。
次回は、それらのコンパイル時の問題への対応方法について書くつもりです。
posted by mato at 02:09| Comment(0) | Blender | このブログの読者になる | 更新情報をチェックする
×

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