I have seen several examples/tutorials of WebGL where the gl.getAttributeLocation() or gl.getUniformLocation() and the like are called. However, these are all in a demo/tutorial scenario.
The issue/concern is this: The gl.getAttributeLocation, for example, takes in a string as the 2nd parameter. This is the name of the variable in the shader code.
Example:
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
To me this seems kind of bad because if i happen to change the shader code slightly (like a variable name), then it might cause all kinds of headaches due to the refactoring i have to do everywhere where the changes variable name is referenced.
I hope I'm getting my concern across. Please let me know if this is not clear and i will try to elaborate some more.
Question: I'm a beginner Opengl-ES/WebGL programmer, so I know i must be missing something. What do experienced programmers do to associate variable names in the shader code with their application code?
Thanks.
The idea is to somehow organize all attributes and uniforms in one place.
I'll use this Three.js demo to show you an example how they did it. Here's the full source code, and I'll show just part of it:
attributes = {
displacement: { type: 'f', value: [] }
};
uniforms = {
amplitude: { type: "f", value: 1.0 },
color: { type: "c", value: new THREE.Color( 0xff2200 ) },
texture: { type: "t", value: THREE.ImageUtils.loadTexture( "img.jpg")
};
So, developer sets up uniforms and attributes that he want's to use, by specifying name (which is written just once, so there aren't multiple versions of the name that you need to care about), type of the variable (f-float, c-color, t-texture and so on...) and value of the variable.
So you create attributes/uniforms in one place, once, and that's it. Engine could also automatically add several other attributes/uniforms (in this example it does so, for positions of vertices and normals of the vertices, and such, but you don't see that anywhere in the code (that behavior can be overriden if there's a need)).
Engine would then try to render the scene, and it would notice that shader for certain mesh is not prepared. So now, you just have JavaScript-set variables, but it is then up to engine to do all the management in the shader. Engine might use same variables that you provided, but could expand them with additional data such as attribLocation, uniformLocation,... but that shouldn't bother your coding. So engine takes some logically organized input of all attributes/uniforms (like in the code above) and generates parts of shader code from it.
So variables expand into something like this below, and data in it can be directly used in gl.drawElements, gl.uniform1f and such:
myMesh.uniforms = {
amplitude: { type: "f", value: 1.0,
shaderLocation: ..., shaderType: "float"},
...
};
myMesh.attributes = {
displacement: { type: 'f', value: [],
shaderLocation: ..., shaderType: "float", bufferedData: ... }
};
It would then generate the rest of the shader code and then set some flag that material/shader is ready to be used. If you change some attribute, you need to manually inform the engine of update so it could do another preparing of the shader.
JavaScript is great for this because of the way the Objects are organized and dynamic typing, but OpenGL engines would use some dictionaries that hold attribute/uniform name as key, and the rest of important data as the value in the dictionary.
Hope this helps.