2009年05月06日

Blenderへの新しいプロシージャルテクスチャの追加

vectexをマルチスレッドレンダリングに対応させる過程で、Blenderのテクスチャプラグインのプログラミングについて学ぶことができました。今後、vectexをさらに改造していく予定ですが、それに合わせてBlenderのソースコードの中身についても、少しずつ勉強していきたいと思っています。

今後進めていく作業内容としては
・vectexをBlender本体に組み込む
・vectexで使用可能なSVGの機能を強化する
の2つを目標としていきたいと考えています。

テクスチャプラグインの形態のままでSVGの機能を強化し、その後Blenderに組み込むか、現状のままBlenderに組み込んでおいて、後からSVG機能を強化するか、どちらがいいのか悩むところです。
vectexのSVG機能を強化する方法については、
・今のままAGGを使用し続ける。
・別のSVGライブラリに乗り換える。
このどちらかの対応が考えられますが、どちらにしてもかなり苦労しそうな予感がします。

現状のままでvectexをBlenderに組み込むことは、使用しているライブラリのAGG、expatなどをうまくBlenderのビルドシステムに対応させられるかという点に若干不安を感じますが、こちらの方が難易度は低そうに思います。
ということで、まずはvectexをBlenderに組み込む作業を行い、その過程でもう少し経験値を高めてから、後でSVG機能を強化するという方向で行こうと思います。

この作業を行うにあたって、とても参考になりそうな情報(Doc/Adding A Procedural Texture)がBlender.orgにありました。

ここで言うプロシージャルテクスチャというのは、Blenderの「Texture」パネルの「Texture Type」で選択して使用する組み込みテクスチャのことです。
このチュートリアルを最後まで完成させるとジュリアフラクタルテクスチャという新しいテクスチャを使えるようになるというものですが、プログラミングの内容はテクスチャプラグイン作成のためのチュートリアルにかなり近いことを行っていると予想できます。

今回はこのチュートリアルを参考にして、以前書いた「テクスチャプラグインを作ってみる」という記事で作成した非常に簡単なテクスチャをBlenderに組み込んでみたいと思います。
pic090505_02.jpg pic090505_03.jpg

以下、プロシージャルテクスチャを追加するための作業を進めていくわけですが、今回は全部で3つのソースファイルを修正することになります。
  1. 変数の定義: DNA_texture_types.h
  2. 描画処理: texture.c
  3. UIの作成: buttons_shading.c
それぞれ、ソースコードの役割が違うため、置かれている場所も全く違っています。
今回使用しているのはBlender2.48aのソースコードです。修正した部分のソースコードはこちら(src090505.zip)になります。

○変数の定義 (/blender/source/blender/makesdna/DNA_texture_types.h)
Tex構造体の中に変数を追加します。(line:130-176)
typedef struct Tex {
    ID id;
   
    float noisesize, turbul;
    float bright, contrast, rfac, gfac, bfac;
    float filtersize;
    ...
    float test_val;
    ...
    float pad;
    ...
    struct ColorBand *coba;
    struct EnvMap *env;
   
    short fradur[4][2];
   
} Tex;
この構造体には、今回作成するテクスチャも含めて、全てのプロシージャルテクスチャが使用する変数がまとめて置かれています。
今回、新たに追加するのは境界線の位置を調整するための数値を保持するfloat型変数一つだけとなります。

    float test_val;
   
この一行だけを追加した状態で一旦ビルドを実行してみると、エラーが出てしまいます。
pic090505_04.jpg

これについては元のチュートリアルできちんと解説されています。
詳しいことはよく分からないのですが、この構造体は8byteのアライメントにしたがう必要があるので他に4byte何かのデータを追加してサイズを合わせるように、ということらしいです。

ということで、

    float pad;

という一行を追加しました。
これでエラーが解消され、コンパイルできるようになります。
pic090505_05.jpg

このファイルには、もう一ヶ所修正が必要な場所があります。
各テクスチャを区別するための番号として定数を割り当てている場所があります。(Line:197-210)
...
#define TEX_VORONOI        12
#define TEX_DISTNOISE    13
#define TEX_TEST        14

/* musgrave stype */
#define TEX_MFRACTAL        0
#define TEX_RIDGEDMF        1
...
最後が13で終わっているので、それに続けて「14」を割り当てます。

○描画処理 (/blender/source/blender/render/intern/source/texture.c)
こちらのソースコードには、色々なテクスチャの関数本体が置かれています。
適当な場所に今回作成するテクスチャのコードを追加します。
static int test_tex(Tex *tex, float *texvec, TexResult *texres)
{
    if (texvec[0] <= tex->test_val) {
            texres->tin = 0;
    } else {
        texres->tin = 1;
    }

    return TEX_INT;
}
この関数は、テクスチャプラグインでのplugin_tex_doit()関数にかなり似ています。

テクスチャプラグインのresult[]配列に相当するのがTexResultという構造体で、この構造体の中に計算結果を入れることでレンダラにデータを渡しています。
テクスチャプラグインのときと同じように、この関数の戻り値は強度、色、ノーマルのうちどの値を使用しているかを指定するために使われています。

ここで行われている計算の中身ですが、先ほどTex構造体の中に作成しておいたtest_valという変数には、後に作成するパネルの数値スライダの値が入ります。
texvec[0]には、レンダラが現在計算している位置のテクスチャ座標のX値が渡されますので、その値が数値スライダの指している位置よりも小さい(左)ならテクスチャのINT(ENSITY)値を0(黒)にし、大きい(右)なら1(白)にします。

最後に、この計算ではテクスチャの強度(INT)のみを使用していますので、関数の戻り値としてTEX_INTを返しています。

このファイルにも、修正箇所がもう一つあります。
Blenderのバージョンアップによってさらに修正箇所が増える可能性もありますので、元のチュートリアルでは「magic」などの既存のテクスチャの名前でファイル内を検索してみるようにと書かれています。

multitex()関数(line:1133-1233)
static int multitex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres)
{
    float tmpvec[3];
    int retval=0; /* return value, int:0, col:1, nor:2, everything:3 */

    texres->talpha= 0;    /* is set when image texture returns alpha (considered premul) */
   
    switch(tex->type) {
   
    case 0:
        texres->tin= 0.0f;
        return 0;
    case TEX_CLOUDS:
        retval= clouds(tex, texvec, texres);
        break;
    case TEX_WOOD:
        retval= wood(tex, texvec, texres);
        break;
    ...
    case TEX_TEST:

        retval = test_tex(tex, texvec, texres);
        break;

    ....
}

この関数の中では、DNA_texture_types.hの中で定義されているTEX_XXXという定数に対応して、テクスチャの描画を行うというような処理が書かれています。
他のテクスチャを参考にして、TEX_TESTの場合にtest_tex()を呼び出すコードを追加しています。

○UI(ユーザーインターフェイス)の作成 (/blender/source/blender/src/buttons_shading.c)
このソースファイルで、パネル上に表示されるボタンなどを設定します。
今回は数値スライダが一つだけの簡単なパネルになります。
static void texture_panel_test_tex(Tex *tex)
{
    uiBlock *block;
   
    block = uiNewBlock(&curarea->uiblocks, "texture_panel_test_tex", UI_EMBOSS, UI_HELV, curarea->win);
    if(uiNewPanel(curarea, block, "Test Tex", "Texture", 640, 0, 318, 204)==0) return;
    uiSetButLock(tex->id.lib!=0,  ERROR_LIBDATA_MESSAGE);

    uiBlockBeginAlign(block);
   
    uiDefButF(block, NUM, B_TEXPRV, "value: ", 10, 90, 150, 19, &tex->test_val, -1.0, 1.0, 10, 0, "Test Value");
   
    uiBlockEndAlign(block);
}

新規に作成したtexture_panel_test_tex()という関数の中でパネルに表示されるボタンなどを作成しています。
1から4行目まではパネルそのものを作成するための記述で、Magicなどの他のテクスチャのソースコードとほとんど共通していますが、パネルに表示される名前等は今回作成しているテストテクスチャ用に修正しています。

5から7行目までがパネルに表示されるボタンのための記述です。
テクスチャプラグインではVarStructという構造体でボタンを作成していましたが、ここではuiDefButF()という関数でボタンの詳細を指定しています。
元のチュートリアルにこの関数の詳しい説明が書かれています。(Blenderのソースコードの「doc」フォルダの中にあるinterface_API.txtから抜粋しているようです)


このファイルには、全部で3ヶ所修正が必要になります。
ここから先は、元のチュートリアルには書かれていませんが、これらの部分を修正しないと「texture」パネルから今回作成した新しいテクスチャを選択することができません。
ここでも「magic」などの既存のテクスチャの名前で検索して、修正が必要な場所を探す方法が有効です。

void texture_panels()関数(line:1576-1702)
static void texture_panel_texture(MTex *actmtex, Material *ma, World *wrld, Lamp *la, bNode *node, Brush *br, SculptData *sd)
{
        ...
        /* newnoise: all texture types as menu, not enough room for more buttons.
         * Can widen panel, but looks ugly when other panels overlap it */
       
        sprintf(textypes, "Texture Type %%t|None %%x%d|Image %%x%d|EnvMap %%x%d|Clouds %%x%d|Marble %%x%d|Stucci %%x%d|Wood %%x%d|Magic %%x%d|Blend %%x%d|Noise %%x%d|Plugin %%x%d|Musgrave %%x%d|Voronoi %%x%d|DistortedNoise %%x%d|TestTex %%x%d", 0, TEX_IMAGE, TEX_ENVMAP, TEX_CLOUDS, TEX_MARBLE, TEX_STUCCI, TEX_WOOD, TEX_MAGIC, TEX_BLEND, TEX_NOISE, TEX_PLUGIN, TEX_MUSGRAVE, TEX_VORONOI, TEX_DISTNOISE, TEX_TEST);
        uiDefBut(block, LABEL, 0, "Texture Type",        160, 150, 140, 20, 0, 0.0, 0.0, 0, 0, "");
        uiDefButS(block, MENU, B_TEXTYPE, textypes,    160, 125, 140, 25, &tex->type, 0,0,0,0, "Select texture type");
        ...
}

この関数の中にある非常に長いsprintf()関数の記述を修正します。
これで、「texture」パネルのポップアップメニューの項目に「TestTex」という新しい項目が追加されます。

texture_panels()関数(line:4508-4616)
void texture_panels()
{
            ...
            case TEX_DISTNOISE:
                texture_panel_distnoise(tex);
                break;
                /* newnoise: voronoi */
            case TEX_VORONOI:
                texture_panel_voronoi(tex);
                break;
            case TEX_TEST:
                texture_panel_test_tex(tex);
                break;

            ...
}
こちらは「texture」パネルで選択された項目に対応するパネルを表示する処理のようです。

以上で必要な修正が完了しました。
新しいファイルを追加したりしていないので、SConsなどのビルドの環境には影響していないはずです。UBUNTU 8.10 amd64の環境では、SConsでビルドすると普通にコンパイルできました。
posted by mato at 00:08| Comment(0) | Blender | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
×

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