文章目录
  1. 1. blur精灵
  2. 2. shader

有的时候为了使画面效果更为柔和,会引入一个模糊的特效。
比如人物以特别快的速度从一个点移动到相对较短的另一个点,又或者人物
身上有某种buff效果。这样的效果一般模糊的方向与运动方向相同。
举个例子就是大多数飞机游戏通关过后会有的那个加速模糊的效果。
我列举一个简单的水平方向模糊的精灵的实现过程,先上结果。

blurSprite

blur精灵

从Sprite中派生出来,做好初始化函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

class GridSprite : public Sprite {
public:

GridSprite();
~GridSprite();

static GridSprite* create(std::string filename);
virtual bool init(std::string filename);
virtual void update(float dt);

void moveToPositon(Vec2 pos);

CC_SYNTHESIZE(float, _speed, Speed);
CC_SYNTHESIZE(Vec2, _targetPos, TargetPos);
CC_SYNTHESIZE(bool, _isMove, IsMove);
CC_SYNTHESIZE(int, _enable, Enable);

void unuse();

private:

Animation* _animation;
GLProgramState* _glProgramState;
bool _isUse;

};

1
2
3
4
5
6
7
8
9
10
11
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
41
42
43
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
#include "GridSprite.h"
#define FLOAT_ZERO 0.000001

GridSprite::GridSprite()
:_speed(3.0)
,_animation(0)
,_glProgramState(0)
,_isMove(false)
,_isUse(false)
,_enable(1)
{
_targetPos = Vec2(0,0);
}

GridSprite::~GridSprite()
{
CC_SAFE_RELEASE(_animation);
}

GridSprite* GridSprite::create(std::string filename)
{
GridSprite* pRef = new GridSprite();
if (pRef && pRef->init(filename))
{
pRef->autorelease();
}
else
{
CC_SAFE_DELETE(pRef);
}
return pRef;
}

bool GridSprite::init(std::string filename)
{
if (!Sprite::initWithFile(filename)) {
return false;
}

auto winSize = Director::getInstance()->getWinSize();

//program
auto _program = GLProgram::createWithFilenames("blur.vert", "blurx.frag");
_glProgramState = GLProgramState::getOrCreateWithGLProgram(_program);
_glProgramState->setUniformVec2("u_resolution",winSize);
_glProgramState->setUniformInt("u_enable",0);
setGLProgramState(_glProgramState);
setGLProgram(_program);

//animation
char str[100]={0};
_animation = Animation::create();
for(int i = 1;i < 9 ; i++)
{
sprintf(str,"hero_run%d.png",i);
_animation->addSpriteFrameWithFile(str);
}
_animation->setDelayPerUnit(0.2f);
_animation->setLoops(-1);
_animation->retain();

scheduleUpdate();

return true;
}

void GridSprite::update(float dt)
{
if (!_isUse) {
return;
}
if (abs(getPositionX() - _targetPos.x) > FLOAT_ZERO + _speed)
{
_glProgramState->setUniformInt("u_enable",_enable);
setPositionX(getPositionX() + _speed);
if (!_isMove) {
runAction(Animate::create(_animation));
_isMove = true;
}
}
else
{
_glProgramState->setUniformInt("u_enable",0);
stopAllActions();
_isMove = false;
}
}

void GridSprite::moveToPositon(cocos2d::Vec2 pos)
{
_targetPos = pos;
_isUse = true;
}

void GridSprite::unuse()
{
_isUse = false;
}

在这里类中,Animation应该是在类的外面初始化并在create时传入。
我为了尽快实现效果手懒了一下。

移动我以最简单的方式呈现到了代码中,将目的地储存在类中,每一帧做
判断并更新位置。

shader

Vertex Shader中没有什么特别的,可以使用引擎自己的。注意置换矩阵使用
CC_PMatrix。
模糊实现的原理是对于某一像素取出相邻的一些像素的color平均值。
这个例子是实现水平方向模糊的,在左右取一些点的平均值即可。

1
2
3
4
5
6
7
8
9
10
11
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

#define N 40

varying vec2 v_texCoord;
varying vec4 v_color;

uniform vec2 u_resolution;
uniform int u_enable;

vec4 verticalBlur(sampler2D t, vec2 p)
{
vec4 sum = vec4(0.0);
int count = 0;
vec2 delta = vec2(1.0, 1.0) / u_resolution.xy;
//int n = int(abs(float(N) * cos(CC_Time[1])));
int n = N;
for (int i = -n; i <= n; i++)
{
vec2 uv;
uv.x = p.x - float(i) * delta.x;
uv.y = p.y;
if (uv.x < 0.0 || uv.x > 1.0)
continue;
sum += texture2D(t, uv);
count ++;
}
return sum / float(count);
}

void main()
{
if (u_enable == 1)
{
gl_FragColor = verticalBlur(CC_Texture0, v_texCoord);
}
else
{
gl_FragColor = texture2D(CC_Texture0, v_texCoord);
}
}

这里如果使用一张大图作为纹理创建帧动画,会出现意外状况。
原因是shader中v_texCoord的x与y是0.0-1.0的值。
在大图的情况,会对整个大图模糊后再取当前动画大小的那一部分,
这就可能会出现精灵的边界出现相邻的另一个部分的颜色值。

例子只是仅仅实现了效果,具体使用要慎重。

代码地址:https://github.com/JackLN/ShaderDemo.git

文章目录
  1. 1. blur精灵
  2. 2. shader