I am planning to write quick tutorials about features in Cocos2d-x that are a bit tricky to use and are rarely (or not at all) discussed in tutorials and forums around the Internet. Basically these come from personal experience gained after not finding any good resources on the Internet. The first bunch of tutorials are going to be around the topic of shader effects (Fragment shaders), render targets and post effects.

[This tutorial is compatible with Cocos2d-x 3.1]

In this tutorial, I will go through how to use a different GLSL program (aka Shader effect) for each Cocos2d-x node.

Out of the box, each Cocos2d-x node can be set to use a different GL program. This is done by calling the setGLProgram(…) method of the desired Node object, and passing the GL program.

A GL program is defined using the GLProgram class. To configure your own GLProgram, follow these steps:

  1. Create a new GLProgram object in the memory that uses generic.vsh as the Vertex shader program and generic.fsh as the Fragment/Pixel shader:

    auto p = GLProgram::createWithFilenames("generic.vsh", "generic.fsh");
    
  2. Create a Sprite node (or any other drawable node), and pass your GLProgram to its setGLProgram(…) method:

    Sprite* dots = Sprite::create("dots.png");
    dots->setPosition(CP(0.5f, 0.5f));
    dots->setGLProgram(p);
    addChild(dots);
    

That’s basically it. But you need the generic vertex and fragment shader template files to start from there. This would be a starting point for generic.vsh:

attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;
                    
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
                                
void main()    
{                            
    gl_Position = CC_MVPMatrix * a_position;
    v_fragmentColor = a_color;
    v_texCoord = a_texCoord;
}

And for the fragment shader generic.fsh:

precision highp float;

varying vec4 v_fragmentColor;    
varying vec2 v_texCoord;
//CC_Time[1] is time, automatically updated by Cocos2d-x.

void main()            
{
    gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord);    
}

You need to put generic.vsh and generic.fsh in your Resources folder, and your job is done.

Note that in previous versions of Cocos2d-x, we needed to manually create a GLProgram object using the new keyword, and manually handle the task of deleting it. Basically making a GLProgram looks like this under-the-hood:

GLProgram* p = new GLProgram();
p->initWithFilenames("generic.vsh", "generic.fsh");
p->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
p->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR);
p->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORDS);
p->link();
p->updateUniforms();