Posted Tuesday, 9 March, 2010 - 11:56 by pontifikas
Which brings me to my other question:
Having written some code that performs drawing using VBOs and glVertexPointer function,
how can I pass the vertex-normal attribute values into the shader now that gl_Vertex (or gl_Normal) is deprecated?
I have some in variables in my shader for storing vertex data. Am I supposed to use VertexAttribPointer and then bind them
to some index or is there some default index for vertex attributes which I can bind to this variables directly with BindAttribLocation?
Posted Tuesday, 9 March, 2010 - 12:21 by the Fiddler
Two ways: you can either bind attributes to specific indices or you can link the shader and query the indices generated by the linker.
In the first case, you could say (for example) that "in Position" is always #0, "in Normal" #1, etc. This is the simplest approach and it works great in most cases.
In the second case, you need to build a dictionary of indices once the shader is linked. You can then use this dictionary to map your vertex attributes to indices. Example code below (this is taken from the WIP OpenTK demo, slightly modified(*)):
publicstruct VertexAttribute
{publicstring Name { get; private set; }publicint Index { get; private set; }public ActiveAttribType AttributeType { get; private set; }public VertexAttribute(string name, int index, ActiveAttribType type)
: this(){
Name = name;
Index = index;
AttributeType = type;
}}publicclass ShaderProgram
{publicint Id { get; private set; }public Dictionary<string, VertexAttribute> Attributes { get; private set; }
...
void DetectAttributes(){// Get the attribute name -> id mapping, as generated by the driver and enable all necessary attributes.//// To find out all necessary attributes we query all attribute names. If a name is a non-zero string, we//// consider that attribute as enabled.int num_attributes;
int max_attribute_length;
GL.GetProgram(Id, ProgramParameter.ActiveAttributeMaxLength, out max_attribute_length);
StringBuilder name = new StringBuilder(2 * max_attribute_length); // Multiply by 2 because of truncated strings on Mono 1.9.1.GL.GetProgram(Id, ProgramParameter.ActiveAttributes, out num_attributes);
for(int index = 0; index < num_attributes; index++){int length, size;
ActiveAttribType type;
name.Remove(0, name.Length);
GL.GetActiveAttrib(Id, index, name.Capacity, out length, out size, out type, name);
if(length > 0){int location = GL.GetAttribLocation(Id, name.ToString());
var attr = new VertexAttribute(name.ToString(), location, type);
Attributes.Add(attr.Name, attr);
//Debug.Print("Attribute detected {0} {1} -> {2}", attr.AttributeType, attr.Name, attr.Index);}}}
...
}
You can then use something similar to program.Attributes["Position"].Index to find out which index "in Position" is mapped to.
This approach is slightly more flexible, but accessing the dictionary to set attributes at runtime can be rather slow without vertex array objects. Still, performance should be adequate for simple applications.
Posted Tuesday, 9 March, 2010 - 13:38 by pontifikas
The question is if there is some default(by the driver) attribute index, so by simply binding my variable to it
using, say BindAttributeLocation(prog_id,driver_default_vertex_attribute_index,"Position"),
to create an alias and be able to access the vertex data from withing the shader via Position.
I ask because I have a general function performing draw in which I dont want to know what variables exist
at any given shader that is executed.
Posted Tuesday, 9 March, 2010 - 14:08 by the Fiddler
No, there is no default mapping. You either have to force a mapping beforehand (i.e. make sure all shaders use the same attribute names that are bound to well-defined indices) or you need to query the driver after shader linkage. The first approach is conceptually similar to using built-in attributes.
I know this doesn't answer your question directly, but the draw method doesn't necessarily need to be aware of the actual shader variables. For example, in the past I've used reflection to generate this information automatically, where a struct{publicVector3 Position, Normal; } can be automagically bound to a shader with in vec3 Position, Normal; attributes. This works, but tends to get complicated when using multiple VBOs for a single shader. Another, possibly better approach is to generate VAOs at load time, so you don't have to worry about binding attributes at render time (the VAO encapsulates this information, so you simply bind it and render).
I'd love to hear if anyone has a better solution to this issue.
When the shader is linked in my engine, the special attribute dictionary is provided.
I call glBindAttributeLocation for each attribute in this dictionary right before linking, not caring about actual existence of the attributes in the shader code.
The dictionary is different for particle systems & regular objects, there might be more of them in the future.
Posted Tuesday, 9 March, 2010 - 15:08 by pontifikas
kvark wrote:
When the shader is linked in my engine, the special attribute dictionary is provided.
I call glBindAttributeLocation for each attribute in this dictionary right before linking, not caring about actual existence of the attributes in the shader code.
The dictionary is different for particle systems & regular objects, there might be more of them in the future.
What do you mean by "special attribute" dictionary?
Do you have some identifier (as is gl_ in the beggining of the uniform name) that tells you "This is for vertex-normal-color data" in your dictionary and you bind the buffer at this variable?
Posted Wednesday, 10 March, 2010 - 07:14 by pontifikas
This is the approach I've been considering. I can't think of any other way to maintain generality in my drawing functions unless I define set of my own variables with, somehow, identifiable names.
Comments
Re: GLSL Compatibility question
It should be, as long as the drivers are up to date. I have written 1.4 shaders on a 2.1 context and they worked fine (both Nvidia and Ati).
Re: GLSL Compatibility question
Which brings me to my other question:
Having written some code that performs drawing using VBOs and glVertexPointer function,
how can I pass the vertex-normal attribute values into the shader now that gl_Vertex (or gl_Normal) is deprecated?
I have some in variables in my shader for storing vertex data. Am I supposed to use VertexAttribPointer and then bind them
to some index or is there some default index for vertex attributes which I can bind to this variables directly with BindAttribLocation?
Re: GLSL Compatibility question
Two ways: you can either bind attributes to specific indices or you can link the shader and query the indices generated by the linker.
In the first case, you could say (for example) that "in Position" is always #0, "in Normal" #1, etc. This is the simplest approach and it works great in most cases.
In the second case, you need to build a dictionary of indices once the shader is linked. You can then use this dictionary to map your vertex attributes to indices. Example code below (this is taken from the WIP OpenTK demo, slightly modified(*)):
You can then use something similar to
program.Attributes["Position"].Indexto find out which index "in Position" is mapped to.This approach is slightly more flexible, but accessing the dictionary to set attributes at runtime can be rather slow without vertex array objects. Still, performance should be adequate for simple applications.
Re: GLSL Compatibility question
The question is if there is some default(by the driver) attribute index, so by simply binding my variable to it
using, say BindAttributeLocation(prog_id,driver_default_vertex_attribute_index,"Position"),
to create an alias and be able to access the vertex data from withing the shader via Position.
I ask because I have a general function performing draw in which I dont want to know what variables exist
at any given shader that is executed.
Re: GLSL Compatibility question
No, there is no default mapping. You either have to force a mapping beforehand (i.e. make sure all shaders use the same attribute names that are bound to well-defined indices) or you need to query the driver after shader linkage. The first approach is conceptually similar to using built-in attributes.
I know this doesn't answer your question directly, but the draw method doesn't necessarily need to be aware of the actual shader variables. For example, in the past I've used reflection to generate this information automatically, where a
struct { public Vector3 Position, Normal; }can be automagically bound to a shader within vec3 Position, Normal;attributes. This works, but tends to get complicated when using multiple VBOs for a single shader. Another, possibly better approach is to generate VAOs at load time, so you don't have to worry about binding attributes at render time (the VAO encapsulates this information, so you simply bind it and render).I'd love to hear if anyone has a better solution to this issue.
Re: GLSL Compatibility question
When the shader is linked in my engine, the special attribute dictionary is provided.
I call glBindAttributeLocation for each attribute in this dictionary right before linking, not caring about actual existence of the attributes in the shader code.
The dictionary is different for particle systems & regular objects, there might be more of them in the future.
Re: GLSL Compatibility question
When the shader is linked in my engine, the special attribute dictionary is provided.
I call glBindAttributeLocation for each attribute in this dictionary right before linking, not caring about actual existence of the attributes in the shader code.
The dictionary is different for particle systems & regular objects, there might be more of them in the future.
What do you mean by "special attribute" dictionary?
Do you have some identifier (as is gl_ in the beggining of the uniform name) that tells you "This is for vertex-normal-color data" in your dictionary and you bind the buffer at this variable?
Re: GLSL Compatibility question
The attribute dictionary I mentioned is just a ('id'->'name') collection. These names are usually meaningful like at_vertex, at_quat, etc.
Re: GLSL Compatibility question
This is the approach I've been considering. I can't think of any other way to maintain generality in my drawing functions unless I define set of my own variables with, somehow, identifiable names.
Thank you all for your answers!