[Solved] Passing a Variable to a Shader

I have a shader working that I can use to manipulate the colors of a sprite, but I am struggling to pass values to variables within the shader. Whenever I call setUniformVec2, I get the error Uniform not found.

I load the shader through
GLProgram* prog = GLProgram::createWithFilenames("res/shader.vsh", "res/shader.fsh");

I create the GLProgramState through
auto progState = GLProgramState::getOrCreateWithGLProgram(prog);

I set the program state with the sprite through
sprite->setGLProgramState(progState);

This works fine without trying to pass a variable. But when I call progState->setUniformVec2("u_point", Vec2(0, 0)); I get the Uniform not found error.

The vertex shader file contains
uniform vec2 u_point;

Is there something I have to do for cocos2d-x to register the uniform for setting it?

Thanks.

I think that you should be more specific with your code.

Can you copy paste the lines exactly as they are in your code?

Probably you are missing to explain something so with a C&P will be easier to help you.

HelloWorldScene.cpp:

bool HelloWorld::init() {   
    if ( !Layer::init() )
    {
        return false;
    }
    
    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();
    
    auto spr = Sprite::create("HelloWorld.png");
    addChild(spr, 0);
    spr->setPosition({ origin.x + visibleSize.width / 2, origin.y + visibleSize.height / 2 });
    spr->setScale(2);

    GLProgram* prog = GLProgram::createWithFilenames("res/shader.vsh", "res/shader.fsh");
    GLProgramState* state = GLProgramState::getOrCreateWithGLProgram(prog);
    spr->setGLProgramState(state);

    state->setUniformVec2("u_point", Vec2(0.0f, 0.0f));

    return true;
}

shader.vsh:

attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord;

varying vec2 v_texCoord;

uniform vec2 u_point;

void main()
{
    gl_Position = CC_PMatrix * a_position;
    
    v_texCoord = a_texCoord;
    v_point = u_point;
}

shader.fsh:

varying vec2 v_texCoord;

void main()
{
    vec4 col = texture2D(CC_Texture0, v_texCoord);
    col.r = 0.5;
    gl_FragColor = col;
}

HelloWorldScene.cpp also contains a createScene function, but it’s unchanged from the standard code when creating a new project.

Yeah maybe copy/paste exact code plus frag shader. Looks like normal “should be working” code for attaching shader w/uniform. You can confirm it’s not finding/reading uniform correctly by breakpoint in GLProgram::parseUniforms.

Might be a simple resource issue. If XCode is it inside a blue folder or yellow group? Have you saved the .fsh file? etc.

You don’t declare v_point, are you sure the shader is even compiling?

It’s working now. I have no idea how… I spent a couple hours on this, and I don’t think I did anything differently this time.

I really wish I could find a proper tutorial for shaders so it would be a lot easier to figure out and now run into these sorts of problems.

Oh well, thanks for your help anyway, guys.

Oh, sorry. Was copying from around commented code so was hoping I didn’t make any mistakes.

No worries. Shaders are a pain to debug for sure. Not sure what kinda tutorial you’re looking for? One can wrap up some of this stuff and you can make it based on conventions. The semi-new Material system designed mostly for 3D could be abstracted a bit further to maybe help with making shader attachment less error prone by allowing one to say what #defines, uniforms, and attributes exist for a given shader in a more declarative manner.

If you have ideas request them here, or on the docs github issues, etc. :smiley:

I just want a step-by-step guide. “Step 1: Here is the necessary code for your shader to compile. Step 2: Here is the code to load in into your cocos2d-x project and apply it to a node.” Plus any other steps that would be useful for basic tasks. Also, an overview of the cocos2d-x specific variables, such as CC_Texture0.

I just want a step-by-step tutorial to get a simple shader up and running, so it’s easy to start playing around. It took me a while just to find code that allows me to load a shader, apply it to a sprite and get the sprite to show.

The cocos2d-x programmer’s guide is underwhelming because it doesn’t tell you how to load a shader or turn it into a GLProgram. I would also love examples of simple shaders to help figure out how shaders work, but that might be a little beyond the scope of cocos and more for a simple OpenGL shader tutorial.

I also want that tutorial, too much things to figure out and it takes time.

By the way, you didn’t make use of the function prog->updateUniforms() or prog->link() or prog->use()??

I tried link() and updateUniforms(), but they didn’t work. Working without them now though.

Yeah, there is a lot of stuff to figure out, and no logging or breakpoints makes it even more difficult.

@grimfate Thanks for that. I didn’t think about the CC_ uniforms and how good that would be to document. This is something I’ll probably create next week, others can improve/add/fix/edit it after.

Awesome. Thanks!

Here’s the list of CC_ uniforms.
http://cocos2d-x.org/documentation/programmers-guide/13/index.html
http://cocos2d-x.org/docs/programmers-guide/advanced_topics/index.html#predefined-uniforms .

Here’s a brief I’ve written, but not finished or edited enough to post on my blog yet. Not sure if this is useful, what do you think? should I continue along these lines to supplement the cocos docs?


Cocos2D Defined Uniforms

Uniforms are values that are like global variables for shaders. When applied to a shader program all Node’s that use that shader will have access to the associated uniforms and each uniform will have the same value for all vertices and fragments in that frame (hence the similarity to global values).

Attributes instead are values that are unique to each vertex. A vertex is essentially a set of attributes of various lengths of bytes.

  • A standard sprite vertex contains a Position, Color, and Texture Coordinate.
  • A 3D sprite vertex might contain Position, Color, Texture Coordinate(s), and Normal
    (optional if texture mapped) (optional - for lighting)
  • A custom Node may submit a quad command with custom attributes (up to limit)

How Engine Applies Default Uniforms

void GLProgram::setUniformsForBuiltins(...) { 
//...
GLint location;
location =  _builtInUniforms[UNIFORM_P_MATRIX];
setUniformLocationWithMatrix4fv(location, matrixP.m, 1);
location = _builtInUniforms[GLProgram::UNIFORM_TIME];
setUniformLocationWith4f(location, time/10.0, time, time*2, time*4);
//...
}

Matrices

CC_PMatrix - Projection matrix - Transforms coordinate from camera to screen (see guide)
CC_MVMatrix - Model-View matrix - Transforms coordinate from model to world to camera (see guide)
CC_MVPMatrix - Model-View-Projection matrix - Transforms coordinate from local to screen (see guide)
Guide - http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/

CC_NormalMatrix - appears to be unused

CC_Time[4] - CPU clock timestamp in seconds multiplied by various factors
CC_SinTime[4] - Similar to CC_Time where element [3] has sin applied
CC_CosTime[4] - Same as CC_Time except elements [3] has cosine applied

setUniformLocationWith4f(..., time/10.0, time, time*2, time*4);
setUniformLocationWith4f(..., time/8.0, time/4.0, time/2.0, sinf(time));
setUniformLocationWith4f(..., time/8.0, time/4.0, time/2.0, cosf(time));

CC_TextureN - 2D Texture (sampler) that can be used to extract pixel information.
(N = four textures can be used [0…3] for CCSprite, and up to eight [0…7] for CCSprite3D)

vec4 color = Sample2D(CC_Texture0, xy);

CC_Random01[4] - Similar to CC_Time, but holds four random values using CCRANDOM_0_1()
CC_alpha_value - Used with alpha discard shader to “cut out” pixels color.a < CC_alpha_value
CC_AmbientColor - appears to be unused; would likely be filled in if there’s an ambient light in the scene

You’ll use one of these to transform your vertices in the vertex shader depending on which of these matrices you have pre-applied when you add your vertices into the GPU buffer object.

Node Applies Model-View Matrix (using default shader)

If you look at the internal code for the Node class you’ll notice that it uses the Model-View matrix to each vertex of the quad (or polygon vertex). It updates and applies the _modelViewTransform to adjust based on the parent hierarchy as well as the camera. This is done, most likely, because then the Model-View matrix multiplication can be done once per model instead of per vertex.

Edit: relatedly I plan to add more examples to the shader cookbook as well as flesh out a similar code sample and post regarding the Material system.
Cocos2d Shader Cookbook Port?
Edit2: Added clarification to the end point about node’s default shader

1 Like

Looks good.

I just had similar issue on cocos2dx v 3.13.1 and find out that if you declare the uniform in shader but not use it within the shader body then cocos2dx removes it from the shader code (when the shader is compiled). very clever I would say!

2 Likes

Hi @stevetranby, it seem likes the link for list of CC_uniforms is dead : http://cocos2d-x.org/documentation/programmers-guide/13/index.html.
It redirect me to the guide main page: http://cocos2d-x.org/docs/programmers-guide/about/.
Do you have any back up list anywhere else? Thanks a lot.

1 Like

@sinhviencodon thanks for letting me know. It’s still there:
http://cocos2d-x.org/docs/programmers-guide/advanced_topics/index.html#predefined-uniforms .

@slackmoehrle apparently editing is disabled for non-recent posts? Is this a desired setting? I was trying to edit my previous post in addition to this reply.

Edit: I was able to update the link in my previous reply :smiley:

1 Like