Trying to implement bloom shader but its not working WHY?

Trying to implement bloom shader but its not working WHY?
0.0 0

#1
//-----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.


#2

bump? any one?


#3

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:


#4

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.


#5

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?


#6
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()->...

#7
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?


#8

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


#9

still same error! How do you guys do it?


#10

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.


#11

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);
}

#12

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:


#13

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


#14

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.


#15

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);


#16

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.


#17

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);