Shader GLprogram in cocos2d-x v4

Hello everyone,
I just upgraded to cocos2d-x v4.0.
I was using this code to apply a “transmission disturb” effect to my scene with a shader file:

       auto visibleSize = Director::getInstance()->getVisibleSize();

	m_pimpl->glProgram = GLProgram::createWithFilenames(vertexShaderFile, fragmentShaderFile);
	m_pimpl->glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_POSITION);
	m_pimpl->glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_COLOR);
	m_pimpl->glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORD);
	m_pimpl->glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD1, GLProgram::VERTEX_ATTRIB_TEX_COORD1);
	m_pimpl->glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD2, GLProgram::VERTEX_ATTRIB_TEX_COORD2);
	m_pimpl->glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD3, GLProgram::VERTEX_ATTRIB_TEX_COORD3);
	m_pimpl->glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_NORMAL, GLProgram::VERTEX_ATTRIB_NORMAL);
	m_pimpl->glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_BLEND_WEIGHT, GLProgram::VERTEX_ATTRIB_BLEND_WEIGHT);
	m_pimpl->glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_BLEND_INDEX, GLProgram::VERTEX_ATTRIB_BLEND_INDEX);

	m_pimpl->renderTexture = RenderTexture::create(visibleSize.width, visibleSize.height);

	m_pimpl->sprite = Sprite::createWithTexture(m_pimpl->renderTexture->getSprite()->getTexture());
	m_pimpl->sprite->setTextureRect(Rect(0, 0, m_pimpl->sprite->getTexture()->getContentSize().width,

But with the new version of cocos2d-x things have changed…
The GLProgram class was replaced by an abstract Program class.
From the “how to migrate” guide I didn’t really understand how I can change my code in the new version.
I’m not very keen in this low level stuff so i don’t understand how to do it!
I noticed that the Program class has a constructor that accept the two shader and vertex files that i was passing to the old GLProgram so I assume I can do it in some similar way.
Do I have to specialize the abstract Program class? If so, what methods do I have to implement?
It seems very hard :frowning:

P.S. If you need the complete code let me know


Can you post your vertex and fragment shader code too, or at the very least a section of them that contains all the attributes you’re using (the ones you’re passing to bindAttribLocation)? It would help figure out what it is you’re trying to do. Check this post to see if it helps in any way.

Also, are you using cocos2d-x 4.0 release, or the latest source from github? The latest code on github has some significant changes related to how the you use the shaders, along with bug fixes.

I wrote a small utility to make shaders easier to use in v4 SimpleShader

this might show you how to get things going.

I’m using the release version.
I managed to adapt my code as your link showed but I think I’m using some variables that are no longer declared:
error: 'CC_MVPMatrix' undeclared
Since I more or less copy-pasted those file without knowing what they really did I’m stuck :sweat_smile:
I’m sorry for my im-noob-pls-help post


Here are my shader and fragment files:

// Vertex
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_texCoord = a_texCoord;
    v_fragmentColor = a_color;


// Fragment
varying vec2 v_texCoord;

vec2 SineWave( vec2 p ) {

    float x;
    x = 0.03 * sin( 25.0 * p.y + CC_Random01.x * 5.0 );
    return vec2(p.x+x, p.y);

void main() {
    gl_FragColor = texture2D(CC_Texture0, SineWave(v_texCoord));

What it does is taking the entire game layer and apply those waves on it (colors remain unchanged)
This is the result:

Try u_MVPMatrix instead of CC_MVPMatrix

You should also study the code at the link that @JRCocos posted, because it may help you understand how all of this works.

These will work Cocos2d-x v4 (latest branch from the github repo):

Vertex shader:

// Vertex
attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;

varying vec4 v_fragmentColor;
varying vec2 v_texCoord;

uniform mat4 u_MVPMatrix;

void main() {
    gl_Position = u_MVPMatrix * a_position;
    v_texCoord = a_texCoord;
    v_fragmentColor = a_color;

Fragment shader:

// Fragment
varying vec2 v_texCoord;

uniform vec3 u_random;
uniform sampler2D u_texture;

vec2 SineWave(vec2 p) 
    float x;
    x = 0.03 * sin( 25.0 * p.y + u_random.x * 5.0 );
    return vec2(p.x+x, p.y);

void main() {
    gl_FragColor = texture2D(u_texture, SineWave(v_texCoord));
auto* sprite = ... // some sprite
auto* ps = CreateProgramState("waves.vert", "waves.frag");
auto randomLoc = ps->getUniformLocation("u_random");
auto randomValues = Vec3(CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1());
ps->setUniform(randomLoc, &randomValues, sizeof(randomValues));
CC_SAFE_RELEASE(ps); // required for v4 since it's retained in Sprite::setProgramState()

Thanks for your feedback!
Now my program is successfully compiled but I don’t get the same result!
I get like a blur effect:

Am I missing something?
I Also tried to ply with the sin frequency and amplitude but nothing changes.

I also get this error in console:

cocos2d: ERROR: compileProgram: failed to link program OpenGL error 0x0501 in /home/carlo/Repos/illuminaticrewthegame/cocos2d/cocos/renderer/backend/opengl/TextureGL.cpp updateData 207

I don’t think it is related because I was getting it also before re-enabling my GLProgram but I post it anyways, maybe it has something to do

I was using the stable version and I tried to change it to the one on github but, again, nothing changes

Using the modified code I posted, this is what I get when I copy the scene to a RenderTexture, and place the sprite from the RenderTexture back into the same scene:


So the problem could be in how I give the Program my texture…
How can I apply this program on a whole Layer? Not just a sprite

From the code you initially posted, I assumed you already knew how to do this, since you’re using a RenderTexture. Render whatever you need to a RenderTexture, then apply the ProgramState to that, which is what your sample code seemed to be doing.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.