In cocos2d-x I need to implement fast gaussian blur and here is how it should looks like( I just found some game on the App Store with already done such blur, in unity):
So, it's nice fadeIn-fadeOut blur when user pauses the game.
GPUImage already has a fast blur I need, but I can't find solution for cocos2d-x.
v1 code when it was (GPUImage v1) Objective C
- GPUImage-x C++ version
Here is result of live camera view using GPUImage2 - tested on iPod Touch 5G, and it works fast on this slow and old device.
Blur in GPUImage works very fast even on very slow devices like iPod Touch 5G.
Looking for solution with super fast Gaussian blur for cocos2d-x.
After studying "Post-Processing Effects in Cocos2d-X" and "RENDERTEXTURE + BLUR", I came along to the following solution.
The common way to achieve post processing effects in Cocos2s-X is to implement layers. The scene is one layer, and a post process is another layer, which uses the scene layer as an input. With this technique, the post process can manipulate the rendered scene.
The blur algorithm is implemented in a shader. A common way to apply a blur effect on a scene is to blur first along he X-axis of the viewport and in an second pass along the Y-axis of the viewport (see ShaderLesson5). This is an acceptable approximations, which gives a massive gain of performance.
This means, that we need 2 post process layers in Cocos2s-X. So wee need 3 layers, one for the scene and 2 for the post processes:
Note, the sprites and resources of the scene have to be added to
m_gameLayer
.In the
updated
methode, the post processes have to be apllied to the scene (I'll describe the setup of the uniforms later):For the management of the post process I implemented a class
PostProcess
, where I tried to keep things as simple as possible:PostProcess.hpp
PostProcess.cpp
The shader needs a unifor which contains the offset for the blur algorithm (
u_blurOffset
). This is the distance between 2 pixels along the X-axis for the first blur pass and the distance between 2 texels along the Y-axis for the second blur pass.The strength of the blur effect is setup by the uniform variable (
u_blurStrength
). Where 0.0 means that blurring is off and 1.0 means maximum blurring. The maximum blur effect is defined by the value ofMAX_BLUR_WIDHT
, which defines the range of the texels wich are looked on in each direction. So this is more or less the blur radius. If you increase the value, the blur effect will increase, at the disadvantage of a loss of performance. If you decrease the value the blur effect will decrease, but you will winn performance. The relation between performance and the value ofMAX_BLUR_WIDHT
is thankfully linear (and not quadratic), because of the approximated 2 pass implementation.I decided to avoid pre calculating gauss weights and passing them to the shader (the gauss weights would depend on
MAX_BLUR_WIDHT
andu_blurStrength
). Instead I used a smooth Hermite interpolation similar to the GLSL functionsmoothstep
:blur.vert
blur.frag
The full C++ and GLSL source code can be found on GitHub (The implementation can be activated by
bool HelloWorld::m_blurFast = false
).See the preview:
Separate shader for each blur radius
A high performance version of an gaussian blur algorithm is the solution presented at GPUImage-x. In this implementation a separated blur shader for each blur radius is created. The source code of the full cocos2d-x demo implementation can be found at GitHub.The implementation provides 2 variants, the standard implementation and the optimized implementation, like the implementation in the link, which can be set up by
bool GPUimageBlur::m_optimized
. The implementation generates a shader for each radius from 0 toint GPUimageBlur::m_maxRadius
and a sigmafloat GPUimageBlur::m_sigma
.See the preview:
Fast limited quality blur
A much more powerful solution, but with obvious very low quality, would be to use the shader presented at Optimizing Gaussian blurs on a mobile GPU. The blurring is not dynamic and can only be switched on or off:
update
methode:Vetex shader:
Fragment shader
See the preview:
The full C++ and GLSL source code can be found on GitHub (The implementation can be switched by
bool HelloWorld::m_blurFast
).Progressive solution with two layers (frame buffers)
The idea of this solution is, to do a smooth, progressive, high quality blur of the scene. For this a weak, but fast and high quality blur algorithm is need. A blurry sprite is not deleted, it will be stored for the next refresh of the game engine and is used as source for the next blurring step. This means the weak blurry sprite, again gets blurry and so it is a little bit more blurry than the last one. This is a progressive process which end in a strong and exact blurred sprite.
To set up this process 3 layers are of need, the game layer and 2 blur layers (even and odd).
Note, that initially all 3 layers are invisible.
In the update` method one layer is set to state visible. If there is no blurring, then the game layer is visible. Once blurring starts, the game layer is rendered to the even layer, with the blur shader. The game layer becomes invisible and the even layer becomes visible. In the next cycle the even layer is rendered to the odd layer, with the blur shader. The even layer becomes invisible and the odd layer becomes visible. This process continues till blurring is stopped. Meanwhile, the scene becomes blurred stronger and stronger, at high quality. If the original scene has to show again, then the game layer has be set to visible and the even and odd layer have to be set invisible.
update
methode:The shader is a simple and exact 3*3 blur shader:
Vetex shader:
Fragment shader:
Again, the full C++ and GLSL source code can be found on GitHub.
See the preview: