在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
游戏中用到的时候, 就是把这一层, 设置一下半径. 然后加到游戏场景中去就可以了!