3

私は非常に単純なグラフィックライブラリを作成しており、アルファブレンディングを行う方法を理解しようとしています。何度か試しましたが、満足のいく結果にはなりませんでした。ウィキペディアによると、私はすべきです:

値=(1-アルファ)値0+アルファ値1

ただし、これはまったく機能していません。多分私は何か間違ったことをしているのですか?

私が含めたコードは、カラフルな絵を描き(これが「近接」関数です)、次に(100,100)に部分的に透明なボックスを描画しようとします。ただし、白い半透明のボックスの代わりに、画像に奇妙な歪みが生じます(投稿の下部に配置するようにします)。助言がありますか?これが私のコードです:

#include "hgl.h"

void proximity()
{
    int x = 0, y = 0, d1, d2, d3, dcenter;

    while(x < WIDTH){
        while(y < HEIGHT){
            d1 = distance(x, y, (WIDTH/2) - 200, (HEIGHT/2) + 200);
            d2 = distance(x, y, (WIDTH/2) + 200, (HEIGHT/2) + 200);
            d3 = distance(x, y, (WIDTH/2), (HEIGHT/2) - 150);
            dcenter = distance(x, y, WIDTH/2, HEIGHT/2);
            putpixel(x, y, d1, d2, d3);
            y++;
        }
        y = 0;
        x++;
    }
}

int alpha_transparency(float alpha, float value1, float value2)
{
    return (1-alpha) * value1 + alpha * value2;
}

void transparent_box(int pos_x, int pos_y, int width, int height, float alpha, char r, char g, char b)
{
    int x = 0, y = 0;
    while(x < width)
    {
        while(y < height)
        {
            int rr, rg, rb;
            rr = alpha_transparency(alpha, p.bitmap[x+pos_x][y+pos_y].r, r);
            rg = alpha_transparency(alpha, p.bitmap[x+pos_x][y+pos_y].g, g);
            rb = alpha_transparency(alpha, p.bitmap[x+pos_x][y+pos_y].b, b);
            putpixel(pos_x + x, pos_y + y, rr, rg, rb);
            y++;
        }
        x++;
        y = 0;
    }
}

int main()
{
    fp = fopen("out.bmp","wb");

    set_dimensions(1440, 900);
    insert_header();

    white_screen();

    proximity();
    transparent_box(100, 100, 500, 500, .9, 255, 255, 255);

    insert_image();
    fclose(fp);
    return 0;
}

申し訳ありませんが、私は新しいユーザーであるため、出力を含めることができませんでした。ただし、ここにリンクがあります。

原画

「透明」ボックス付きの画像

4

3 に答える 3

2

アルファブレンド機能は正しいです。アルファブレンディングを考える別の方法は、アルファに基づいて2つのカラー値の間を補間することです。したがって、[0、1]の値である必要があります。

charただし、デフォルトで署名されているカラーコンポーネントをとして渡すことはできません。それらをより広い整数型として、またはより広い整数型として渡す必要がありますunsigned char。何が起こっているのかというと255、期待どおりに通過するのではなく、通過しているということです-1

言い換えると、色成分をunsigned charsとして保存して、signness shenanigansがないことを確認します(EDIT2を参照)。

編集:アルファが[0、255]にある場合は、アルファブレンディング操作を実行するために[0、1]に正規化する必要があることに注意してください。

charEDIT2:また、ピクセルをの代わりに保存している場合unsigned char、これは私が見た奇妙なクランプを説明します:

alpha_transparency(0.9, (char)255, (char)255)
== alpha_transparency(0.9f, -1.0f, -1.0f)
== -1.0f
== 0xff (cast to char)

alpha_transparency(0.9, (char)128, (char)255)
== alpha_transparency(0.9f, -128.0f, -1.0f)
== -13.7f
== 0xf3

alpha_transparency(0.9, (char)127, (char)255)
== alpha_transparency(0.9f, 127.0f, -1.0f)
== -11.80f
== 0x0b

alpha_transparency(0.9, (char)0, (char)255)
== alpha_transparency(0.9f, 0.0f, -1.0f)
== -0.9f
== 0x00
于 2010-07-01T22:57:41.990 に答える
0

私が思う問題は、あなたが色を扱う方法にあります。ウィキペディアで使用されている方法では、0が黒、1が白で、0.5が中央にあると想定しています。ただし、コードはintを使用しているため、0を黒、255を白として定義していると仮定します。

したがって、正しいコードは次のとおりです。

return (255-alpha)*value1+alpha*value2;

また、コンパイラの丸めに苦しんでいる可能性があります。関数のコードを次のように変更します。

float result = (255.0f-alpha)*value1+alpha*value2;
return (int) result;

一般に、intの代わりにfloatを使用して画像を操作することは非常に一般的です。今日の多くのプログラムは、画像全体をフロートに変換し、処理してから元に戻します。この方法でいくつかのバグを回避できます。

于 2010-06-30T21:12:05.460 に答える
0

すべてのfloatまたはすべての整数のいずれかの単一のデータ型に固執するのがおそらく最善です。これにより、混乱の可能性が減り、パフォーマンスの落とし穴のクラスが回避されます。

すべてのintについて、結果が元の範囲に戻るように整数を再スケーリングすることを忘れないでください。

int alpha_transparency(int alpha, int value1, int value2) {
  int unscaled= (255-alpha)*value1 + alpha*value2;
  return unscaled / 255;  /* integer division */
}

すべての浮動小数点数の場合、整数入力を[0..255](またはその他)の生の値から[0.0 .. 1.0]の浮動小数点数に正規化し、すべての処理を行ってから、整数のみに変換することを忘れないでください。最後に。

float input_raw_value(unsigned char value)  { return value/255.0; }
...
float alpha_transparency(float alpha, float value1, float value2) {
  return (1.0-alpha)*value1 + alpha*value2;
}
...
unsigned char output_raw_value(float value) { return value*255.0; }

各メソッドの丸めの問題を無視していることに注意してください。基本的な計算を開始して実行したら、それに注意を払う必要があります。また、乗算またはビット操作によって除算(比較的遅くなる可能性があります)を置き換えるためのさまざまなトリックがあります。

于 2010-07-01T22:13:27.687 に答える