一、目的
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( setFilterMat(cocos2d::Mat4matrixArray); //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(); @H_301_1059@ (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" CCASSERT(frame!=nullptr,msg); #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\ gl_Fragcolor=fiterMat*value;\n\ }"; @H_403_1265@ 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 renderer->addCommand(&_customCommand); } FilterSprite::onDraw( { autoglProgramState=getGLProgramState(); glProgramState->apply(transform); GL::blendFunc(_blendFunc.src,_blendFunc.dst); GL::bindTexture2D(_texture->getname()); GL::enabLevertexAttribs(GL::VERTEX_ATTRIB_FLAG_POS_color_TEX); #definekQuadSize sizeof (_quad.bl) @H_461_1404@ 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 glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD,2,monospace!important; Font-size:1em!important; min-height:inherit!important; background:none!important">*)(offset+diff)); //color glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_color,4,GL_UNSIGNED_BYTE,GL_TRUE,monospace!important; Font-size:1em!important; min-height:inherit!important; background:none!important">*)(offset+diff)); glDrawArrays(GL_TRIANGLE_STRIP,4); CHECK_GL_ERROR_DEBUG(); CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,4); } |
来源网址:http://www.cocoachina.com/bbs/read.php?tid-238457.html
分享到: 赞(0) 文章评论 (3) tjunxin @H_601_1502@2014-12-11 15:07:22 是不是直接继承自sprite的类想用shader都要重写draw啊? @L_502_7@ 回复(0) q312998164 @H_601_1502@2014-11-12 10:23:01 Reference to 'Rect' is ambiguous ? 这是什么错误呀 zxcvbnm0014 @H_601_1502@2014-11-11 17:16:33 Node下有个setcolor函数 实现的就是这种效果。拿setcolor传入参数 乘于像素的颜色 得到最终的效果 总结以上是内存溢出为你收集整理的在Cocos2d-x v3.x 中实现带颜色滤镜的Sprite全部内容,希望文章能够帮你解决在Cocos2d-x v3.x 中实现带颜色滤镜的Sprite所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)