Shader uniforms not updating

I’m trying to add some blurring effect to some texture. For this I have a custom shader that has some uniforms with settings such as the blur radius.

The shader does get applied, however the uniforms don’t get updated somehow.
Their values are all 0, while I try to set them in code, but this seems to have no effect.

void NodeBlur::update(float dt)
{
    GLuint pixelSizeLoc = glGetUniformLocation(mBlurX->getProgram(), "pixelSize");
    GLuint directionLoc = glGetUniformLocation(mBlurX->getProgram(), "direction");
    GLuint radiusLoc = glGetUniformLocation(mBlurX->getProgram(), "sampleRadius");
    mBlurX->setUniformLocationWith2f(pixelSizeLoc, mPixelSize.width, mPixelSize.height);
    mBlurX->setUniformLocationWith2f(directionLoc, 1.0f, 0.0f);
    mBlurX->setUniformLocationWith1i(radiusLoc, 64);
	mBlurX->updateUniforms();

mRenderTextureX->beginWithClear(1.0f, 0.0f, 0.0f, 1.0f);
    mStepX->visit();
    mRenderTextureX->end();
}

mBlurX is the GLProgram.
When reading the uniforms in the shader they are not set to these values somehow. The function does get called. Also trying to directly use the GL functions does not have an effect.

The shader:

`static const GLchar* blurShaderFrag = \
"#ifdef GL_ES									\n"\
"precision mediump float;						\n"\
"#endif											\n"\
"												\n"\
"varying vec4 v_fragmentColor;					\n"\
"varying vec2 v_texCoord;						\n"\
"												\n"\
"uniform vec2 pixelSize;						\n"\
"uniform vec2 direction;						\n"\
"uniform int sampleRadius;						\n"\
"uniform float weights[64];						\n"\
"												\n"\
"void main()									\n"\
"{												\n"\
"    gl_FragColor = texture2D(CC_Texture0, v_texCoord) * weights[0];									\n"\
"    for (int i=1; i<sampleRadius; i++)																	\n"\
"    {																									\n"\
"        vec2 offset = vec2(float(i)*pixelSize.x*direction.x, float(i)*pixelSize.y*direction.y);		\n"\
"        gl_FragColor += texture2D(CC_Texture0, v_texCoord + offset)*weights[i];						\n"\
"        gl_FragColor += texture2D(CC_Texture0, v_texCoord - offset)*weights[i];						\n"\
"    }																									\n"\
"}																										\n";
`

the for loop is not getting executed, as sampleRadius seems 0. If I hardcode it to say 64 it works, except that the other uniforms also are 0 values.

Am I doing something weird? I tried updating the GLProgram uniforms in both the constructor and at some update function, but both don’t work. But again, the shader does get executed, so that seems to work all fine. Just the uniforms don’t get updated.

I left out the weights uniform update, as I had to add a function to cocos2d-x to do this. But that is not the problem.

Any suggestions are welcome :slight_smile:
I use Cocos2d-x 3.1.1 on Windows 8

Are you creating your shader in just a text editor? Or what tools do you use to compile and test it?

@slackmoehrle It is just inline code, so a c++ string that is passed to the initWithByteArrays function of GLProgram.

I test it by rendering the output RenderTexture on screen.
If I manually loop say 64 times, rather than using the sampleRadius, then it actually does things if I ignore the weights etc. All uniforms are just set to 0 somehow.

I tried now adding some bindAttribLocation, but that also didn’t help.

Also as soon as I do this it seems to generate GL errors, but this is not related I think as things still render. Just the uniforms don’t get updated :frowning:

OpenGL error 0x0502 in CCClippingNode.cpp cocos2d::ClippingNode::onBeforeVisit 354

Little update:

GLProgramState* state = GLProgramState::getOrCreateWithGLProgram( mBlurX );
state->setUniformInt("sampleRadius", 13);
state->setUniformVec2("direction", Vec2(1.0f, 0.0f) );
state->setUniformVec2("pixelSize", Vec2(mPixelSize.width, mPixelSize.height) );

This actually works.
However there is no way to set a uniform that is an array of floats?
Somehow using the GLProgram doesn’t work, but using the GLProgramState does work? Is this normal?

I worked around the weights issue by calculating them inside the shader.
But still I wonder why this didn’t work and what the right way to work with shader uniforms is? Because this seems very buggy or incomplete.

Hello there!

I got some problems with Uniforms too, in fact I didn’t find any place where I can see the C++ code to update those Uniform values. I’m quite new to shaders and trying to apply this one ( http://www.alcove-games.com/opengl-es-2-tutorials/vertex-shader-for-tiled-water/ )

Here is my Cocos c++ code :

init function of my Sprite:

m_myShader = GLProgram::createWithFilenames("waterMove.vsh", "waterMove.fsh");    

    m_myShader->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
    m_myShader->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR);
    m_myShader->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORDS);
    m_myShader->link();
    m_myShader->updateUniforms();
    
    GLProgramState* state = GLProgramState::getOrCreateWithGLProgram(m_myShader);
    state->setUniformFloat("waveData", 0.f);  
    
    this->setShaderProgram(m_myShader);

then Update() func of my Sprite:

GLfloat _angleWave = 0.f;
    _angleWave += _dt * 100.f;
    while(_angleWave > PI*2.f)
        _angleWave -= PI*2.f;

    m_myShader->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
    m_myShader->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR);
    m_myShader->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORDS);
    m_myShader->link();
    m_myShader->updateUniforms();    
    
    GLProgramState* state = GLProgramState::getOrCreateWithGLProgram(m_myShader);
    state->setUniformFloat("waveData", _angleWave);        

    m_myShader->use();

VertexShader :

attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord;
uniform float waveData;
varying vec4 vColor;
varying vec2 vTexCoord;
 
void main() 
{
    vColor = a_color;
    vTexCoord = a_texCoord;
    vec4 newPos = vec4(a_position.x + 2 * sin(waveData+a_position.x+a_position.y), a_position.y + 2 * cos(waveData+a_position.x+a_position.y), a_position.z, a_position.w);
    gl_Position = CC_PMatrix * newPos; 
}

Pixel Shader :

varying vec4 vColor;
varying vec2 vTexCoord;

void main()
{
    gl_FragColor =  texture2D(CC_Texture0, vTexCoord) * vColor;
}

I tried many different things, switched from vec2 type to float, still not working, I’m breaking in CCGLProgramState.cpp, function void UniformValue::apply() it says my uniform type is unvalid…

Thanks for helping :slight_smile:

I resolved probleme, posted code here : Basic Shader Help

Exactly, cocos2d-x v3.7 cannot pass uniform array to shader cause of bug, I cannot post a new thread due to account level, so that I will notice this issue right here.
CCGLProgram.cpp: parseUniforms()


if(length > 3)
{
char* c = strrchr(uniformName, ‘[’);
if©
{
*c = ‘\0’;
}
}

I don’t know why they remove “[]” when parsing uniform.
Just remove above line to fix this bug.

another issue is that, you cannot pass #version 330 to shader to use new shader API.
I think should there is a way to pass this string at the begining of shader string code.