SickBoy
SickBoy

Reputation: 225

How to get the index of an uniform variable?

I'm currently writing a function for automatic generation of uniform setters, and because of this I need the information which type an uniform variable has. Now the idea is to use the data type that is stored in the object returned by calling gl.getActiveUniform, a method that expects the index of the uniform as second argument, which therefore has to be evaluated first.

But as far as I can see, there is no way to retrieve the index of an uniform from the WebGL interface by passing in the identifier of the variable, is this right?

Of cause there is gl.getUniformLocation, but the object returned by this method does not have any public members and it's sole purpose seems to be to get passed in as an argument for setter functions - though it would be the right place to provide information about the index of an uniform, wouldn't it?

Finally there is gl.getProgramParameter, which can be called with gl.ACTIVE_UNIFORMS as second argument, but it only gives back the count of uniforms declared in the shaders.

So, the question is, do I have to provide the information about the index values of the variables by myself or is there built-in functionality in WebGL to get this done?

EDIT

Well, sometimes you can't see the forrest for the trees. The obvious solution would be not to get the index value from the variable name, but the variable name from it's index, since the name of the uniform is also member of the object returned by gl.getActiveUniform.

The procedure would be to first call gl.getProgramParameter with gl.ACTIVE_UNIFORMS to get the count of variables and then just loop over this, calling gl.getActiveUniform on each iteration. That would be the more elegant solution anyway, I think.

But nevertheless it would've been interesting to know, if there is a direct way to get the index for a single uniform by it's name...

Upvotes: 2

Views: 403

Answers (1)

WacławJasper
WacławJasper

Reputation: 3364

What you proposed in the edit is basically how I always done it. Like so:

function makeUniformSetters(program){
    var unifInfos = {};
    var uniformCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
    for (var i = 0; i < uniformCount; i++) {
        var info = gl.getActiveUniform(program, i);
        info.loc = gl.getUniformLocation(program, info.name);
        unifInfos[info.name] = info;
    }

    var unifSetters = {};
    Object.keys(unifInfos).forEach(function(k){
        unifSetters[k] = createUniformSetter(k);
    });


    function createUniformSetter(n){
        var info = unifInfos[n];
        if (info === undefined){
            console.log("program is not using uniform "+n);
            return function noOp(){};
        }

        var u = info;
        var loc = u.loc;
        var type = u.type;


        if (type === gl.FLOAT)
            return function(v){ gl.uniform1f(loc,v);};
        if (type === gl.FLOAT_VEC2)
            return function(v){ gl.uniform2fv(loc,v);};

        // etc
    }

    return unifSetters;
}

Then you can use it like so: unifSetters["u_viewProjection"](mat4);

I modified the code to get rid of engine specific parts, so it might not work 100% out of the box. But hopefully the idea should be clear.

Upvotes: 1

Related Questions