How can I add a post process shader?

Hello. How can I add a post process shader which changes the contrast of all scene?
I tried to figure out in FrameBuffer, RenderTarget, but I couldn’t find an examle with a similar shader.

Hi.

It’s pretty hard if you did not try to read cocos2d-x source code but I will try to help you.
First of all there are 2 ways to do it but any of them is pretty similar.

  1. You can render all the scene to the texture by using RenderTexture;
  2. You can render all the scene to the texture by using FrameBuffer.

Examples (untested):
1 (RenderTexture).auto render = RenderTexture::create(width, height); render->begin(); scene->visit(); render->end(); // TODO: You've got a texture: render->getSprite()->getTexture();
2. (FrameBuffer)auto buffer = FrameBuffer::create(1, width, height); auto target = RenderTarget::create(width, height); auto camera = ... buffer->attachRenderTarget(target); camera->setFrameBuffer(buffer); ... // TODO: You've got a texture: frame->getTarget()->getTexture();

So now you have got a texture with whole scene and all scene elements and you can easily apply any shader to this texture.

Example:
GLProgramCache::getInstance()->addGLProgram( GLProgram::createWithFilenames("shader.vert", "shader.frag"), "@shader" ); auto sprite = Sprite::create(texture); sprite->setGLProgram( GLProgramCache::getInstance()->getGLProgram("@shader") );

Feel free to ask any questions.
Good luck :slight_smile:

4 Likes

Thank you, really. I used the way with FrameBuffer and it helped me. But now I have 1 small problem.

A resolution of the new sprite with a shader is lower than window resolution. It is 200320, because 200320 - the virtual base resolution of our game. But it should be 400640, when еру game’s window is 400640.

It’s a part of my code from AppDelegate.cpp:
auto director = Director::getInstance();

auto glview = director->getOpenGLView();

if (!glview){
	if (cocos2d::TargetPlatform::OS_ANDROID == cocos2d::Application::getTargetPlatform())
		glview = GLViewImpl::createWithFullScreen("Game");
	else {
		glview = GLViewImpl::create("Game");
		glview->setFrameSize(Settings::DesktopScreenWidth, Settings::DesktopScreenHeight);
	}

	director->setOpenGLView(glview);
}

glview->setDesignResolutionSize(Settings::VirtualScreenWidth, Settings::VirtualScreenHeight, ResolutionPolicy::FIXED_WIDTH);
director->setClearColor(BACKGROUND_COLOR);
director->setAnimationInterval(1.0 / 60.0);

It’s a part of my code from GameScene.cpp (the main scene):

const cocos2d::Size size = cocos2d::Size(Settings::VirtualScreenWidth, Settings::VirtualScreenHeight);
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);

cocos2d::Camera* defaultCamera = cocos2d::Camera::getDefaultCamera();

cocos2d::Camera* camera = cocos2d::Camera::create();

frameBuffer->attachRenderTarget(renderTarget);
camera->setFrameBufferObject(frameBuffer);
camera->setZOrder(15);
camera->setGlobalZOrder(15);
mainLayer_->addChild(camera);

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(Settings::VirtualScreenWidth*.5, Settings::VirtualScreenHeight*.5));
sprite->setZOrder(15);
sprite->setGlobalZOrder(15);
addChild(sprite);

Please try to use this size for FrameBuffer and RenderTarget:
const cocos2d::Size size = Director::getInstance()->getWinSizeInPixels();