1. 程式人生 > >cocos2dx系列--顏色混合BlendFunc

cocos2dx系列--顏色混合BlendFunc

一、概念
    “混合”是指兩種顏色的疊加方式。在新圖片將要渲染畫到螢幕上的時候,將用在新圖片中的紅、綠、藍和透明度資訊,與螢幕上已經存在的圖片顏色資訊相融合。
    說的具體一點,就是把某一畫素位置上原來的顏色和將要畫上去的顏色,通過某種方式混在一起,從而實現特殊的效果。
    新圖片顏色被稱作“源顏色”,而螢幕上已存在的圖片顏色則被稱作“目標顏色”。
    OpenGL會把源顏色和目標顏色各自取出,並乘以一個係數(源顏色乘以的係數稱為“源因子”,目標顏色乘以的係數稱為“目標因子”),然後相加,這樣就得到了新的顏色。


二、計算公式
    假設:顏色資訊的四個分量(紅,綠,藍,透明度)
        (1)“源顏色”  :(Rs, Gs, Bs, As)


        (2)“目標顏色”:(Rd, Gd, Bd, Ad)
        (3)“源因子”  :(Sr, Sg, Sb, Sa)
        (4)“目標因子”:(Dr, Dg, Db, Da)
    那麼混合產生的新顏色可以表示為:
        (Rs*Sr + Rd*Dr , Gs*Sg + Gd*Dg , Bs*Sb + Bd*Db , As*Sa + Ad*Da)
    如果顏色的某一分量超過了1.0,則它會被自動擷取為1.0,不需要考慮越界的問題。

三、混合因子



GL_ZERO:     表示使用0.0作為因子,實際上相當於不使用這種顏色參與混合運算。
GL_ONE:      表示使用1.0作為因子,實際上相當於完全的使用了這種顏色參與混合運算。
GL_SRC_ALPHA:表示使用源顏色的alpha值來作為因子。
GL_DST_ALPHA:表示使用目標顏色的alpha值來作為因子。
GL_ONE_MINUS_SRC_ALPHA:表示用1.0減去源顏色的alpha值來作為因子。
GL_ONE_MINUS_DST_ALPHA:表示用1.0減去目標顏色的alpha值來作為因子。


四、使用方法
    Sprite精靈類中有一個設定混合方式的函式setBlendFunc(BlendFunc),另外混合方式的屬性值是以BlendFunc結構體作為資料的,定義方式為:{ '源因子' , '目標因子' }。
    混合方式可用於精靈紋理圖片顏色資訊的混合與疊加。
看一下cocos2d-x中BlendFunc的定義,其中有兩個成員src和dst,並定義了幾種預設的混合方式。

struct CC_DLL BlendFunc
{
    //! source blend function
    GLenum src;
    //! destination blend function
    GLenum dst;

    //! Blending disabled. Uses {GL_ONE, GL_ZERO}
    static const BlendFunc DISABLE;
    //! Blending enabled for textures with Alpha premultiplied. Uses {GL_ONE, GL_ONE_MINUS_SRC_ALPHA}
    static const BlendFunc ALPHA_PREMULTIPLIED;
    //! Blending enabled for textures with Alpha NON premultiplied. Uses {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA}
    static const BlendFunc ALPHA_NON_PREMULTIPLIED;
    //! Enables Additive blending. Uses {GL_SRC_ALPHA, GL_ONE}
    static const BlendFunc ADDITIVE;

    bool operator==(const BlendFunc &a) const
    {
        return src == a.src && dst == a.dst;
    }

    bool operator!=(const BlendFunc &a) const
    {
        return src != a.src || dst != a.dst;
    }

    bool operator<(const BlendFunc &a) const
    {
        return src < a.src || (src == a.src && dst < a.dst);
    }
};
程式碼測試如下:
//test 1
	Sprite* sp1 = Sprite::create("my_test/red.png");
	sp1->setPosition(Vec2(200, 200));
	addChild(sp1);

	Sprite* sp2 = Sprite::create("my_test/green.png");
	sp2->setPosition(Vec2(220,220));
	this->addChild(sp2);

	BlendFunc cbl = { GL_SRC_ALPHA , GL_ONE };
	sp2->setBlendFunc(cbl);
	//test 2
	Sprite* sp3 = Sprite::create("my_test/red.png");
	sp3->setPosition(Vec2(300, 200));
	addChild(sp3);

	Sprite* sp4 = Sprite::create("my_test/green.png");
	sp4->setPosition(Vec2(320,220));
	this->addChild(sp4);

	BlendFunc cb2 = {GL_ZERO, GL_ONE};
	sp4->setBlendFunc(cb2);
	//test 3
	Sprite* sp5 = Sprite::create("my_test/red.png");
	sp5->setPosition(Vec2(400, 200));
	addChild(sp5);

	Sprite* sp6 = Sprite::create("my_test/green.png");
	sp6->setPosition(Vec2(420,220));
	this->addChild(sp6);

	sp6->setBlendFunc(BlendFunc::DISABLE);

測試結果如下:



如果設定了glBlendFunc(GL_ONE, GL_ZERO);,則表示完全使用源顏色,完全不使用目標顏色,因此畫面效果和不使用混合的時候一致(當然效率可能會低一點點)。如果沒有設定源因子和目標因子,則預設情況就是這樣的設定。 如果設定了glBlendFunc(GL_ZERO, GL_ONE);,則表示完全不使用源顏色,因此無論你想畫什麼,最後都不會被畫上去了。(但這並不是說這樣設定就沒有用,有些時候可能有特殊用途) 如 果設定了glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);,則表示源顏色乘以自身的alpha 值,目標顏色乘以1.0減去源顏色的alpha值,這樣一來,源顏色的alpha值越大,則產生的新顏色中源顏色所佔比例就越大,而目標顏色所佔比例則減 小。這種情況下,我們可以簡單的將源顏色的alpha值理解為“不透明度”。這也是混合時最常用的方式。 如果設定了glBlendFunc(GL_ONE, GL_ONE);,則表示完全使用源顏色和目標顏色,最終的顏色實際上就是兩種顏色的簡單相加。例如紅色(1, 0, 0)和綠色(0, 1, 0)相加得到(1, 1, 0),結果為黃色。


注意: 所 謂源顏色和目標顏色,是跟繪製的順序有關的。假如先繪製了一個紅色的物體,再在其上繪製綠色的物體。則綠色是源顏色,紅色是目標顏色。如果順序反過來,則 紅色就是源顏色,綠色才是目標顏色。在繪製時,應該注意順序,使得繪製的源顏色與設定的源因子對應,目標顏色與設定的目標因子對應。不要被混亂的順序搞暈。