WonderPlanet DEVELOPER BLOG

ワンダープラネットの開発者ブログです。モバイルゲーム開発情報を発信。

Cocos2d-x で BlendFunc

おつかれさまです。今回ブログを担当します藤澤です。

さて、Cocos2d-x ではレイヤ(ノード)を重ねて画面を作成するわけですが、ゲームですから画像を透過させてみたくなることもあります。そんなときは setOpacity を使って不透明度を変更してやってもいいのですが、BlendFunc というのを使うと、いわゆる Graphics ツールでいうところのレイヤと同じようにさまざまな合成結果を得ることができます。しかしこの BlendFunc、普段あまり使わないのでいざというときに使い方を忘れてしまいがちです。そこで今回は備忘録的に BlendFunc の使い方をまとめてみたいと思います。

まずは基本的な使い方ですが、以下のようになります。

    CCSize size = CCDirector::sharedDirector()->getWinSize();  
  
    CCLayerColor* background = CCLayerColor::create(ccc4(0, 255, 0, 255), size.width, size.height);  
    this->addChild(background, 10);  
  
    CCLayerColor* foreground = CCLayerColor::create(ccc4(0, 0, 255, 127), size.width, size.height);  
    this->addChild(foreground, 20);  
  
    ccBlendFunc blend;  
    blend.src = GL_SRC_ALPHA;  
    blend.dst = GL_ONE;  
  
    foreground->setBlendFunc(blend);  

ccBlendFunc 構造体で合成方法を指定します。おおまかにいうと背景色と前景色にそれぞれ指定した係数を掛けて加算した値が合成結果になります。(src が前景、dst が背景)
上記の例では
src が R:0, G:0, B:255, A:127
dst が R:0, G:255, B:0, A:255
GL_SRC_ALPHA は src のアルファ値 (%) = 127 ÷ 255 ≒ 0.5
GL_ONE は 1.0
ですので、
(0, 0, 255) × 0.5 + (0, 255, 0) × 1.0 = (0, 255, 127)
となり、合成結果は SpringGreen になります。

実際はこんな計算式をいちいち意識せず、代表的な係数の組み合わせを使っていくことになると思います。
以下はそのサンプルです。

アルファブレンド(規定値)

src = GL_SRC_ALPHA
dst = GL_ONE_MINUS_SRC_ALPHA

逕サ蜒十01

なにも指定しない場合、デフォルトでこの効果が適用されます。
キャラクター画像の背景部分が透過し、背景画像が表示されています。

加算

src = GL_SRC_ALPHA
dst = GL_ONE

逕サ蜒十02

いわゆる覆い焼きのような感じになります。

乗算

src = GL_ZERO
dst = GL_SRC_COLOR

逕サ蜒十03

そのままでは透明部分が無視されるため、前景画像の背景色は白にしておくとよいです。

反転

src = GL_ONE_MINUS_DST_COLOR
dst = GL_ZERO

逕サ蜒十04

これも透明度が無視されますので背景を白にしています。

スクリーン

src = GL_ONE_MINUS_DST_COLOR
dst = GL_ONE

逕サ蜒十05

排他的論理和

src = GL_ONE_MINUS_DST_COLOR
dst = GL_ONE_MINUS_SRC_COLOR

逕サ蜒十06

また、CCLayerColor で画面全体をグレーアウトさせ、一部分だけグレーアウトを解除する、といった使い方もできます。スポットライトのような効果が得られるので便利です。

    CCLayerColor* mask = CCLayerColor::create(ccc4(0, 0, 0, 128), size.width, size.height);  
    this->addChild(mask, 30);  
  
    srand((unsigned int)time(NULL));  
  
    CCDrawNode* dot = CCDrawNode::create();  
    dot->drawDot(ccp(rand() % (int)size.width, rand() % (int)size.height), rand() % 100, ccc4f(1, 1, 1, 1));  
    dot->drawDot(ccp(rand() % (int)size.width, rand() % (int)size.height), rand() % 100, ccc4f(1, 1, 1, 1));  
    dot->drawDot(ccp(rand() % (int)size.width, rand() % (int)size.height), rand() % 100, ccc4f(1, 1, 1, 1));  
    dot->drawDot(ccp(rand() % (int)size.width, rand() % (int)size.height), rand() % 100, ccc4f(1, 1, 1, 1));  
    dot->drawDot(ccp(rand() % (int)size.width, rand() % (int)size.height), rand() % 100, ccc4f(1, 1, 1, 1));  
    dot->drawDot(ccp(rand() % (int)size.width, rand() % (int)size.height), rand() % 100, ccc4f(1, 1, 1, 1));  
    dot->drawDot(ccp(rand() % (int)size.width, rand() % (int)size.height), rand() % 100, ccc4f(1, 1, 1, 1));  
    dot->drawDot(ccp(rand() % (int)size.width, rand() % (int)size.height), rand() % 100, ccc4f(1, 1, 1, 1));  
    this->addChild(dot, 40);  
  
    ccBlendFunc blend;  
    blend.src = GL_DST_COLOR;  
    blend.dst = GL_ONE;  
  
    dot->setBlendFunc(blend);  

逕サ蜒十07