ofxTips-JP

openFrameworksに関する様々なTipsを紹介するブログです。

ofFbo上でのアルファブレンディング

ofFboのバッファ内でアルファブレンディングを行う際、ウィンドウに直接描画するのと同じ方法ではうまくいかない場合があります。

まずはこちらのソースコードと、キャプチャをご覧ください。

ofEnableBlendMode(OF_BLENDMODE_ALPHA);
ofBackground(0, 0, 0);
ofSetColor(255, 255, 255,100);
for (int i = 0;i < 10;i++){
	ofRect(i*30, i*30, 50, 50);
}

f:id:of_tips:20130901175437p:plain

上記ソースを、ウィンドウとFboにそれぞれ描画しています。
左がウィンドウに直接描画したもの、右がFboに描画した後、ウインドウに再度描画したものです。
既に結果が違ってしまっています。アルファ値が、Fboの方が小さいように見えますが、そういうことではありません。次にウィンドウ側の背景色を変更してみます。

f:id:of_tips:20130901175826p:plain

Fbo側では黒い背景に白い四角形を描画したにも関わらず、四角形が赤みがかっています。
これはFbo自体のα値がブレンディングされてしまうため、バッファ自体が半透明になってしまっているのです。

ofEnableBlendMode(OF_BLENDMODE_ALPHA);では、内部的に以下のようなopenGLの命令を呼び出しています。

glEnable(GL_BLEND);
#ifndef TARGET_OPENGLES
	glBlendEquation(GL_FUNC_ADD);
#endif
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

RGBAについて、アルファブレンドを適用するため、始め背景色のαを最大にしても、Fboに半透明な四角形を描画した場合はその影響でFbo自体のα値が下げられてしまいます。

ではどうすればいいかというと、α値のブレンディングをアルファ合成から加算合成に変更する必要があります。
oFにそのようなメソッドは無いため、直接openGLの命令を書いてあげる必要があります。以下のように記述します。

/*ofEnableBlendMode(OF_BLENDMODE_ALPHA);と差し替える*/
glBlendFuncSeparate(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA,GL_SRC_ALPHA,GL_ONE);

通常、ブレンドの係数はglBlendFuncという命令を使っていますが、glBlendFuncSeparateではRGBのブレンド係数とαのブレンド係数を別々に指定します。
αのブレンド係数を加算にしてあげることで、後ろの背景が透けることなくFboを表示することができます。

f:id:of_tips:20130901181637p:plain
適用した状態。赤みが無くなって、後ろの赤が透けなくなったことがわかります。

ofCircleで楽に正多角形を描画する

oFでプリミティブな図形を描画する物には、

ofCircle
ofRect
ofTriangle

などなど様々な関数が用意されていますが、正方形や正三角形正以外の多角形を描画するには工夫が必要です。
まずは真面目に計算してみます。

/*中心点(center)と基準となる円の半径(radius)を定義*/
ofPoint center;
float radius = 50.0;
center.set(50,50);

/*描画*/
ofBeginShape();
for (int i = 0;i < 360;i += (360/6)){ /*360を割る数で頂点数が決まる*/
	ofVertex(center.x+cos(ofDegToRad(i))*radius,
		 center.y+sin(ofDegToRad(i))*radius);
}
ofEndShape();

これは三角関数を用いて、中心点center、半径radiusの円周上に多角形の頂点をプロットしていく方法です。
この方法で描画することもできますが、少しプログラムの行数が多くなってしまいます。

そこで、ofSetCircleResolutionを裏技的に使います。

ofSetCircleResolution(6);
ofCircle(50, 50, 50);

こうすると、たった2行で先ほどと同じように多角形を描画することができます。

実は、ofCircle命令で描画しているのは”限りなく円に近い多角形”です。
本来、より綺麗な円を描いたり、負荷を下げる目的で円の解像度を設定できるのですが、これを利用して正n角系をサクっと描くことができるわけです。

アンチエイリアシングを"無効"にする方法

openFrameworks v0.8.0以降、デフォルトでアンチエイリアシングが有効になりました。

描画が綺麗になるので嬉しい機能ですが、細かいドットを扱うような処理の場合に困ります。
1ピクセルの点を打つような処理の場合、ドットがボケて見えてしまうのです。

そこで、ofDisableAntiAliasing();を呼び出すことでアンチエイリアシングを無効にすることができます。

//--------------------------------------------------------------
void testApp::setup(){
	ofSetCircleResolution(40);
	ofBackground(0, 0, 0);

        /*アンチエイリアシングを無効に*/
	ofDisableAntiAliasing();
}

//--------------------------------------------------------------
void testApp::update(){

}

//--------------------------------------------------------------
void testApp::draw(){
        /*円と線を描画*/
	ofSetColor(255);
	ofCircle(50,50,30);
	ofSetColor(0, 0, 0);
	ofLine(0, 0, 100, 100);

        /*大量のドットを描画*/
	ofSetColor(255);
	glBegin(GL_POINTS);
	for (int i = 0;i < 100;i++){
		glVertex2f(ofRandom(100),ofRandom(100));
	}
	glEnd();
}

また、ofEnableAntiAliasing();を使って元に戻す事もでき、特定の描画のみ、アンチを無効にすることができます。

        /*円と線を描画(アンチエイリアス有効)*/
	ofEnableAntiAliasing();
	ofSetColor(255);
	ofCircle(50,50,30);
	ofSetColor(0, 0, 0);
	ofLine(0, 0, 100, 100);

        /*大量のドットを描画(アンチエイリアス無効)*/
	ofDisableAntiAliasing();
	ofSetColor(255);
	glBegin(GL_POINTS);
	for (int i = 0;i < 100;i++){
		glVertex2f(ofRandom(100),ofRandom(100));
	}
	glEnd();

以下が、実際に描画してみた結果です。

f:id:of_tips:20130901144943p:plain

ofxTips開設

本サイトは、openFrameworksに関する様々なTipsをご紹介するためのウェブサイトです。

oFは公式のドキュメンテーションがとてもよくできていて、基本的な使い方をとてもスムーズに覚えることができます。 ですが、少しマニアックなルールだったり、oF特有のクセのような物を知らないと意外なところでデバッグ時間を食ってしまったりします。

そこで、そういったニッチなTipsを、私自らが忘れないように備忘録の意味も含めてブログとしてまとめられたらと思い開設した次第です。

まだまだ記事の量は多くありませんが、是非とも活用していただいたり、メール等で”こんなTipsあるよ!”というのを教えていただけたらと思います…!