在Cocos2d-x v3.x 中实现带颜色滤镜的Sprite

前端之家收集整理的这篇文章主要介绍了在Cocos2d-x v3.x 中实现带颜色滤镜的Sprite前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

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;
@H_403_97@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回调时调用

1
glProgramState->setUniformMat4( "fiterMat" ,m_uSpriteFilter)

四、使用

使用起来非常简单,只需要设置一个颜色矩阵,例如,如果要变灰就设置一个灰度矩阵,如果要恢复原貌就设置一个单位矩阵。

11
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:

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@H_879_301@ 41
42
43
44
/****************************************************************************
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);
@H_403_438@ 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:

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/****************************************************************************
****************************************************************************/
"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;
}
@H_403_438@ 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" 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\
}";
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_264_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_710_1502@2014-12-11 15:07:22
    是不是直接继承自sprite的类想用shader都要重写draw啊?
  • q312998164 @H_710_1502@2014-11-12 10:23:01
Reference to 'Rect' is ambiguous ? 这是什么错误
zxcvbnm0014 @H_710_1502@2014-11-11 17:16:33
Node下有个setColor函数 实现的就是这种效果。拿setcolor传入参数 乘于像素的颜色 得到最终的效果
原文链接:https://www.f2er.com/cocos2dx/345281.html

猜你在找的Cocos2d-x相关文章