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

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