Trying to implement bloom shader but its not working WHY?

//-----All graphics layer
_allGraphics = new AllGraphics(_loadLevel);
this->addChild(_allGraphics);

auto gl_cache = GLProgramCache::getInstance();
std::string fragSource = FileUtils::getInstance()->getStringFromFile(FileUtils::getInstance()->fullPathForFilename("shader/example_Bloom.fsh"));
auto program = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource.data());

program->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
program->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR);
program->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORDS);
program->link();
program->updateUniforms();
program->use();
gl_cache->addGLProgram(program, "bloom");
auto glProgramState = GLProgramState::getOrCreateWithGLProgram(program);

_allGraphics->setShaderProgram(program);
_allGraphics->setGLProgramState(glProgramState);

It renders the whole scene as it is.

bump? any one?

i dont know about you but it works fine for me … and all what i did is copy the example_Bloom.fsh to the Resources folder and just do this:

std::string fragSource = FileUtils::getInstance()->getStringFromFile(FileUtils::getInstance()->fullPathForFilename("example_Bloom.fsh"));
auto prog = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource.data());
auto programState = GLProgramState::getOrCreateWithGLProgram(prog);

spr = Sprite::create("HelloWorld.png");
spr->setPosition(center);
this->addChild(spr);
spr->setGLProgramState(programState);

check the fragment shader path maybe it is incorrect?

and here is the shader result:

1 Like

wooow! lucky u got it just like that. which version of cocos? I have .csb file and i want to apply to the layer which will be over graphics layer.

LOL! my bunch of lines waste. your simple code works on the sprite for me too thanx a lot bro :slight_smile:
but now it works on single sprite how do i make it work on whole .csb scene file?

virtual void setGLProgramState(GLProgramState *glProgramState);

This function is a member of Node, therefore since Scene derives from Node you should be able to call it on the scene itself:

Director::getInstance()->getRunningScene()->...
auto gl_cache = GLProgramCache::getInstance();
std::string fragSource = FileUtils::getInstance()->getStringFromFile(FileUtils::getInstance()->fullPathForFilename("example_Bloom.fsh"));
auto prog = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource.data());
gl_cache->addGLProgram(prog, "bloom");
auto programState = GLProgramState::getOrCreateWithGLProgram(prog);

Director::getInstance()->getRunningScene()->setGLProgram(gl_cache->getGLProgram("bloom"));
Director::getInstance()->getRunningScene()->setGLProgramState(programState);

Exception thrown at 0x00BAFFEB in xyz.exe: 0xC0000005: Access violation reading location 0x00000000.
why its point to null object?

try putting the code in Scene::onEnter() method!

still same error! How do you guys do it?

On your Scene init(on which you want to apply this shader), try schedeOnce to be executed[quote=“MatrixAndrew, post:6, topic:38027”]
Director::getInstance()->getRunningScene()->…
[/quote]

after 0.1 seconds, I believe [quote=“gplayers, post:7, topic:38027”]
Exception thrown at 0x00BAFFEB in xyz.exe: 0xC0000005: Access violation reading location 0x00000000.
[/quote]

is because init() hasn’t returned yet from scene so logically there is no running scene yet for renderer.

This idea clears some logic. And now no errors. But it doesnt render the shader…here is the implementation

//---setting opengl shader "bloom"
gl_cache = GLProgramCache::getInstance();
std::string fragSource = FileUtils::getInstance()->getStringFromFile(FileUtils::getInstance()->fullPathForFilename("example_Bloom.fsh"));
GLProgram* prog = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource.data());
gl_cache->addGLProgram(prog, "bloom");
programState = GLProgramState::getOrCreateWithGLProgram(prog);

this->scheduleOnce(SEL_SCHEDULE(&MainScene::onEnter), 0.1);

return true;
}

void MainScene::onEnter(float dt)
{
	Director::getInstance()->getRunningScene()->setGLProgram(gl_cache->getGLProgram("bloom"));
	Director::getInstance()->getRunningScene()->setGLProgramState(programState);
}

i think for now your best bet is this:

// in Scene or Layer init method
// setGLProgramState for each node separately
for(auto node: scene->getChildren()){
	if(node == what am looking for){
		node->setGLProgramState(programState);
	}
}

i too tried putting some sprites in a sprite node as a container and apply the shader on the sprite container but even with that is didnt work

i also tried the same idea for scene and layer and even for layer color and Layer Gradient and still didn’t work.

i also advise you to check this post as it has some great ideas on how to apply a shader to a whole scene:

Well, Thanks for your interest and reply. I will look after FBO than.

Great, i have learned this:

	const cocos2d::Size size = Director::getInstance()->getWinSizeInPixels();
	cocos2d::experimental::FrameBuffer* frameBuffer = cocos2d::experimental::FrameBuffer::create(1, size.width, size.height);
	cocos2d::experimental::RenderTarget* renderTarget = cocos2d::experimental::RenderTarget::create(size.width, size.height);

auto camera = new Camera;
camera->initDefault();
camera->setCameraFlag(CameraFlag::DEFAULT);
camera->setDepth(-1);
camera->setFrameBufferObject(frameBuffer);
this->addChild(camera);

frameBuffer->attachRenderTarget(renderTarget);

cocos2d::Texture2D* texture = frameBuffer->getRenderTarget()->getTexture();

cocos2d::Sprite* sprite = cocos2d::Sprite::createWithTexture(texture);

sprite->setGLProgram(cocos2d::GLProgram::createWithFilenames("generic.vert", "color_transition.frag"));
sprite->setFlippedY(true);
sprite->setPosition(cocos2d::Vec2(size.width *0.5, size.height *0.5));
sprite->setZOrder(15);
sprite->setGlobalZOrder(15);
auto rotateTo = RotateTo::create(3.0f, Vec3(0.0f, 240.0f, 0.0f));
sprite->runAction(rotateTo);
this->addChild(sprite);

at the place sprite->runAction(rotateTo) makes clear that we are creating another render object over our default one.

What i want to do, can we get default rendering texture from default frame buffer? so it wont render double time.

void Shared::BloomRecursive(cocos2d::Node *_node, bool _bloom)
{
if(_blur)
{
auto glprogramstate = GLProgramState::getOrCreateWithGLProgram(GLProgram::createWithFilenames(“res/shader/SpriteShine.vsh”,“res/shader/bloom.fsh”));
_node->setGLProgramState(glprogramstate);

}
else{
    _node->setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP));

}

auto& children = _node->getChildren();
for (size_t i = 0; i < children.size(); i++)
{
    BloomRecursive(children.at(i), _blur);
}

}

go to your scene… call it like this

Shared::BloomRecursive(this,true);

well thanx for sharing the idea. you mean calling this method again and again till number of children are inside my scene .csb file. In that case i should put GLProgram on cache. well i had this option in mind but I thought this could be costly in perfomance. well, i will have to test, which one better framebuffer or your this for loop.I will try this with GLProgram on cache. thanx again.

Instead of

auto camera = new Camera;
camera->initDefault();
camera->setCameraFlag(CameraFlag::DEFAULT);

do

auto camera = Camera::create();
camera->setCameraFlag(CameraFlag::USER1);
camera->setDepth(-1);

set your other sprites to that mask (not the sprite of your framebuffer which keeps the default)

helloworldsprite->setCameraMask((unsigned short)CameraFlag::USER1);