Each shader gets its own set of uniforms returned after it is compiled. Okay, in my engine I have not just one shader per material, but a shader group. Depending on the number of lights visible and other factors, the engine adds defines to the shader source code and compiles a new version of the shader for every possible combination of visible lights and other settings.
Because each shader group has more than ten thousand possible variations, most of which are never used in any given application, the engine only compiles the ones that are needed, when they are needed. When a shader is set, the engine passes built-in information to the shader like light settings and other things.
Okay, now comes the fun part. I have a custom shader, and I want the user to be able to pass some data to that shader in a uniform. I could make a function that sets the uniform for every compiled version of the shader, but that doesn’t mean new versions will get the data. I could add a callback, but the users who use the scripting language won’t be able to use that, and I doubt anyone will even understand what the callback is doing. Right now, I am using a SetGlobalShaderOptions() command that sets a vec4 that will get pass as “options” any time a shader is set. It’s a really bad hack and I feel like apologizing to my users for it.
I just wanted to say that for anything more complicated than simple tech demos, the way OpenGL handles uniforms is really ****ing retarded, and there has got to be a better way. Allowing for global uniforms shared between shaders would have made a lot more sense. Next time around, I am going to think up another layer of abstraction to add on top of OpenGL’s shader commands, so that I can simplify the passing of uniforms to shader groups.
Is probably what you are looking for. An alternative are GLSL’s built-in uniforms. You can abuse them to get some kind of global environment uniforms.
If I remember right, my 8800 only supports up to about 8 bindable uniforms.
I abuse the hell out of the built-in uniforms, and I love every minute of it.
It’s still totally wack.
The idea is that you will use the bindable uniforms to pass structure with many informations or even array of structures (e.g. lights).
I abuse the hell out of the built-in uniforms, and I love every minute of it.
I used them in the past. The problem is that they waste constant space and are susceptible to driver not noticing that they had changed.
The wrapper I use represents each shader (in your case, a specific instance of a group) as an object, and when I try to access the uniforms I basically do a myshader->setUniform4f(“camPos”, camera->Position); (converted to c++ish).
It then just queries opengl for the uniform position and updates the uniform (obviously the location could be cached for performance, but that wasn’t an issue for me). Depending on mode, setting a non-existing uniform will simply return false or raise an exception.
Just a few lines of code and it makes life rather easy. At least for me Then again, I might be missing the point…
Does glGetUniform() require a GPU sync?
All get functions usually require a GPU sync, although this can be easily optimized away as far as I understand…
I’ve got a similar design issue in the past. The way I resolve this is:
instead of having the user sets the uniform value for the shader, the user updates the uniform into a global parameter table. Then, any shader can look-up the uniforms it requires from that global parameter table.
From the user code:
int index = g_globalParams.getUniformIndex("colorTint");
From the shader C++ class:
for (int i = 0; i < customUniformsCount; ++i)
int index = g_globalParams.getUniformIndex(customUniformNames[i])'
if (index >= 0)
void *userUniform; = g_globalParams.getUniform(index);
// cast and upload user uniform to GLSL here
The index of the uniform within g_globalParam table can be cached for efficiency, as well as the type of each uniforms. This way it’s all data-driven!
Hope it helps.
I do it as Lord crc and i don’t quite get the point what’s your problem.
If your engine has built in variables, that you want to pass to the shader, why don’t you pass these to the shader, upon material-switch.
Everytime your material changes, you can just do:
- is uniform x present in shader-source: set uniform x to value y
- is uniform y present …
And if the user wants to pass custom information to his shaders, he could just register his own uniforms through the scripting-language:
setUniformValue (“MyCrazyOwnUniform”, x, y, z)
Your engine will get this call and caches the value (and the uniform name) and passes it to the next shader (or even the current one). Thus users can modify their own shaders at run-time, with a little help by your engine.
In my opinion the current system of GLSL is pretty good, i hated the ARB_fp way. But maybe i missed the point, if so please tell me.
For me it is exactly the oposite. Most of my shaders share common set of variables whose value is constant most of the frame(e.g. fog parameters, position of the camera, projection matrices and so on) or for several consecutive draws with different shaders (e.g. light parameters). It seems to me as ineffective if I need to send them to the OGL once for each shader instead of specifying them once at start of the rendering block in which they are constant.
I think these responses are divided into engine programmers and tech demo writers. :\
The messiest part of this is that I don’t use just one shader for each material. I use groups of shader optimized for the combination of lights that might be onscreen. So any time the user passes values, it requires me to do some kind of recording and latent passing, and it all seems very silly.
For my own internal uniforms it is not a problem, it is just difficult to allow user-defined uniforms for their own custom shaders.
From your description, I think I’d create a ShaderGroup class, and make it have SetUniform() methods. It would keep a list of supplied uniforms and their value, applying them each time a shader from the group is activated.
Ok so it adds a few extra lines of code, and I agree that the new uniform buffer objects will probably be great, but other than a bit of extra work on our part I don’t see the big issue. I especially fail to see why user-defined uniforms present a problem.
In other words, “everyone who doesn’t agree with me is incompetent”. That’s not the best way to treat people who are actually trying to help you solve your problem…
When your engine design has a problem with the way OpenGL handles things, change your design. There are some very good suggestions on how to solve your problem in some of those “tech demo writers” comments.
Btw, I wasn’t trying to sound like an ass or anything, but I truly don’t understand why this is such a PITA.
whats wrong with
vec4 camera_pos = gl_ModelViewMatrixInverse;
though im in agreement the lack of global uniforms is a PITA, i use the gl_LightSource[X].ambient.xyz etc stuff for light positions which is very messy
I am not using the modelview matrix and all my shaders are operating in world space (although to less degree than they used to). I send model matrix trough the vertex attributes (the pseudo-instancing). The view and projection matrices are combined into the projection matrix.
i use the gl_LightSource[X].ambient.xyz etc stuff for light positions which is very messy
I used them too. After I got burned by various drivers forgetting to upload various types of builtin uniforms unless the shader was rebound, I switched to arrays of vec4 uniforms. The builtin uniforms for lights also sometimes consumed much more uniform space than was necessary given the fields I used so I run out of uniforms in one big shader on ATI hw.
The vec4 approach is unfortunately not flawless too. Few days ago I was fighting with driver for GF9600 which incorrectly compiled some simple code using them.
I don’t expect any decent answers for this one but why isn’t EXT_bindable_uniform available on other hw besides the Gf8 and Gf 9?
At least there is http://developer.nvidia.com/object/nvidia_opengl_specs.html
but does ATI have similar docs about their GPU and the extensions it supports?
I use the same sort of “use caps bits to lookup common shader compiled with different #define’s” approach. I call it shader instancing, not groups.
I really like despoke’s method - I hadn’t thought of that before. It’s a neat way of having a common meeting point between application and shader instance, but at the same time giving both ends the option of caching the index of each uniform they use.
I would add a change number for each global uniform, so the shader instance would only actually upload the value if the change number is != to the shader instances change number for that uniform.
It seems to me that this fixes the OP’s problem without adding anything to GL.
Anyway, it’s all good fun.
i feel your pain, this was bad nvidia bug 6-18months ago =(making me have a seperate path during shader setup where i would reset an already set state, now that and the occlusion error are solved its cool.
but yes i cant see why they never had this before as its in the spirit of gl where u can set some states + leave them alone + draw unlike d3d where u must reset things over again for each drawing, hmmm
This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.