2009年09月18日

OSAへの対応

OSAはレンダリング時のアンチエイリアスを行う機能です。
OSAの設定はRenderパネルの「Render」ボタンのすぐ下の「OSA」ボタンと「5」「8」「11」「16」という数字のボタンで行います。
pic090918_01.jpg

これまでvectexでは独自の計算でアンチエイリアスの処理を行っていて、Blenderが元々用意しているOSAの計算処理を使用していませんでした。
今回は、vectexのアンチエイリアス処理にBlenderのOSAの機能を使用するように改良しました。

これに合わせて、前回の修正でvectexパネルを表示させたときに同時に表示されるようにしたMap Imageパネルの表示内容を修正し、イメージテクスチャを使用したときと完全に同じ内容にしました。
今回、Map Imageパネルに追加したボタンは「Gauss」「Rot90」「Min」ボタン、「Filter」数値入力ボタン、「Normal Map」ボタン、「Normal Space」トグルボタンです。
pic090918_02.jpg

実行ファイルはこちらになります。

Linux 64bit

Linux 32bit

Windows 32bit


ソースファイルのパッチ(Blender2.49.2_Vectex_QtSVG_patch.zip)

AGGバージョンも更新しています。
実行ファイルは以前の記事のURLからダウンロード可能です。
AGGバージョンのソースファイルのパッチ(Blender_modified_patch090916.zip)

この記事を書くまで気づかなかったのですがGaussボタンをオンにしたときの処理は今回の更新では実装していませんでした。
このため現在の状態ではGaussボタンを押しても効果がありません。

今回の機能の更新はかなり地味な感じですが、vectexの中枢部分の改良ともいえる重要なものです。
OSAを使用したvectexのレンダリング画像は、特に細かい模様が連続しているような部分でかなり向上していると思います。
下の画像では、左からオリジナルのvectexの補間計算、今回可能になったvectex+OSA、PNG画像でOSA使用という条件でレンダリングしています。
pic090918_04.jpg


ここから、ソースコードの解説になります。
これまでソースコードの修正はプラグインから移植してきたvectexのオリジナルのコードに少しずつ機能追加をするという感じで進めてきましたが、今回はイメージテクスチャの描画部分のソースコードを丸ごとコピーしてきて、その中で画像データからピクセルの色情報を取得する部分を探してvectexのコードに置き換えるというような感じになっています。

イメージテクスチャでvectexの描画を行うvectex()関数に相当するのは、blender/source/blender/render/intern/source/imagetexture.cにあるimagewrap()関数、imagewraposa()関数です。
OSAの機能が有効な場合にはimagewraposa()関数が呼ばれ、そうでない場合にはimagewrap()関数が呼ばれます。

imagewraposa()関数を使用するためには、同じファイルに書かれているboxsample()、boxsampleclip()、clipy_rctf()、clipx_rctf()、square_rctf()、clipy_rctf_swap()、clipx_rctf_swap()、ibuf_get_color()などの関数が必要になります。

今回はそれらすべてのファイルをtexture.cにコピーし、関数名にvtex_という文字列を加えるなどして別の関数にした上で、vectexの機能を使用できるように修正を加えました。
imagewraposa()関数については、名前をvectex_osa()として関数の引数もvectex()関数と同じになるように修正しています。

その上で、OSAが有効な場合はvectex_osa()関数が呼ばれ、OSAが無効な時とvectexパネルでMipmap(Old)、Interpol(Old)がオンになっている時にはvectex()関数が呼ばれるようにしています。

これでは、かなりのソースコードが重複していて無駄な感じがしますが、これは今後の開発の方向性などを考えた上で行っています。

今回でBlender2.49上での開発を終了し、次からはBlender2.5をベースとしていくつもりです。
ただし、単純に今の状態でそのまま移行するのではなく、vectexの実装の仕方をもう少しBlenderのプログラミングの方針に合うように修正したいと思っています。
現在vectexはイメージテクスチャとは独立したテクスチャタイプになっていますが、実際のところソースコードのかなりの部分が重複するため、イメージテクスチャの中に統合してしまうのがより合理的なように思います。

今回、imagewraposa()関数をコピーしてvectex_osa()という関数に作り替えることで、次回以降イメージテクスチャのコードの中にvectexを移していくための足掛かりとしたいと思いました。

具体的なソースコードの修正内容について見ていきます。
前回からの修正内容(changes090918.zip)

まず、ユーザーインターフェイスの部分です。
vectexパネルからMap Imageパネルと重複するボタンを削除し、MipMap、Interpolボタンの名前と説明を修正しました。

blender/source/blender/src/buttons_shading.c
(line:800-)
static void texture_panel_vectex(Tex *tex)
{
...
    uiDefButI(block, TOG, B_TEXPRV, "MipMap(Old)", 10, 55, 150, 18, &tex->vtex_mipmap, 0, 1, 0, 0, "Uses mipmap averaging(Use original plugin's mipmap calculation)");
    uiDefButI(block, TOG, B_TEXPRV, "Interpol(Old)", 160, 55, 150, 18, &tex->vtex_interpol, 0, 1, 0, 0, "Interpolates nearby pixels(Use original plugin's interpolate calculation)");
...
/*   
    uiDefButBitS(block, TOG, TEX_USEALPHA, B_TEXPRV, "UseAlpha",    10, 35, 100, 20, &tex->imaflag, 0, 0, 0, 0, "Click to use Image's alpha channel");
    uiDefButBitS(block, TOG, TEX_CALCALPHA, B_TEXPRV, "CalcAlpha",    110, 35, 100, 20, &tex->imaflag, 0, 0, 0, 0, "Click to calculate an alpha channel based on Image RGB values");
    uiDefButBitS(block, TOG, TEX_NEGALPHA, B_TEXPRV, "NegAlpha",    210, 35, 100, 20, &tex->flag, 0, 0, 0, 0, "Click to invert the alpha values");
*/
...
}

Map Imageパネルについては、vectexが有効な場合に非表示にしていた部分を削除して、イメージテクスチャのときと同じ内容で表示されるように修正しました。
これは前回行った修正内容を取り消して、元のソースコードと同じになったということで、ソースコードの引用は省略します。

次に、vectex()関数を呼び出しているmultitex()関数の修正です。
vectex()関数が呼ばれる条件を制限し、今回追加したvectex_osa()関数を呼び出すコードを追加しています。
blender/source/blender/render/intern/source/texture.c
(line:3116-)
static int multitex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres, short thread, short which_output)
{
...
    case TEX_VECTEX:
        /*retval= vectex(tex, texvec, dxt, dyt, osatex, texres);*/
        if(tex->vtex_mipmap || tex->vtex_interpol || !(osatex)) retval= vectex(tex, texvec, dxt, dyt, osatex, texres);
        else retval= vectex_osa(tex, texvec, dxt, dyt, osatex, texres);

        break;
...
}

vectex()関数には本来は変更は必要ないのですが、vtex_osa()関数と共通するコードのうちの一部を別の関数として分離してみました。
vectex()関数の頭の方で、tex->vtex_instance_dataの状態をチェックしてプレビュー画面の色を黒、赤にしたり、SVGファイル名が変更されたときにキャッシュされたタイル画像を作成し直している部分です。
チェックした内容によってはvectex()関数から抜ける必要があるため、その場合は関数の戻り値をNULLとし、正常な場合はインスタンスデータを返すようにしています。
(line:1264-)
VtexInstance * vtex_check_instance(Tex *tex, TexResult *texres)
{

    if (! tex->vtex_enable)
    {
        /* Plugin is disabled, check if there is allocated memory to cleanup */
        if (tex->vtex_instance_data != NULL)
        {
            vtex_destroy_instance(tex);
            tex->vtex_mem = 0;
        }
       
        /* Return a black pixel */
        texres->tin = texres->ta = 1.0;
        texres->tr = texres->tg = texres->tb = 0;
           

        return NULL;  

    }
...
    VtexInstance *instance = (VtexInstance *) tex->vtex_instance_data;      
...
    }
   
    return instance;
}
分離したコードを呼ぶ出す部分です。
(line:1333)
static int vectex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres)
{
...
    BLI_lock_thread(LOCK_IMAGE);

    VtexInstance *instance = vtex_check_instance(tex, texres);
    if (instance == NULL){

        BLI_unlock_thread(LOCK_IMAGE);
   
        return (TEX_INT | TEX_RGB);  
    }
    BLI_unlock_thread(LOCK_IMAGE);
...
}


以下は、imagetexture.cからコピーしてきた関数なので、diffコマンドではすべてが追加されたようになっています。
かなり長いので、短く引用しながらコメントしていきます。

まず、vectex_osa()関数からです。
引数を変更して元のImage *ima、ImBuf *ibufを削除、int osatexを追加しています。
当然のように、関数内でそれら削除した引数を使用している部分はコメントアウトするか、削除してあります。
最初にあるImBuf、ミップマップのチェックを行っている部分はコメントアウトしています。
次に、vectex()関数からインスタンスデータのチェックを呼び出す処理、解像度計算を行う処理などをコピーしています。
(line:2151-)
int vectex_osa(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres)
{
...
    /* quick tests */
    /*if(ibuf==NULL && ima==NULL)
...
       return retval;*/
   
    /* mipmap test */
    /*if(tex->imaflag & TEX_MIPMAP) {
...
    }*/
   
    BLI_lock_thread(LOCK_IMAGE);

    VtexInstance *instance = vtex_check_instance(tex, texres);
    if (instance == NULL){
        BLI_unlock_thread(LOCK_IMAGE);
   
        return (TEX_INT | TEX_RGB);  
    }
    BLI_unlock_thread(LOCK_IMAGE);
...
    else {
        /* OSA is not active; use the default image resolution */
        ideal_res = VTEX_TILE_SIZE;
        power     = VTEX_TILE_SIZE_POWER;
        pixel_size = 1.0 / VTEX_TILE_SIZE;
    }

そして、ImBufの中に格納されている画像サイズの代わりに使用する値resolutionをここで定義しています。
フィールドレンダリング関連の処理はImBuf構造体に関係しているためコメントアウトしています。
vectexでは今のところフィールドレンダリングには未対応です。
    int resolution = 1 << power;
...
    /*if(ibuf->flags & IB_fields) {
        if(R.r.mode & R_FIELDS) {*/            /* field render */
            /*if(R.flag & R_SEC_FIELD) {*/        /* correction for 2nd field */
                /* fac1= 0.5/( (float)ibuf->y ); */
                /* fy-= fac1; */
            /*}
            else {*/                /* first field */
                /*fy+= 0.5f/( (float)ibuf->y );
            }
        }
    }*/
...

ここで、画像サイズを取得している部分を先ほど定義したresolutionに置き換えています。
vectexでは画像のサイズは縦横同じになるため、MIN2マクロでの比較処理が不要になります。
そして、解像度が可変のためレンダリング時には各ピクセル毎に計算し直されることになります。
この関数内でImBufが使用されるのは、画像サイズの取得が用途のほとんどです。
それ以外は、boxsample()関数に引数で渡されるとき、ミップマップの処理の際にどのレベルのミップマップが有効になっているのかを調べる処理に使われているだけです。
...
    if(tex->imaflag & TEX_FILTER_MIN) {
        /* make sure the filtersize is minimal in pixels (normal, ref map can have miniature pixel dx/dy) */
         /*float addval= (0.5f * tex->filtersize) / (float) MIN2(ibuf->x, ibuf->y);*/
         float addval= (0.5f * tex->filtersize) / (float) resolution;
...

間がかなり開いて、フィールドレンダリングの処理をコメントアウトしています。
関数内での処理の流れで言うと、ここからミップマップを使用している場合の処理が始まっています。
ミップマップの処理をする際に対象のレベルを保持するために使用するImBuf構造体の定義をコメントアウトしています。
pixsizeの計算に画像サイズが使用されている部分をresolutionに置き換えています。
...
    /* warning no return! */
    /*if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
        ibuf->rect+= (ibuf->x*ibuf->y);
    }*/

    /* choice:  */
    if(tex->imaflag & TEX_MIPMAP) {
        /*ImBuf *previbuf, *curibuf;*/
        float bumpscale;
       
        dx= minx;
        dy= miny;
        maxd= MAX2(dx, dy);
        if(maxd>0.5) maxd= 0.5;

        /*pixsize = 1.0f/ (float) MIN2(ibuf->x, ibuf->y);*/
        pixsize = 1.0f/ (float) resolution;
       
        bumpscale= pixsize/maxd;
        if(bumpscale>1.0f) bumpscale= 1.0f;
        else bumpscale*=bumpscale;

Blenderの通常のミップマップの処理はテクスチャ画像の解像度が低い部分で有効になるように計算されています。
一方でvectexはテクスチャの解像度が高い場合でも動作するミップマップのようなものと考えることができます。
そのため、今回は既存のミップマップのコードをすべてvectexに置き換えるようにソースコードを修正しています。
以下の部分では、既存のミップマップの処理をコメントアウトし、新規に追加するvectexのミップマップ処理のために必要な変数max_res、min_resを定義しています。
次の部分ではミップマップの補間処理をスキップするかどうかを判別する条件式を置き換えています。
ミップマップの処理ではミップマップレベルが一つ下のものと現在のレベルのものを合成するという形で補間を行います。
もし、ミップマップの段数が少なくて一つしかなければ、補間計算はできません。
ミップマップの補間計算をスキップするかどうかの条件は、元のコードでは previbuf!=curibuf ですが、vectexでは ideal_res != max_res となります。
そして、ここでも画像サイズが使用されている部分をresolutionに置き換えています。
        /*curmap= 0;
        previbuf= curibuf= ibuf;
        while(curmap<IB_MIPMAP_LEVELS && ibuf->mipmap[curmap]) {
            if(maxd < pixsize) break;
            previbuf= curibuf;
            curibuf= ibuf->mipmap[curmap];
            pixsize= 1.0f / (float)MIN2(curibuf->x, curibuf->y);
            curmap++;
        }*/
       
        int max_res = 1 << power;
        int min_res = max_res >> 1;


        /*if(previbuf!=curibuf || (tex->imaflag & TEX_INTERPOL)) {*/
        if(ideal_res != max_res || (tex->imaflag & TEX_INTERPOL)) {
            /* sample at least 1 pixel */
            /*if (minx < 0.5f / ibuf->x) minx = 0.5f / ibuf->x;
            if (miny < 0.5f / ibuf->y) miny = 0.5f / ibuf->y;*/
            if (minx < 0.5f / resolution) minx = 0.5f / resolution;
            if (miny < 0.5f / resolution) miny = 0.5f / resolution;

        }

この後、非常に重要な部分、ピクセルデータを取得するvtex_boxsample()関数を呼び出して、最終的な計算結果をtexres構造体に格納する部分になります。
しかし、かなり長い上にミップマップを使用しているか、そうでないかで条件分岐し、その両方についてさらに、バンプマップを使用する場合とそれ以外というようにif、else文が重なり合っていて、コードがかなり見づらくなっています。

まず、ミップマップが有効で、バンプマップを使用している場合です。
vtex_boxsample()関数で引数の内容が違っています。
元々は2つのミップマップcuribufとprevibufのそれぞれのピクセルデータを取得して、それらをdx:dyの比率で足し合わるという処理を行っていました。
vectexではpowerの値から作成されたタイル画像のインデックス値が計算できるので、ImBuf構造体の代わりにint powerの値を渡しています。
そしてvectexの計算に必要なVtexInstance *instance、Tex *texが引数に追加されています。
2つのミップマップから得られた値を足し合わせる比率の計算方法も違っています。
最後に、バンプマップの強度を補正するbumpscaleの値の計算にミップマップの補間をする処理を付け加えています。
        if(texres->nor && (tex->imaflag & TEX_NORMALMAP)==0) {
            /* a bit extra filter */
            //minx*= 1.35f;
            //miny*= 1.35f;
           
            /*vtex_boxsample(curibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend);*/
            vtex_boxsample(instance, power, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend, tex);
            val1= texres->tr+texres->tg+texres->tb;
            /*vtex_boxsample(curibuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend);*/
            vtex_boxsample(instance, power, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend, tex);
            val2= texr.tr + texr.tg + texr.tb;
            /*vtex_boxsample(curibuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend);*/
            vtex_boxsample(instance, power, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend, tex);
            val3= texr.tr + texr.tg + texr.tb;

            /* don't switch x or y! */
            texres->nor[0]= (val1-val2);
            texres->nor[1]= (val1-val3);
           
            /*if(previbuf!=curibuf) {*/  /* interpolate */
            if(ideal_res != max_res) {  /* interpolate */
               
                /*vtex_boxsample(previbuf, fx-minx, fy-miny, fx+minx, fy+miny, &texr, imaprepeat, imapextend);*/
                vtex_boxsample(instance, power -1, fx-minx, fy-miny, fx+minx, fy+miny, &texr, imaprepeat, imapextend, tex);
               
                /* calc rgb */
                /*dx= 2.0f*(pixsize-maxd)/pixsize;
                if(dx>=1.0f) {
                    texres->ta= texr.ta; texres->tb= texr.tb;
                    texres->tg= texr.tg; texres->tr= texr.tr;
                }
                else {
                    dy= 1.0f-dx;
                    texres->tb= dy*texres->tb+ dx*texr.tb;
                    texres->tg= dy*texres->tg+ dx*texr.tg;
                    texres->tr= dy*texres->tr+ dx*texr.tr;
                    texres->ta= dy*texres->ta+ dx*texr.ta;
                }*/
               
                /* Do mipmapping: interpolate final pixel from the sampled pixels */
                double max_weight = (double)(ideal_res - min_res) / (max_res - min_res);
                double min_weight = 1 - max_weight;
                texres->tr = texres->tr * max_weight + texr.tr * min_weight;
                texres->tg = texres->tg * max_weight + texr.tg * min_weight;
                texres->tb = texres->tb * max_weight + texr.tb * min_weight;
                texres->ta = texres->ta * max_weight + texr.ta * min_weight;

               
                /*val1= dy*val1+ dx*(texr.tr + texr.tg + texr.tb);
                vtex_boxsample(previbuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend);*/
                val1=  max_weight*val1+ min_weight*(texr.tr + texr.tg + texr.tb);
                vtex_boxsample(instance, power -1, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend, tex);

                /*val2= dy*val2+ dx*(texr.tr + texr.tg + texr.tb);
                vtex_boxsample(previbuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend);*/
                val2=  max_weight*val2+ min_weight*(texr.tr + texr.tg + texr.tb);
                vtex_boxsample(instance, power -1, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend, tex);

                /*val3= dy*val3+ dx*(texr.tr + texr.tg + texr.tb);*/
                val3= max_weight*val3+ min_weight*(texr.tr + texr.tg + texr.tb);
               
                texres->nor[0]= (val1-val2);    /* vals have been interpolated above! */
                texres->nor[1]= (val1-val3);
               
                /*if(dx<1.0f) {
                    dy= 1.0f-dx;
                    texres->tb= dy*texres->tb+ dx*texr.tb;
                    texres->tg= dy*texres->tg+ dx*texr.tg;
                    texres->tr= dy*texres->tr+ dx*texr.tr;
                    texres->ta= dy*texres->ta+ dx*texr.ta;
                }*/
               
                int resolution_cur = 1 << power;
                int resolution_prev = 1 << (power - 1);
                float resolution_mix =(float) resolution_cur * max_weight + (float) resolution_prev * min_weight;

                pixsize = 1.0f/ resolution_mix;

                bumpscale= pixsize/maxd;
                if(bumpscale>1.0f) bumpscale= 1.0f;
                else bumpscale*=bumpscale;

            }
            texres->nor[0]*= bumpscale;
            texres->nor[1]*= bumpscale;
        }
こちらはバンプマップを使用していない場合の処理です。
法線計算のために本来のテクスチャ座標の他にX、Yそれぞれの方向にずらした位置の色データを計算するため、それぞれのミップマップに対して3回ずつ行っていたvtex_bosxample()関数の呼び出しが1回ずつに減っています。
代わりにvectex()関数からコピーしてきた tex->vtex_tex_level が有効な場合の処理が増えています。
これはテクスチャの解像度を色分け表示するための処理で、vectexパネルのTex Levelボタンがオンになったときに使用されます。
        else {
            maxx= fx+minx;
            minx= fx-minx;
            maxy= fy+miny;
            miny= fy-miny;

            /*vtex_boxsample(curibuf, minx, miny, maxx, maxy, texres, imaprepeat, imapextend);*/
            vtex_boxsample(instance, power, minx, miny, maxx, maxy, texres, imaprepeat, imapextend, tex);

            if (tex->vtex_tex_level)
            {
                /* Apply hue color based on image detail level */
                double h = (power - 1) * 30.0;
                double cr, cg, cb;
                vtex_hsv2rgb(h, 1.0, 1.0, &cr, &cg, &cb);
                texres->tr *= cr;
                texres->tg *= cg;
                texres->tb *= cb;
            }

           
            /*if(previbuf!=curibuf) {*/  /* interpolate */
            if(ideal_res != max_res) {  /* interpolate */
                /*vtex_boxsample(previbuf, minx, miny, maxx, maxy, &texr, imaprepeat, imapextend);*/
                vtex_boxsample(instance, power -1, minx, miny, maxx, maxy, &texr, imaprepeat, imapextend, tex);
               
                if (tex->vtex_tex_level)
                {
                    /* Apply hue color based on texture detail level */
                    double h = (power - 2) * 30.0;
                    double cr, cg, cb;
                    vtex_hsv2rgb(h, 1.0, 1.0, &cr, &cg, &cb);
                    texr.tr *= cr;
                    texr.tg *= cg;
                    texr.tb *= cb;
                }

               
                /*fx= 2.0f*(pixsize-maxd)/pixsize;
               
                if(fx>=1.0) {
                    texres->ta= texr.ta; texres->tb= texr.tb;
                    texres->tg= texr.tg; texres->tr= texr.tr;
                } else {
                    fy= 1.0f-fx;
                    texres->tb= fy*texres->tb+ fx*texr.tb;
                    texres->tg= fy*texres->tg+ fx*texr.tg;
                    texres->tr= fy*texres->tr+ fx*texr.tr;
                    texres->ta= fy*texres->ta+ fx*texr.ta;
                }*/
               
                /* Do mipmapping: interpolate final pixel from the sampled pixels */
                double max_weight = (double)(ideal_res - min_res) / (max_res - min_res);
                double min_weight = 1 - max_weight;
                texres->tr = texres->tr * max_weight + texr.tr * min_weight;
                texres->tg = texres->tg * max_weight + texr.tg * min_weight;
                texres->tb = texres->tb * max_weight + texr.tb * min_weight;
                texres->ta = texres->ta * max_weight + texr.ta * min_weight;

            }
        }
    }
ここからミップマップを使用しない場合の処理です。
バンプマップを使用する場合は法線計算のためvtex_boxsampleを3回呼び出しています。
バンプマップを使用しない場合、vectexのTex Level表示のための処理をしています。
    else {
        if((tex->imaflag & TEX_INTERPOL)) {
            /* sample 1 pixel minimum */
            /*if (minx < 0.5f / ibuf->x) minx = 0.5f / ibuf->x;
            if (miny < 0.5f / ibuf->y) miny = 0.5f / ibuf->y;*/
            if (minx < 0.5f / resolution) minx = 0.5f / resolution;
            if (miny < 0.5f / resolution) miny = 0.5f / resolution;

        }

        if(texres->nor && (tex->imaflag & TEX_NORMALMAP)==0) {
           
            /*vtex_boxsample(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend);*/
            vtex_boxsample(instance, power, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend, tex);
            val1= texres->tr+texres->tg+texres->tb;
            /*vtex_boxsample(ibuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend);*/
            vtex_boxsample(instance, power, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend, tex);
            val2= texr.tr + texr.tg + texr.tb;
            /*vtex_boxsample(ibuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend);*/
            vtex_boxsample(instance, power, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend, tex);
            val3= texr.tr + texr.tg + texr.tb;
            /* don't switch x or y! */
            texres->nor[0]= (val1-val2);
            texres->nor[1]= (val1-val3);
        }
        else {
            /*vtex_boxsample(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend);*/
            vtex_boxsample(instance, power, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend, tex);
           

            if (tex->vtex_tex_level)
            {
                /* Apply hue color based on image detail level */
                double h = (power - 1) * 30.0;
                double cr, cg, cb;
                vtex_hsv2rgb(h, 1.0, 1.0, &cr, &cg, &cb);
                texres->tr *= cr;
                texres->tg *= cg;
                texres->tb *= cb;
            }

        }
    }
ここで再び、フィールドレンダリング関連のコードをコメントアウトしています。
最後にvectexのメモリチェックの処理を追加しています。
...
    /*if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
        ibuf->rect-= (ibuf->x*ibuf->y);
    }*/
...
    /* Before returning, check if the memory limit has been reached */
    BLI_lock_thread(LOCK_IMAGE);
    if (tex->vtex_mem_max != 0 && instance->tile_memory > tex->vtex_mem_max << 20)
    {
        vtex_limit_tile_set(instance, tex->vtex_mem_max << 20);
    }
    tex->vtex_mem = (instance->tile_memory + 524288) >> 20;
    BLI_unlock_thread(LOCK_IMAGE);


    return retval;
}
vectex_osa()関数が終わったので、次はvtex_boxsample()関数を見てみます。
vectex_osa()関数の説明中に書いていますが、引数が元のboxsample()関数から変わっています。
修正している内容は、ImBufから取得していた画像サイズをpowerから計算したresolutionの値に置き換えているだけです。
(line:2048-)
static void vtex_boxsample(VtexInstance *instance, int power, float minx, float miny, float maxx, float maxy, TexResult *texres, int imaprepeat, int imapextend, Tex *tex)
{
...
   
    int resolution = 1 << power;


    rf= stack;
    /*rf->xmin= minx*(ibuf->x);
    rf->xmax= maxx*(ibuf->x);
    rf->ymin= miny*(ibuf->y);
    rf->ymax= maxy*(ibuf->y);*/
    rf->xmin= minx*(resolution);
    rf->xmax= maxx*(resolution);
    rf->ymin= miny*(resolution);
    rf->ymax= maxy*(resolution);


    texr.talpha= texres->talpha;    /* is read by boxsample_clip */
   
    if(imapextend) {
        /*CLAMP(rf->xmin, 0.0f, ibuf->x-1);
        CLAMP(rf->xmax, 0.0f, ibuf->x-1);*/
        CLAMP(rf->xmin, 0.0f, resolution-1);
        CLAMP(rf->xmax, 0.0f, resolution-1);

    }
    else if(imaprepeat)
        /*vtex_clipx_rctf_swap(stack, &count, 0.0, (float)(ibuf->x));*/
        vtex_clipx_rctf_swap(stack, &count, 0.0, (float) resolution);
    else {
        /*alphaclip= vtex_clipx_rctf(rf, 0.0, (float)(ibuf->x));*/
        alphaclip= vtex_clipx_rctf(rf, 0.0, (float) resolution);

        if(alphaclip<=0.0) {
            texres->tr= texres->tb= texres->tg= texres->ta= 0.0;
            return;
        }
    }

    if(imapextend) {
        /*CLAMP(rf->ymin, 0.0f, ibuf->y-1);
        CLAMP(rf->ymax, 0.0f, ibuf->y-1);*/
        CLAMP(rf->ymin, 0.0f, resolution-1);
        CLAMP(rf->ymax, 0.0f, resolution-1);

    }
    else if(imaprepeat)
        /*vtex_clipy_rctf_swap(stack, &count, 0.0, (float)(ibuf->y));*/
        vtex_clipy_rctf_swap(stack, &count, 0.0, (float) resolution);
    else {
        /*alphaclip*= vtex_clipy_rctf(rf, 0.0, (float)(ibuf->y));*/
        alphaclip*= vtex_clipy_rctf(rf, 0.0, (float) resolution);

        if(alphaclip<=0.0) {
            texres->tr= texres->tb= texres->tg= texres->ta= 0.0;
            return;
        }
    }
...

}
vtex_boxsample()関数から呼ばれている関数、vtex_boxsampleclip()です。
こちらも引数を変更しています。
関数の中の修正は、やはり画像サイズをresolutionに変更している部分です。
vtex_get_color()関数の呼び出しは、もともとはibuf_get_color()という名前の関数を呼び出しています。
この関数はImBufに格納されている画像のデータ領域からピクセルの色情報を取得する関数で、今回の修正ではこの部分をvectexのタイル画像からピクセル情報を取得するように修正しています。
(line:1962-)
static void vtex_boxsampleclip(VtexInstance *instance, int power, rctf *rf, TexResult *texres, Tex *tex)
{
...
    int resolution = 1 << power;
...
    /*if(endx>=ibuf->x) endx= ibuf->x-1;
    if(endy>=ibuf->y) endy= ibuf->y-1;*/
    if(endx>=resolution) endx= resolution-1;
    if(endy>=resolution) endy= resolution-1;

...
    if(starty==endy && startx==endx) {
        vtex_get_color(instance, &texres->tr, power, startx, starty, tex);
...
                vtex_get_color(instance, col, power, startx, y, tex);
...
                    vtex_get_color(instance, col, power, x, y, tex);
...
}
vtex_get_color()関数は元の関数を修正したというよりは、vtex_sample()関数から補間処理を省いて、引数を変更したものという感じになっています。
この関数の引数は、元のibuf_get_color()関数とvtex_sample()関数の両方を足して2で割ったような感じになっています。
(line:1719)
static void vtex_get_color(VtexInstance *instance, float *col, int power, int x, int y, Tex *tex)
{
     int premul;
     if (tex->vtex_imaflag & IMA_DO_PREMUL) {
         premul = 1;
     }
     else {
         premul = 0;
     }

    int resolution = 1 << power;
    y = resolution - y - 1;
    int tile_size  = (power < VTEX_TILE_SIZE_POWER) ? resolution : VTEX_TILE_SIZE;
   
    int index = vtex_get_tile(instance, x, y, power, tex);       
    unsigned char *tile = instance->tile_set[index].image;
    if (instance->tile_set[index].age == VTEX_CONST_COLOR)
    {   
        /* Constant color tile */
            if (premul) {
            int val= tile[3];
            col[2] = (float)(((tile[0]*val)>>8) / 255.0);
            col[1] = (float)(((tile[1]*val)>>8) / 255.0);
            col[0] = (float)(((tile[2]*val)>>8) / 255.0);
            col[3] = (float)(tile[3] / 255.0);
        }
        else {
            col[2] = (float)(tile[0] / 255.0);
            col[1] = (float)(tile[1] / 255.0);
            col[0] = (float)(tile[2] / 255.0);
            col[3] = (float)(tile[3] / 255.0);
        }
    }
    else
    {
        /* Clip coordinates to be inside the tile */
        x %= tile_size;
        y %= tile_size;

        /* Calculate pixel offset taking the border into account */
        int offset = (y * (tile_size + VTEX_TILE_BORDER) + x) * 4;
            if (premul) {
            int val= tile[offset + 3];
               col[2] = (float)(((tile[offset]*val)>>8)     / 255.0);
            col[1] = (float)(((tile[offset + 1]*val)>>8) / 255.0);
            col[0] = (float)(((tile[offset + 2]*val)>>8) / 255.0);
            col[3] = (float)(tile[offset + 3] / 255.0);
        }
        else {
               col[2] = (float)(tile[offset]     / 255.0);
            col[1] = (float)(tile[offset + 1] / 255.0);
            col[0] = (float)(tile[offset + 2] / 255.0);
            col[3] = (float)(tile[offset + 3] / 255.0);
        }
    }
}
vtex_boxsample()関数から呼ばれている他の関数vtex_clipy_rctf()、vtex_clipx_rctf()、vtex_square_rctf()、vtex_clipy_rctf_swap()、vtex_clipx_rctf_swap()については、引数まで含めて元の関数からの変更はありません。
ということは元の関数を使えばいいだけなのですが、imagetexture.cの中の関数はヘッダファイルなどで外部に公開されていないので、それを使えるようにするためにはヘッダファイルを新規に作成する必要があって、sconsの設定などにも影響が出る可能性まで考えるとかえって面倒なことになってしまいます。
posted by mato at 23:08| Comment(0) | Blender Vectex | このブログの読者になる | 更新情報をチェックする

2009年09月08日

テクスチャリピート、テクスチャノードへの対応

vectexにイメージテクスチャ相当の機能を追加する作業も終盤に近づいてきました。
今回は、テクスチャのリピート、テクスチャノードへの対応という2つの機能追加を行いました。
pic090908_01.jpg pic090908_02.jpg

さらに、ちょうどBlender2.49bがリリースされたばかりだったので、ベースとしているBlederのバージョンを2.49bに変更しました。

実行ファイルはこちらになります。
Linux 64bit

Linux 32bit


Windows 32bit

ソースファイルのパッチ(Blender2.49.2_Vectex_QtSVG_patch.zip)


AGGバージョンも更新しています。
実行ファイルは以前の記事のURLからダウンロードできます。
AGGバージョンのソースファイルのパッチ(Blender_modified_patch090905.zip)


ここから今回の変更内容についてのソースコードの解説になります。

前回からの修正内容(changes090908.zip)
zipファイルを展開すると中に2つのdiffファイルが入っています。
ベースとしているBlenderのバージョンを2.49bに変更した関係で、前回からの修正内容をdiffファイルで出力しようとすると、Blender2.49aから2.49bへの差分情報も含まれることになってしまいました。
それを防ぐためにsvn diffコマンドを2回に分けて使用し、Blenderのバージョンアップの情報を含めないようにしました。

○テクスチャリピート
Blenderでイメージテクスチャを使用するとButtons Windowには「Image」パネルの他に「Map Image」というパネルが表示されます。
このMap Imageパネルの下半分を占めているのがテクスチャのリピート表示に関連するボタンです。
pic090908_03.jpg

このパネルのボタンのうち「Extend」「Clip」「Clip Cube」「Repeat」「Checker」の5つのトグルボタンでどれが有効になっているかによって、テクスチャ座標上での画像の表示のされ方が変わります。
これらのボタンで指定するのはテクスチャ座標で画像範囲の外側をどのように表示するかについてです。

パネルの一番下の「MinX」「MaxX」「MinY」「MaxY」の値をデフォルト状態から変更すると、テクスチャの張られている面よりも表示される画像を小さくすることができ、その場合に画像の外側の表示は、
  1. Extendであれば画像の一番外側のピクセルを延長する。
  2. Clip,Clip Cubeならアルファ値を0としてベースのマテリアルを表示する。
  3. Repeatでは画像の範囲外にも同じ画像を繰り返し表示する。
  4. CheckerではRepeatのように画像を繰り返す部分とClipのようにベースのマテリアルを表示する部分を交互に表示する。
というようになります。
pic090908_04.jpg

今回、Blenderのソースコードで、この処理に関連する部分をvectexでも使えるように修正しました。

まずは、ユーザーインターフェイスのパネルを用意する必要があります。
blender/source/blender/src/buttons_shading.c (line:4676-)
void texture_panels()
{
...
            case TEX_VECTEX:
                texture_panel_vectex(tex);
                texture_panel_image_map(tex, mtex);
                break;
            }
        }
    }
}
これで、Map Imageパネルをvectexパネルの横に表示させることができます。
このとき、イメージテクスチャのときと同じようにMap Imageパネルの表示される位置をvectexパネルの左にするためには、vectexパネルを描画するコードを修正する必要があります。
表示される位置のX座標を640から960に変更しています。
(line:800-)
static void texture_panel_vectex(Tex *tex)
{
...
    if(uiNewPanel(curarea, block, "vectex", "Texture", 960, 0, 318, 204)==0) return;
...
}
Map Imageパネルをそのまま表示してしまうとvectexでは使用しないボタンまで表示されてしまいますので、tex->typeがTEX_VECTEXのときには必要ない部分を表示しないようにMap Imageパネルの描画コードを修正します。
(line:1376-)
static void texture_panel_image_map(Tex *tex, MTex *mtex)
{
...
    /* types */
    if (tex->type==TEX_IMAGE) {
        uiBlockBeginAlign(block);
        uiDefButBitS(block, TOG, TEX_MIPMAP, B_IMAGECHANGED, "MipMap",    10, 180, 75, 20, &tex->imaflag, 0, 0, 0, 0, "Generates and uses mipmaps");
        ...
        uiBlockEndAlign(block);
    }       
...
}

以上の変更でMap Imageパネルを表示できるようにした時点で、実はテクスチャのリピート機能のうちの半分は使えるようになってしまいます。
前々回の修正でvectex()関数に渡されるテクスチャ座標をイメージテクスチャと同じになるようにしていますが、そこで渡されるテクスチャ座標の計算の処理の中にテクスチャのリピートの処理も含まれています。
具体的には、次の部分でその計算が行われています。
blender/source/blender/render/intern/source/texture.c (line:1905-)

static void do_2d_mapping(MTex *mtex, float *t, VlakRen *vlr, float *n, float *dxt, float *dyt)

do_2d_mapping()関数では、テクスチャ座標で「Flat」「Cube」「Tube」「Sphere」のうちのどれを選択しているかに応じた座標計算、Map ImageパネルでRepeatを選択した場合の座表計算、同じくMap ImageパネルでMinX、MaxX、MinY、MaxYを指定したときの座表計算が行われています。

この計算ではテクスチャ座標texvec(この関数の引数ではfloat *tとなっている)の計算の他に、dxt、dytの値も計算されているので、vectexでテクスチャの解像度の計算をするときにも問題ないようです。

あとは、Map ImageパネルでExtend、Clip、Clip Cube、Checkerを選んだ場合の処理です。
これらについては、ソースコードの次の部分に処理が書かれています。

blender/source/blender/render/intern/source/imagetexture.c

int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, float *texvec, TexResult *texres) (line:104-)
int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, float *texvec, float *dxt, float *dyt, TexResult *texres) (line:629-)

これらの関数は、基本的には同じ処理をしていてOSAが有効なときはimagewraposa()関数が呼ばれ、無効な時はimagewrap()関数が呼ばれます。
これらの関数内のテクスチャリピートに関連する部分を探して、vectex()関数の中にも同じような動作をするようにコードを追加します。
blender/source/blender/render/intern/source/texture.c (line:1264-)
static int vectex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres)
{
...
    texres->tin= texres->ta= texres->tr= texres->tg= texres->tb= 0.0f;
...
    float fx, fy;
   
    fx= texvec[0];
    fy= texvec[1];

    if(tex->extend == TEX_CHECKER) {
        int xs, ys;
       
        xs= (int)floor(fx);
        ys= (int)floor(fy);
        fx-= xs;
        fy-= ys;

        if( (tex->flag & TEX_CHECKER_ODD)==0) {
            if((xs+ys) & 1);else return retval;
        }
        if( (tex->flag & TEX_CHECKER_EVEN)==0) {
            if((xs+ys) & 1) return retval;
        }
        /* scale around center, (0.5, 0.5) */
        if(tex->checkerdist<1.0) {
            fx= (fx-0.5)/(1.0-tex->checkerdist) +0.5;
            fy= (fy-0.5)/(1.0-tex->checkerdist) +0.5;
        }
    }
   
    int resolution = 1 << power;
    int x = (int)(fx * resolution);
    int y = (int)(fy * resolution);
    if(tex->extend == TEX_CLIPCUBE) {
        if(x<0 || y<0 || x>=resolution || y>=resolution || texvec[2]<-1.0 || texvec[2]>1.0) {
            return retval;
        }
    }
    else if( tex->extend==TEX_CLIP || tex->extend==TEX_CHECKER) {
        if(x<0 || y<0 || x>=resolution || y>=resolution) {
            return retval;
        }
    }

...
}

tex->extend == TEX_CHECKERのときの処理は、imagewrap()関数のものをそのままコピーアンドペーストしただけです。
その次の部分でresolutionの値を計算してfx、fyに掛けていますが、元のコードでは画像のサイズをImBuf構造体から取得してその値を使用しています。
imagewrap()関数の中では、if(tex->extend == TEX_CLIPCUBE)、else if( tex->extend==TEX_CLIP || tex->extend==TEX_CHECKER)の後に、さらに続いてif(tex->extend==TEX_EXTEND)の処理がありますが、その部分はvectex()関数の中ではなくてvtex_sample()関数の中に移しました。

この部分の処理をどうするべきか試行錯誤している間にvtex_sample()関数の引数でtexvecを2つのfloat値からfloat値の配列に変更しました。
そのためvectex()関数の中のvtex_sample()関数の呼び出しの部分を書き換えていますが、最終的にはその変更は今回の機能追加に直接関係がなかったため上の引用部分では省略しています。

vtex_sample()関数の中では、次の様にソースコードを修正しています。
(line:1068-)
void vtex_sample(VtexInstance *instance, float *texvec, int power, int interp,
            double *pr, double *pg, double *pb, double *pa, Tex *tex)
{
...
    if (interp == 0)
    {
    ...
        /* extend: copy the color of edge pixels */
        /*x = CLAMPIS(x, 0, resolution - 1);
        y = CLAMPIS(y, 0, resolution - 1);*/
        /* clip: alpha=0 outside edges */
        /* repeat: duplicate horizontally and vertically */
       
        if(tex->extend==TEX_EXTEND) {
            if(x>=resolution) x = resolution-1;
            else if(x<0) x= 0;
        }
        else {
            x= x % resolution;
            if(x<0) x+= resolution;
        }
        if(tex->extend==TEX_EXTEND) {
            if(y>=resolution) y = resolution-1;
            else if(y<0) y= 0;
        }
        else {
            y= y % resolution;
            if(y<0) y+= resolution;
        }

    ...
    }
    else
    {
        /* Pick the four nearest pixels and return a bilinear interpolation */
        /*double u = (*texvec0 + 1.0) * (resolution >> 1) - 0.5;
        double v = (1.0 - *texvec1) * (resolution >> 1) - 0.5;*/
        double u = texvec[0] * resolution - 0.5;
        double v = (1.0 - texvec[1]) * resolution - 0.5;
        int x = (int)u;
        int y = (int)v;
        double u_ratio = u - x;
        double v_ratio = v - y;
        if (u_ratio < 0.0) {
            u_ratio = 0.0;
        }
        if (v_ratio < 0.0) {
            v_ratio = 0.0;
        }
        if (u_ratio > 1.0) {
            u_ratio = 1.0;
        }
        if (v_ratio > 1.0){
            v_ratio = 1.0;
        }

        double u_opposite = 1 - u_ratio;
        double v_opposite = 1 - v_ratio;

        /* extend: copy the color of edge pixels */
        /*x = CLAMPIS(x, 0, resolution - 1);
        y = CLAMPIS(y, 0, resolution - 1);*/
        /* clip: alpha=0 outside edges */
        /* repeat: duplicate horizontally and vertically */

        if(tex->extend==TEX_EXTEND) {
            if(x>=resolution) x = resolution-1;
            else if(x<0) x= 0;
        }
        else {
            x= x % resolution;
            if(x<0) x+= resolution;
        }
        if(tex->extend==TEX_EXTEND) {
            if(y>=resolution) y = resolution-1;
            else if(y<0) y= 0;
        }
        else {
            y= y % resolution;
            if(y<0) y+= resolution;
        }

...
}

vectexの作者のmgmalheirosさんは、コメントでextend以外の場合にどう処理をするべきかを書いていますので、将来的に機能を拡張する予定だったようです。
ここで、vectexの元のコードではCLAMPマクロを使ってx、y座標の値を0、resolution-1の範囲に収まるようにしていました。
これがBlenderのExtendボタンを押した状態に相当するので、このソースコードをそのまま利用することもできるのですが、今回はimagewrap()関数の中にあったソースコードに置き換えることにしました。
Interpolボタンを押したときの処理ではx、yの値以外にもu_ratio、v_ratio、u_opposite、v_oppositeなどの値を使用しているため、これらの値も範囲内に収まるように修正しました。

テクスチャリピートの機能については、以上のような感じです。

○テクスチャノード
今回はノードエディタの中に、vectexのための専用のパネルを作っていません。
テクスチャノードでvectexを使用するためには、テクスチャノードのメニューで「Add」->「Input」->「Texture」を実行してTextureノードを作成し、そのノードのメニューからあらかじめ作成しておいたvectexを使用したテクスチャを選択する、という手順が必要です。
pic090908_05.jpg pic090908_06.jpg

vectexをテクスチャノードに対応させるためには、まずテクスチャノードでdxt、dytの値を使用できるようにする必要があります。
Blender2.5の方では少し前にテクスチャノードでdxt、dytを使えるようにする修正が加えられました。
以下はその部分のsvn logコマンドの出力です。
------------------------------------------------------------------------
r22583 | kakbarnf | 2009-08-18 05:30:11 +0900 (火, 18  8月 2009) | 3 lines

Slight refactor of texture nodes.

Delegates now receive a TexParams* instead of float *coords. This gives texture nodes access to dxt, dyt, cfra as well as coords. This fixes the time node and allows nice sampling to be implemented.

今回はこの部分の修正をBlender2.5から持ち込んでみました。
この部分のソースコードの修正内容の詳細についてはかなり長くなるので説明は省略します。

ただ、この修正を行っただけではvectexの解像度計算ができるようになりませんでした。
原因を調べると、実際にvectex()関数を呼び出す処理を行っているmultitex()関数、それを呼び出すmultitex_thread()関数、それを呼び出すmultitex_ext()関数、それを呼び出すcolorfn()関数というようにさかのぼって、ようやく理由が分かります。
blender/source/blender/nodes/intern/TEX_nodes/TEX_texture.c (line:43-)
static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, short thread)
{
...
        textype = multitex_ext(nodetex, coord, p->dxt, p->dyt, p->osatex, &texres);
        /*textype = multitex_ext(nodetex, coord, 0, 0, 0, &texres);*/
...
}

この部分でdxt、dytのポインタ値を0として処理しているために、せっかくTexParamsに保存するようにしたdxt、dytの値が最終的に呼び出されるvectex()関数まで届いていませんでした。

Blender2.5でのテクスチャノードでのdxt、dytの拡張は私が使いたかったこととは別の理由で使われているようです。
ちなみに、もともとはdxt、dytのみの拡張でしたが、vectexではそれ以外にもosatexの値も必要なため追加してあります。

blender/source/blender/nodes/intern/TEX_util.h (line:75-)
typedef struct TexCallData {
    TexResult *target;
    float *coord;
    float *dxt, *dyt;
    int osatex;
    char do_preview;
    short thread;
    short which_output;
     int cfra;
} TexCallData;

typedef struct TexParams {
    float *coord;
    float *dxt, *dyt;
    int osatex;
    int cfra;
} TexParams;

...
void ntreeTexExecTree(bNodeTree *nodes, TexResult *texres, float *coord, float *dxt, float *dyt, int osatex, char do_preview, short thread, struct Tex *tex, short which_output, int cfra);
blender/source/blender/blenkernel/BKE_node.h (line:427)
void ntreeTexExecTree(struct bNodeTree *ntree, struct TexResult *target, float *coord, float *dxt, float *dyt, int osatex, char do_preview, short thread, struct Tex *tex, short which_output, int cfra);
blender/source/blender/nodes/intern/TEX_util.c
(line:124-)
void params_from_cdata(TexParams *out, TexCallData *in)
{
    out->coord = in->coord;
    out->dxt = in->dxt;
    out->dyt = in->dyt;
    out->osatex = in->osatex;
    out->cfra = in->cfra;
}
(line:133-)
void tex_do_preview(bNode *node, bNodeStack *ns, TexCallData *cdata)
{
...
    float dxt[3] = {0.0, 0.0, 0.0};
    float dyt[3] = {0.0, 0.0, 0.0};
...
    params.dxt = dxt;
    params.dyt = dyt;
    params.osatex = 0;
...
}
(line:214-)
void ntreeTexExecTree(
     bNodeTree *nodes,
     TexResult *texres,
     float *coord,
     float *dxt, float *dyt,
    int osatex,
     char do_preview,
     short thread,
     Tex *tex,
     short which_output,
     int cfra
) {
    TexResult dummy_texres;
    TexCallData data;
   
    if(!texres) texres = &dummy_texres;
    data.coord = coord;
    data.dxt = dxt;
    data.dyt = dyt;
    data.osatex = osatex;
    data.target = texres;
    data.do_preview = do_preview;
    data.thread = thread;
    data.which_output = which_output;
   
    ntreeExecTree(nodes, &data, thread);
}

blender/source/blender/render/intern/source/texture.c
(line:720-)
static int evalnodes(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres, short thread, short which_output)
{
    short rv = TEX_INT;
    bNodeTree *nodes = tex->nodetree;
   
    ntreeTexExecTree(nodes, texres, texvec, dxt, dyt, osatex, 0, thread, tex, which_output, R.r.cfra);
   
    if(texres->nor) rv |= TEX_NOR;
    rv |= TEX_RGB;
    return rv;
}

(line:2120-)
static int multitex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres, short thread, short which_output)
{
...
    if(tex->use_nodes && tex->nodetree) {
        retval = evalnodes(tex, texvec, dxt, dyt, osatex, texres, thread, which_output);
    }
...
}

テクスチャノードを使用しているときには、tex->typeがTEX_VECTEXになっていない状態でテクスチャ座標の計算などが行われます。
この場合、そのままではosatexに正しい値が入りません。
これに対応するためには、以前tex->typeがTEX_VECTEXの場合にosatexに正しい値が入るように修正した場所に再度修正を加える必要があります。
blender/source/blender/blenkernel/intern/material.c (line:639-)
static void do_init_render_material(Material *ma, int r_mode, float *amb)
{
...
            if(r_mode & R_OSA) {
                if ELEM4(mtex->tex->type, TEX_IMAGE, TEX_PLUGIN, TEX_ENVMAP, TEX_VECTEX) ma->texco |= TEXCO_OSA;
                if (mtex->tex->use_nodes && mtex->tex->nodetree) ma->texco |= TEXCO_OSA;
            }
...
}

前々回の修正でテクスチャ座標でReflを選択したときに、tex->typeがTEX_VECTEXの場合にdxt、dytの値を補正していましたが、その条件式にテクスチャノードが使用されている場合も含める必要があります。
blender/source/blender/render/intern/source/texture.c
(line:2453-)
void do_material_tex(ShadeInput *shi)
{
...
                if ((tex->type==TEX_VECTEX) || (tex->use_nodes && tex->nodetree)) {
...
}

同じような修正が、前回修正したスカイテクスチャ、ランプテクスチャ、ヘイローテクスチャの処理の部分でも必要です。
(line:3019-)
void do_halo_tex(HaloRen *har, float xn, float yn, float *colf)
{
...
        if ((mtex->tex->type==TEX_VECTEX) || (mtex->tex->use_nodes && mtex->tex->nodetree)) {
...
}

(line:3162-)
void do_sky_tex(float *rco, float *lo, float *dxyview, float *hor, float *zen, float *blend, int skyflag, short thread)
{
...
            if ((mtex->tex->type==TEX_VECTEX) || (mtex->tex->use_nodes && mtex->tex->nodetree)) {
...
                if (((mtex->tex->type==TEX_VECTEX) || (mtex->tex->use_nodes && mtex->tex->nodetree)) && (dxyview)) {
...
                    if (((mtex->tex->type==TEX_VECTEX) || (mtex->tex->use_nodes && mtex->tex->nodetree)) && (dxyview)) {
...
                    if (((mtex->tex->type==TEX_VECTEX) || (mtex->tex->use_nodes && mtex->tex->nodetree)) && (dxyview)) {
...
}

blender/source/blender/render/intern/source/convertblender.c (line:3326-)
static GroupObject *add_render_lamp(Render *re, Object *ob)
{
...
            if(G.rendering) {
                if(re->osa) {
                    if((la->mtex[c]->tex->type==TEX_IMAGE) || (la->mtex[c]->tex->type==TEX_VECTEX) || (la->mtex[c]->tex->use_nodes && la->mtex[c]->tex->nodetree)) lar->mode |= LA_OSATEX;
                }
            }
...
}

テクスチャノードの機能をテストしているときに、ノードを使ってスケールを変更するとvectexの解像度計算が正しくならないことに気がつきました。
他の操作でも同じようなことが起こる可能性がありますが、とりあえず気がついたスケールノードのソースコードについてだけ修正をしておきました。
blender/source/blender/nodes/intern/TEX_nodes/TEX_scale.c (line:43-)
static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, short thread)
{
    float scale[3], new_coord[3];
    float new_dxt[3], new_dyt[3];
    TexParams np = *p;
    np.coord = new_coord;
   
    tex_input_vec(scale, in[1], p, thread);
   
    new_coord[0] = p->coord[0] * scale[0];
    new_coord[1] = p->coord[1] * scale[1];
    new_coord[2] = p->coord[2] * scale[2];
   
    np.dxt = new_dxt;
    np.dyt = new_dyt;
    new_dxt[0] = p->dxt[0] * scale[0];
    new_dxt[1] = p->dxt[1] * scale[1];
    new_dxt[2] = p->dxt[2] * scale[2];
    new_dyt[0] = p->dyt[0] * scale[0];
    new_dyt[1] = p->dyt[1] * scale[1];
    new_dyt[2] = p->dyt[2] * scale[2];
   

    tex_input_rgba(out, in[0], &np, thread);
}
テクスチャノードについての修正は、以上のような感じです。
posted by mato at 04:40| Comment(0) | Blender Vectex | このブログの読者になる | 更新情報をチェックする
×

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