ドッターがアンチエイリアスをかける時の感覚をPixel Benderで再現してみよう

アンチエイリアスの処理を行なう時に,特に重要なのはメモリ使用量と速度だ。となれば,Pixel Benderを使うしかない。

下調べで,色々なアンチエイリアスの方法があることがわかった訳だが,どの方法を取るか。スーパーサンプリングが一般的なようだが,そのためにはPixel Benderに入力する画像(フォント描画)を最低2倍にしなければならない。できればそれは避けたい。

そこでドッターがアンチエイリアスをかける時の感覚をPixel Benderで再現してみたらどうだろうと考えた。

ドット絵の解説本をいくつか当たりつつ考えるに,その感覚とは「上下左右に隣接するカラーピクセルが2つ以上ある透明ピクセルに,隣接しているカラーピクセルの中間色を割り当てる」というように見えた。

それを実装するとこうだ。

<languageVersion : 1.0;>

kernel EdgeAntiAliasFilter
<   namespace : "junkoro";
    vendor : "Masahito Ohtsuka";
    version : 1;
    description : "edge anti-aliasing filter";
>
{

    //入力画像
    input image4 src;

    //出力ピクセル
    output pixel4 dst;

#if !AIF_FLASH_TARGET

    //フィルタースイッチ
    parameter bool on
    <
        defaultValue:bool(true);
    >;

    //補完エッジ表示スイッチ
    parameter bool showEdge;

    //補完エッジピクセルカラー
    parameter pixel4 edgeColor
    <
        minValue:pixel4(0);
        maxValue:pixel4(1);
        defaultValue:pixel4(1, 0, 0, 1);
    >;

#endif

    //ピクセル処理
    void evaluatePixel() {

        //現在注目しているピクセルの位置
        float2 pos = outCoord();
        
        //3x3の行列の各要素を次のように考える
        //  LT CT RT
        //  LM CM RM
        //  LB CB RB
        
        //上段
        //pixel4 pixLT =  sampleNearest(src, pos + float2(-1, -1));
        pixel4 pixCT =  sampleNearest(src, pos + float2(0, -1));
        //pixel4 pixRT =  sampleNearest(src, pos + float2(1, -1));
        
        //中段
        pixel4 pixLM =  sampleNearest(src, pos + float2(-1, 0));
        pixel4 pixCM =  sampleNearest(src, pos + float2(0, 0));
        pixel4 pixRM =  sampleNearest(src, pos + float2(1, 0));
        
        //下段
        //pixel4 pixLB =  sampleNearest(src, pos + float2(-1, 1));
        pixel4 pixCB =  sampleNearest(src, pos + float2(0, 1));
        //pixel4 pixRB =  sampleNearest(src, pos + float2(1, 1));
  
        //透明ピクセル
        pixel4 pixNull = pixel4(0);

        //上下左右に隣接するピクセルがあれば加算しつつ隣接ピクセルカウントを増やす
        int neighborCnt = 0;
        pixel4 pix = float4(0);
        if (pixCT != pixNull) {
            neighborCnt++;
            pix += pixCT;
        }
        if (pixLM != pixNull) {
            neighborCnt++;
            pix += pixLM;
        }
        if (pixRM != pixNull) {
            neighborCnt++;
            pix += pixRM;
        }
        if (pixCB != pixNull) {
            neighborCnt++;
            pix += pixCB;
        }
        
        //透明部分でかつ上下左右に隣接するピクセルが2つ以上ある場合のみ処理

//通常コード
#if !AIF_FLASH_TARGET
        if (pixCM == pixNull && neighborCnt >= 2 && on) {
            if (showEdge) {

                //エッジカラーを出力
                dst = edgeColor;

            } else {

                //上下左右,4つのピクセルカラーの平均
                pix /= 4.0;
                
                //平均したピクセルを出力
                dst = pix;

            }
            
        }
#endif

//Flash用コード
#if AIF_FLASH_TARGET
        if (pixCM == pixNull && neighborCnt >= 2) {

            //上下左右,4つのピクセルカラーの平均
            pix /= 4.0;
            
            //平均したピクセルを出力
            dst = pix;
            
        }
#endif        
        
        else {

            //入力ピクセルをそのまま出力
            dst = pixCM;

        }

    }
    
}

一応考えたことは実現できたが,現実的なアンチエイリアス効果とはならなかった。かえって汚くなる場合もあり,まったくもって使えない。スクリーンショットを取る気も起きない(^^);

いかにFPに搭載されているSaffronが優秀であるかを実感した。

いやぁ。やおいかん。

コメント

  1. やおいかんねぇ、この問題は。もう泣こうごたるばい。

    返信削除

コメントを投稿

このブログの人気の投稿

レオナルド・ダ・ビンチはなぜノートを「鏡文字」で書いたのか?

macでsmb(samba)共有サーバーに別名で接続(別アカウント名で接続)する方法

Google DriveにCURLでアップロードするには?