Unable to update uniform float array

Hi,

I’m trying to update uniforms of my shader:

void TextureLoader::updateUniforms()
{
    //updating Vec3 and float, forks fine
    renderSprite->getGLProgramState()->setUniformVec3("shadowsShift", shadowShift);
    renderSprite->getGLProgramState()->setUniformFloat("overlap", overlap);

    //...
    
    //updating float arrays, doesn't work
    GLProgram* glprogram = renderSprite->getGLProgramState()->getGLProgram();
    GLfloat params[7] = { 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f};
    GLuint location = glGetUniformLocation(glprogram->getProgram(), "hueShift");
    glprogram->setUniformLocationWith1fv(location, params, 7);
}

Updating of float array doen’t work in distinction from Vec3 and floats.

Here’s how I’m calling this function:

   void TextureLoader::visit(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
    //updating uniforms
    command.init(_globalZOrder);
    command.func = CC_CALLBACK_0(TextureLoader::updateUniforms, this);
    renderer->addCommand(&command);

    //texture rendering
    renderLayer->beginWithClear(0, 0, 0, 0);
    renderSprite->visit(renderer, transform, flags);
    renderLayer->end();
}

When I create shader and set float array in a same way as above at first time, everything is all right. But when I’m trying to update this array, this doesn’t work and has no effect. Vec3 and float updating always works fine.

How can I update uniform float arrays?

Thanks in advance.

Could you please also share your other parts of code ? I’d love to update just a float uniform variable but I’m not managing to do that at the moment :confused:

I just had same issue with uniform array and just figured out how it works.

TL;DR: Use dynamic float array instead of static when you call setUniform…() function.

Currently I’m using cocos2d-x version 3.14 and this trouble might get resolved with future updates, but just going to leave comment here for anyone who needs help.

Also make sure your shader code is valid (compiles and links) and all uniforms are valid as well(location must not be -1). Check your console log all the time.


So in cocos2d-x, shaders doesn't allow you to set uniform array to specific index.

If you see CCGLProgram.cpp, they ignore the bracket symbol while they parses the shader code.

 // remove possible array '[]' from uniform name
 if(length > 3)
 {
        char* c = strrchr(uniformName, '[');
         if(c)
         {
               *c = '\0';
          }
  }

like so, and just remembers the location where uniform array starts.

You can still query specific uniform array location with GLProgram, like getUniformLocation(“position[1]”), and get valid location number(not -1), but it doesn’t work. (correct me if this works)

So the only way to update uniform array is to pass entire array to uniform location at once, like OP did.

However, when we call setUniform…() function to update uniform array, cocos2d-x shaders doesn’t update uniform array right away but remembers which to update. It shallow copies the data array and only stores the pointer to it.

So when your scene’s update loop ends, your static float array is dead due to end of scope, shader doesn’t care about it and keep points to dead array.

So, obviously, you need to create dynamic array instead.

GLfloat* params = new GLfloat[7];    // <-
auto loc = get uniform location....();
shader->setUniform....();
//or
shaderState->setUniform...();

Then, shader will point to valid data array all the time and problem is solved.