CocoaChina论坛2014-11-10 16:38:251358 次阅读
一、目的
Cocos2d-x做项目时经常会碰到要对图片进行变色的需求,最常用的就是变灰了,就要让按钮变灰来表示当前的状态是不可点的。 但是Cocos2d-x的Sprite中是没有这个变灰支持的。那么,就要我们自己动手来扩展实现一个。我们让这个带变色功能的Sprite叫做FilterSprite。这个FilterSprite扩展了Sprite的功能:可以方便地变换颜色。
二、原理
对图片进行颜色变换,就是对图片上的每个像素进行变换。要实现这个,要新创建一个fragmentShader,这个fragmentShader 比sprite的那个fragmentShader多了一个颜色变换矩阵。shader会让图片上每个像素与颜色变换矩阵进行相乘,输出新的像素值。
这个shader是这样的:
1
2
3
4
5
6
7
8
9
10
11
12
|
#ifdefGL_ES
precisionmediump
float
;
#endif
uniformsampler2Du_texture;
varyingvec2v_texCoord;
varyingvec4v_fragmentColor;
uniformmat4fiterMat;
void
main(
)
{
vec4value=v_fragmentColor*texture2D(u_texture,v_texCoord);
gl_FragColor=fiterMat*value;
};
|
从shader上我们看到,“filterMat” 就是所谓的颜色变换矩阵,仅仅在原来像素输出前用它处理了一下:与待输出像素相乘。 这个shader是opengl层级的,要应用到coco2dx引擎中,我们要着手实现cocos2dx的FilterSprite类了。
三、实现
实现这个FilterSprite注意几个要点:
引擎中一个shader对应一个GLProgram,所以这个带颜色滤镜的shader(称为filterShader)对应一个GLProgram(称为filterProgram)对象,在实际使用时,是用对GLProgram进行了封装的GLProgramState(称为filterProgramState)对象,FilterSprite对象的_glProgramState要设置成filterProgramState对象,在源码中FilterSprite的initWithTexture进行这个filterShader和filterProgram的关联。
在渲染时要将滤镜传递给shader程序,在源码中就是在onDraw回调时调用:
glProgramState->setUniformMat4(
"fiterMat"
,m_uSpriteFilter)
|
四、使用
使用起来非常简单,只需要设置一个颜色矩阵,例如,如果要变灰就设置一个灰度矩阵,如果要恢复原貌就设置一个单位矩阵。
Sprite*_sprite1;
_sprite1=FilterSprite::create(
"Images/background3.png"
);
GLfloatfilterMat[16]={
0.3f,0.3f,0.0f,
0.59f,0.59f,
0.11f,0.11f,
0.0f,1.0f,
};
dynamic_cast
<FilterSprite*>(_sprite1)->setFilterMat(filterMat);
|
五、源码
FilterSprite.h:
/****************************************************************************
FilterSpirte.h
CreatedbyLiaoYanXuanon14-10-21.
****************************************************************************/
#ifndef__FilterSpirte_h
#define__FilterSpirte_h
#include
"cocos2d.h"
USING_NS_CC;
class
FilterSprite:
public
Sprite{
:
FilterSprite();
virtual
~FilterSprite();
static
FilterSprite*create();
FilterSprite*create(
const
std::string&filename);
std::string&filename,
Rect&rect);
FilterSprite*createWithTexture(Texture2D*pTexture);
FilterSprite*createWithTexture(Texture2D*pTexture,monospace!important; font-size:1em!important; min-height:inherit!important; background:none!important">Rect&rect,
bool
rotated=
false
);
FilterSprite*createWithSpriteFrame(SpriteFrame*pSpriteFrame);
FilterSprite*createWithSpriteFrameName(
std::string&spriteFrameName);
initWithTexture(Texture2D*pTexture,monospace!important; font-size:1em!important; min-height:inherit!important; background:none!important">Rect&tRect);
virtual
draw(Renderer*renderer,monospace!important; font-size:1em!important; min-height:inherit!important; background:none!important">Mat4&transform,uint32_tflags)override;
onDraw(
//to-do提供一个设置滤镜的方法
protected
:
CustomCommand_customCommand;
private
:
cocos2d::Mat4m_uSpriteFilter;
};
#endif
|
FilterSprite.cpp:
/****************************************************************************
****************************************************************************/
"FilterSprite.h"
FilterSprite::FilterSprite(
)
{
m_uSpriteFilter=Mat4::IDENTITY;
}
FilterSprite::~FilterSprite()
{
}
FilterSprite*FilterSprite::create()
{
FilterSprite*sprite=
new
(std::
nothrow
)FilterSprite();
if
(sprite&&sprite->init())
{
sprite->autorelease();
return
sprite;
}
CC_SAFE_DELETE(sprite);
nullptr;
}
FilterSprite*FilterSprite::create(
std::string&filename)
{
)FilterSprite();
(sprite&&sprite->initWithFile(filename))
{
sprite->autorelease();
sprite;
}
CC_SAFE_DELETE(sprite);
nullptr;
}
Rect&rect)
{
)FilterSprite();
(sprite&&sprite->initWithFile(filename,rect))
{
sprite->autorelease();
sprite;
}
CC_SAFE_DELETE(sprite);
nullptr;
}
FilterSprite*FilterSprite::createWithTexture(Texture2D*pTexture)
{
)FilterSprite();
Rectrect=Rect::ZERO;
rect.size=pTexture->getContentSize();
(sprite&&sprite->initWithTexture(pTexture,rect))
{
sprite->autorelease();
sprite;
}
CC_SAFE_DELETE(sprite);
nullptr;
}
FilterSprite*FilterSprite::createWithTexture(Texture2D*texture,monospace!important; font-size:1em!important; min-height:inherit!important; background:none!important">rotated)
{
)FilterSprite();
(sprite&&sprite->initWithTexture(texture,rect))
{
sprite->autorelease();
sprite;
}
CC_SAFE_DELETE(sprite);
nullptr;
}
FilterSprite*FilterSprite::createWithSpriteFrame(SpriteFrame*spriteFrame)
{
)FilterSprite();
(sprite&&spriteFrame&&sprite->initWithSpriteFrame(spriteFrame))
{
sprite->autorelease();
sprite;
}
CC_SAFE_DELETE(sprite);
nullptr;
}
FilterSprite*FilterSprite::createWithSpriteFrameName(
std::string&spriteFrameName)
{
SpriteFrame*frame=SpriteFrameCache::getInstance()->getSpriteFrameByName(spriteFrameName);
#
COCOS2D_DEBUG>0
char
msg[256]={0};
sprintf
(msg,
"InvalidspriteFrameName:%s"
#endif
createWithSpriteFrame(frame);
}
FilterSprite::initWithTexture(Texture2D*pTexture,monospace!important; font-size:1em!important; min-height:inherit!important; background:none!important">Rect&tRect){
do
{
CC_BREAK_IF(!Sprite::initWithTexture(pTexture,tRect));
GLchar*pszFragSource=
"#ifdefGL_ES\n\
;\n\
#endif\n\
uniformsampler2Du_texture;\n\
varyingvec2v_texCoord;\n\
varyingvec4v_fragmentColor;\n\
uniformmat4fiterMat;\n\
)\n\
{\n\
}";
autoglprogram=GLProgram::createWithByteArrays(ccPositionTextureColor_vert,pszFragSource);
autoglprogramstate=GLProgramState::getOrCreateWithGLProgram(glprogram);
setGLProgramState(glprogramstate);
CHECK_GL_ERROR_DEBUG();
return
true
;
}
while
(0);
;
}
FilterSprite::setFilterMat(cocos2d::Mat4matrixArray)
{
m_uSpriteFilter=matrixArray;
}
FilterSprite::draw(Renderer*renderer,uint32_tflags)
{
_customCommand.init(_globalZOrder);
_customCommand.func=CC_CALLBACK_0(FilterSprite::onDraw,153)!important; background:none!important">this
}
FilterSprite::onDraw(
autoglProgramState=getGLProgramState();
GL::blendFunc(_blendFunc.src,_blendFunc.dst);
GL::bindTexture2D(_texture->getName());
GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POS_COLOR_TEX);
#definekQuadSize
sizeof
(_quad.bl)
size_t
offset=(
)&_quad;
//vertex
int
diff=offsetof(V3F_C4B_T2F,vertices);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION,3,GL_FLOAT,GL_FALSE,kQuadSize,(
*)(offset+diff));
//texCoods
//color
glDrawArrays(GL_TRIANGLE_STRIP,4);
CHECK_GL_ERROR_DEBUG();
CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,4);
}
|
文章评论 (3)