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