Learning and using OpenGL Shader?

I have no clue about OpenGL and Shaders and I don’t know what would even be possible or where to start.

Would it be possible to use OpenGL Shader on a full screen background sprite with an animation like this for example: https://www.shadertoy.com/view/ldBGRR ?

Would this work on iOS and Android devices? And is there a way to use such a shader from shadertoy in Cocos2d-x?

Where to start learning about OpenGL Shaders and how to use them with Cocos2d-x (3.9)?

1 Like

Seems everything I can find on OpenGL shaders in Cocos2d-x is outdated. There is only the API reference, which doesn’t help in learning at all, and the samples, which don’t help me either. If I missed anything, I would be happy if someone could point me to the right direction?

For now just have a look at the cpp-tests ShaderTest folder. There is only a little cocos2d-x specific code you have to write, namely loading in your custom shader, setting the uniform values, and applying it to the sprite/node.

Shadertoy does have specific values that aren’t directly applicable to a cocos2d-x shader, but there are some engine shader uniform values that are provided.

In your example iGlobalTime would probably be changed to CC_Time[0] or CC_Time[1]

Example recently posted that sets up a shader and uses a different default uniform CC_Random01:

Is there any recommended book (or video?) about shaders like they are used in cocos2d-x? From what I have seen at amazon, most are either opengl ES in general with probably very little about shaders, or they are on opengl ES 3.0, which, as far as I understand, is not what I want.

Yea, your example should work in cocos2d-x, not sure about the performance, it should be interesting to test it out :smile:

as for book and tutorials, I actually think apple’s documentation is pretty good here

I got it to work - even though I have completely no idea how or why :wink: But it does work and it works actually very well and fairly fast as a background, I’m still getting 60 fps on my Moto G 1st gen even with lots of sprites movement.

I tested quite a few of the shaders. The more complicated 3d and even raytracing shaders work too, but they are way too slow, but that was expected. The simple 2d shaders like plasmas and 2d kind of shapes mostly work quite good, sometimes one need to make some adjustments and lower the quality - but just for using it as an animated background that’s perfectly fine.

However, as I have no clue what I am doing and just playing around with some values, I stumble fairly often and it was of course not my intention to just steal other code, I want to learn and make my own. I will check out the documentation from Apple.

I don’t get how to just use the current texture of a sprite?

I use this function in my code (some lines are just for testing other things, I leave them in, maybe it helps someone else who struggles to find this out, like I did):

void LayerBackground::addShader(Sprite * s) {
    auto shaderProgram = GLProgram::createWithFilenames("shaders/vertex.vsh", "shaders/test.fsh");
    shaderProgram->link();
    shaderProgram->updateUniforms();
    shaderProgram->retain();
    shaderProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
    shaderProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR);
    shaderProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORD);
    s->setGLProgram(shaderProgram);
    auto size = s->getTexture()->getContentSizeInPixels();
    auto texture = Director::getInstance()->getTextureCache()->addImage("noise.png");
    auto texturesize = texture->getContentSizeInPixels();

    s->getGLProgramState()->setUniformVec2("iResolution", size);
    s->getGLProgramState()->setUniformTexture("u_texture", s->getTexture());
    s->getGLProgramState()->setUniformTexture("iChannel0", texture);
    s->getGLProgramState()->setUniformVec2("iChannelResolution", texturesize);
}

vertex.vsh:

attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;
uniform mat4 u_MVPMatrix;

#ifdef GL_ES
varying mediump vec2 v_texCoord;
varying mediump vec4 v_fragmentColor;
#else
varying vec2 v_texCoord;
varying vec4 v_fragmentColor;
#endif

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

test.fsh:

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 iResolution; 
uniform sampler2D iChannel0;
float  iGlobalTime = CC_Time[1];
varying vec2 v_texCoord;
varying vec4 v_fragmentColor;
uniform sampler2D u_texture;

void main() {
    gl_FragColor = v_fragmentColor;   
}

I don’t get any errors, but it produces just a white texture. Shouldn’t this use the original texture of the sprite and just pass this through (I don’t mean the noise.png, that was just for testing other things, but the original sprite texture)?

1 Like

The problem lies here:

gl_FragColor = v_fragmentColor; 

You’re setting the fragment (pixel) color to the varying v_fragmentColor which seems to be white in your case. If you want to get a texel from the texture, do something like this:

gl_FragColor = texture2D(iChannel0, v_texCoord);

If you wan’t the original sprite texture:

gl_FragColor = texture2D(CC_Texture0, v_texCoord);

ah, thanks a lot. u_texture worked too, in my case.

Hello were u successful in finding examples for custom shaders in cocos2dx? Seems like I am exactly where u were a month ago… please help!

1 Like