1. 程式人生 > >OpenGL 顏色混合函式 glBlendFunc() 及cocos2d中的戰爭迷霧效果

OpenGL 顏色混合函式 glBlendFunc() 及cocos2d中的戰爭迷霧效果

在OpenGL中繪製的時候,有時候想使新畫的顏色和已經有的顏色按照一定的方式進行混合,比如想使物體擁有半透明的效果,或者繪製疊加光亮的效果,這時候就要用到glBlendFunc()函式。

看名字就知道,用它的原因就是,我們需要把幾種顏色通過混合來達到半透明或其它我們需要的效果。

拿半透明效果來說,已經畫了紅色和白色兩個長方形,想在上面畫一個半透明的綠色方形,則畫在紅色上的綠色其實就是綠色和紅色混合了之後的顏色:

transparent Green1 = (%a*RED+(1-%a)GREEN);

畫在白色上面的綠色是綠色和白色混合了之後的效果:

transparent Green2 = (%a*WHITE+(1-%a)GREEN);

這裡詳細的解釋一下glBlendFunc()的函式原型,各種引數的意義,以及用法。

1. 混合函式的函式原型是:

void glBlendFunc(GLenum srcfactor, GLenum destfactor); 

它的功能就控制了新畫上來的顏色(source values, RGBA),和已經在幀緩衝區的顏色(destination values, RGBA)怎麼來混合。

src是源的簡寫,dest是目標的簡寫。

2. 引數:

引數 srcfactor: 
指定了新來的顏色(source values)如何被運算。九個列舉型被接受使用: 
GL_ZERO,  
GL_ONE,  
GL_DST_COLOR, 
GL_ONE_MINUS_DST_COLOR, 
GL_SRC_ALPHA,  
GL_ONE_MINUS_SRC_ALPHA,  
GL_DST_ALPHA,  
GL_ONE_MINUS_DST_ALPHA,  
GL_SRC_ALPHA_SATURATE.

引數 destfactor: 
指定幀緩衝區的顏色(destination values)如何被運算。八個列舉型被接受使用: 
GL_ZERO,  
GL_ONE,  
GL_SRC_COLOR,  
GL_ONE_MINUS_SRC_COLOR,  
GL_SRC_ALPHA,  
GL_ONE_MINUS_SRC_ALPHA,  
GL_DST_ALPHA, 
GL_ONE_MINUS_DST_ALPHA

下表表示了每個列舉變數代表的意思:

(Rs, Gs, Bs, As) 和 (Rd, Gd, Bd, Ad) 分別表示 源顏色(src) 和 目標顏色(dest)

顏色的各個通道R, G, B, A的最大值是(kR, kG, kB, kA)

i = min (As, kA, Ad) / /kA

_________________________________________________________________________

GL_ZERO                                               |       (0,0,0,0)

GL_ONE                                                 |      (1,1,1,1)

GL_SRC_COLOR                                   |       (Rs/kR,Gs/kG,Bb/kB,As/kA)

GL_ONE_MINUS_SRC_COLOR            |       (1,1,1,1) - (Rs/kR,Gs/kG,Bs/kB,As/kA)

GL_DST_COLOR                                   |       (Rd/kR,Gd/kG,Bd/kB,Ad/kA)

GL_ONE_MINUS_DST_COLOR            |       (1,1,1,1)

GL_SRC_ALPHA                                    |      (As/kA,As/kA,As/kA,As/kA)

GL_ONE_MINUS_SRC_ALPHA             |      (1,1,1,1) - (As/kA,As/kA,As/kA,As/kA)

GL_DST_ALPHA                                    |      (Ad/kA,Ad/kA,Ad/kA,Ad/kA)

GL_ONE_MINUS_DST_ALPHA             |      (1,1,1,1) - (Ad/kA,Ad/kA,Ad/kA,Ad/kA)

GL_SRC_ALPHA_SATURATE               |      (i,i,i,1)                                                                    

---------------------------------------------------------------------------------------------------------------------

在RGB模式中,Opengl按照下面的方程來計算最後得到的顏色:(srcfactor: Sr, Sg, Sb, Sa; destfactor: Dr, Dg, Db, Da)

R (d) = min(kR,RsSr+RdDr)

G (d) = min(kG,GsSg+GdDg)

B (d) = min(kB,BsSb+BdDb)

A (d) = min(kA,AsSa+AdDa)

實現透明效果的時候,最佳引數是將不同物體從遠到近依次畫出(有時候順序很重要),並設定混合方程為:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ;

void display(void)

{

    ...

    ////draw solid models here;

    //glColor4f(1.0, 1.0, 1.0, 0.3);

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//設定混合方式

    glEnable(GL_BLEND);//啟用混合

    ////draw transparent models here;

    glDisable(GL_BLEND);//禁止混合

    ...

}

以上內容引用自:http://hi.baidu.com/zhujianzhai/blog/item/8feb9e35f3d7dfa2d1a2d37f.html

在cocos2d中, 可以用以上方法改寫一下. 實現遮罩效果 ( 模擬戰爭迷霧效果 ):

//--------------------------------------------------------------------------檔案:MaskLayer.h:

#import <Foundation/Foundation.h>

#import "cocos2d.h"

@interface MaskLayer : CCLayer {

intm_iRadius;

CCSprite* m_maskSprite;

CCRenderTexture* m_renderTexture;

CGPointm_position;

}

@property CGPoint m_position;

//設定

-(void) setRadius:( int ) p_iRadius;

-(void)  reDrawMaskBuffer ;

@end

//-----------------------------------------------------------------------檔案MaskLayer.m

//

//  MaskLayer.m

//  Butterfly

//

//  Created by chongtao rao on 11/12/11.

//  Copyright 2011 AStepGame. All rights reserved.

//

#import "MaskLayer.h"

#import "Constants.h"

@implementation MaskLayer

-( id ) init{

self = [superinit];

if( self ){

}

returnself;

}

-(void) setM_position:(CGPoint) p_position{

m_maskSprite.position = p_position;

}

-(CGPoint) m_position{

returnm_maskSprite.position;

}

-( void ) setRadius:( int ) p_iRadius{

CGSize size = [CCDirectorsharedDirector].winSize;

m_iRadius = p_iRadius;

int l_iWidth = 2*p_iRadius;

int l_iHeight = 2*p_iRadius;

unsigned char *data = malloc((l_iWidth * l_iHeight * 4));

for( int i=0; i<l_iHeight; i++ ){

for( int j=0; j<l_iWidth; j++ ){

int l_distance = sqrt(pow(i-p_iRadius, 2) + pow(j-p_iRadius, 2));

int l_iValue = (p_iRadius - l_distance)*255/p_iRadius;

limit(l_iValue, 0, 255);

for(int k=0; k<4; k++){

data[4*(i*l_iWidth+j)+k] = l_iValue;

}

}

}

CCTexture2D* l_texture = [[[CCTexture2Dalloc] initWithData:datapixelFormat:kCCTexture2DPixelFormat_RGBA8888pixelsWide:l_iWidth pixelsHigh:l_iHeightcontentSize:CGSizeMake(l_iWidth, l_iHeight)] autorelease];

m_maskSprite = [CCSpritespriteWithTexture:l_texture];

[m_maskSprite setBlendFunc:(ccBlendFunc){GL_ZERO, GL_ONE_MINUS_SRC_COLOR}];

m_renderTexture = [CCRenderTexturerenderTextureWithWidth:size.widthheight:size.height];

m_renderTexture.position= ccp(size.width/2, size.height/2);

[selfaddChild:m_renderTexture];

[selfreDrawMaskBuffer];

free(data);

}

-(void)  reDrawMaskBuffer {

[m_renderTexturebeginWithClear:0g:0b:0a:1];

if(m_maskSprite) {

[m_maskSpritevisit];

}

[m_renderTextureend];

}

-( void ) dealloc{

[superdealloc];

}

@end

遊戲中用到的時候, 就是把這一層, 設定一下半徑. 然後加到遊戲場景中去就可以了!