check this out … it just might suit your needs:
Fragment shader:
#ifdef GL_ES
precision lowp float;
#endif
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
uniform vec2 PixelSize;
uniform vec2 PixelSizeHalf;
// Kernel width 35 x 35
const int stepCount = 9;
float gWeights[stepCount] = float[](
0.10855,
0.13135,
0.10406,
0.07216,
0.04380,
0.02328,
0.01083,
0.00441,
0.00157
);
float gOffsets[stepCount] = float[](
0.66293,
2.47904,
4.46232,
6.44568,
8.42917,
10.41281,
12.39664,
14.38070,
16.36501
);
vec3 GaussianBlur9(sampler2D tex0, vec2 centreUV, vec2 halfPixelOffset, vec2 pixelOffset) {
vec3 colOut = vec3(0, 0, 0);
vec2 texCoordOffset0 = gOffsets[0] * pixelOffset;
vec3 col0 = texture(tex0, centreUV + texCoordOffset0).xyz + texture(tex0, centreUV - texCoordOffset0).xyz;
vec2 texCoordOffset1 = gOffsets[1] * pixelOffset;
vec3 col1 = texture(tex0, centreUV + texCoordOffset1).xyz + texture(tex0, centreUV - texCoordOffset1).xyz;
vec2 texCoordOffset2 = gOffsets[2] * pixelOffset;
vec3 col2 = texture(tex0, centreUV + texCoordOffset2).xyz + texture(tex0, centreUV - texCoordOffset2).xyz;
vec2 texCoordOffset3 = gOffsets[3] * pixelOffset;
vec3 col3 = texture(tex0, centreUV + texCoordOffset3).xyz + texture(tex0, centreUV - texCoordOffset3).xyz;
vec2 texCoordOffset4 = gOffsets[4] * pixelOffset;
vec3 col4 = texture(tex0, centreUV + texCoordOffset4).xyz + texture(tex0, centreUV - texCoordOffset4).xyz;
vec2 texCoordOffset5 = gOffsets[5] * pixelOffset;
vec3 col5 = texture(tex0, centreUV + texCoordOffset5).xyz + texture(tex0, centreUV - texCoordOffset5).xyz;
vec2 texCoordOffset6 = gOffsets[6] * pixelOffset;
vec3 col6 = texture(tex0, centreUV + texCoordOffset6).xyz + texture(tex0, centreUV - texCoordOffset6).xyz;
vec2 texCoordOffset7 = gOffsets[7] * pixelOffset;
vec3 col7 = texture(tex0, centreUV + texCoordOffset7).xyz + texture(tex0, centreUV - texCoordOffset7).xyz;
vec2 texCoordOffset8 = gOffsets[8] * pixelOffset;
vec3 col8 = texture(tex0, centreUV + texCoordOffset8).xyz + texture(tex0, centreUV - texCoordOffset8).xyz;
colOut += gWeights[0] * col0;
colOut += gWeights[1] * col1;
colOut += gWeights[2] * col2;
colOut += gWeights[3] * col3;
colOut += gWeights[4] * col4;
colOut += gWeights[5] * col5;
colOut += gWeights[6] * col6;
colOut += gWeights[7] * col7;
colOut += gWeights[8] * col8;
return colOut;
}
void main() {
gl_FragColor.xyz = GaussianBlur9( CC_Texture0, v_texCoord, PixelSize, PixelSizeHalf );
gl_FragColor.w = 0.05;
}
then in cocos2d :
spr = Sprite::create("badland.png");
spr->retain();
spr->setPosition(center);
auto texSize = spr->getTexture()->getContentSizeInPixels();
std::string fragSource1 = FileUtils::getInstance()->getStringFromFile(FileUtils::getInstance()->fullPathForFilename("frag1.fsh"));
auto prog1 = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource1.data());
auto programState1 = GLProgramState::getOrCreateWithGLProgram(prog1);
auto prog2 = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource1.data());
auto programState2 = GLProgramState::getOrCreateWithGLProgram(prog2);
programState1->setUniformVec2("PixelSize", Vec2(1.f / texSize.width, 0));
programState1->setUniformVec2("PixelSizeHalf", Vec2(0.5 / texSize.width, 0));
programState2->setUniformVec2("PixelSize", Vec2(0, 1.f / texSize.height));
programState2->setUniformVec2("PixelSizeHalf", Vec2(0, 0.5 / texSize.height));
rtA = RenderTexture::create(winSize.width, winSize.height);
rtA->retain();
rtA->getSprite()->setGLProgramState(programState1);
rtA->getSprite()->setPosition(center);
rtB = RenderTexture::create(winSize.width, winSize.height);
this->addChild(rtB);
rtB->getSprite()->setGLProgramState(programState2);
rtB->getSprite()->setPosition(center);
spr->getTexture()->setAntiAliasTexParameters();
rtA->getSprite()->getTexture()->setAntiAliasTexParameters();
rtB->getSprite()->getTexture()->setAntiAliasTexParameters();
const int downScale = 8;
spr->setScale(spr->getScale() / downScale);
rtB->getSprite()->setScale(rtB->getSprite()->getScale() * downScale);
rtA->beginWithClear(0, 0, 0, 0);
spr->visit();
rtA->end();
rtB->beginWithClear(0, 0, 0, 0);
rtA->getSprite()->visit();
rtB->end();
Original img:
Blurred img:
i tried it in an update loop like this and it runs at 60fps!!
void GameScene::update(float dt) {
rtA->beginWithClear(0, 0, 0, 0);
spr->visit();
rtA->end();
rtB->beginWithClear(0, 0, 0, 0);
rtA->getSprite()->visit();
rtB->end();
}
and if you are curious … the shader is from here (zip file):
PS: am not an expert in shaders but i think the fragment shader can be improved even more by making the arrays uniform instead of initializing theme each time.