Gotchas! Shaders in Cocos2d-x - Fri, Jun 20, 2014
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:
- Create a new
GLProgram
object in the memory that usesgeneric.vsh
as the Vertex shader program andgeneric.fsh
as the Fragment/Pixel shader:
auto p = GLProgram::createWithFilenames("generic.vsh", "generic.fsh");
- Create a Sprite node (or any other drawable node), and pass your
GLProgram
to itssetGLProgram(…)
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();