Referencing to external structs

If I have two Vertex shader objects linked together in one program is it possible to define some uniform structures in one and use them in the other?

//shared.vert


/*----------------------------------------------
 Shared Structures
 
----------------------------------------------*/
struct light
{
	vec4 position;
	vec3 colour;
};
uniform light lightSource;

/*----------------------------------------------
 Universal Attributes
----------------------------------------------*/
attribute vec4 attrVertex;		//vertices

/*----------------------------------------------
 Shared Functions
 
----------------------------------------------*/
vec4 GetShadowMapCoords()
{
	return (gl_TextureMatrix[5] * attrVertex);
}

//general.vert


/*---------------------------------------------
 Externals 
---------------------------------------------*/
vec4 GetShadowMapCoords();
uniform light lightSource;

/*----------------------------------------------
 Universal Attributes
----------------------------------------------*/
attribute vec4 attrVertex;

// uniforms

void main()
{
  //do some stuff
}

I have something like the above, and general.vert is able to use GetShadowMapCoords in main properly, but I am getting compiler errors when I try to make a uniform structure in the shared.vert.

I hope this is clear, Thanks for any input.

AFAIK this is not possible with glsl because there is no support of the #include directive unlike with Nvidia Cg. You have to include explicitly all shared structures, functions, etc used in one shader.

Yeah, as dletozeun said, not with #include since it isn’t supported. And you annoyingly can’t put both vert and frag in one source file, since they both must be called main.

However, the usual trick (e.g. as described here) is to pass two strings to glShaderSourceARB, the first is the shared stuff (#defines, types, etc.) and the second is the real shader code. Iternally GLSL is just going to mash them together, but it saves you from having to do the string mashing in client-side application code. Kind-of a cheap #include.

Theoretically you could have that first source string #define MAIN vertex or #define MAIN fragment so that you could cheat the system and use the same source string to contain both vertex and fragment shaders.

Thanks Dark Photon and dletozeun,

I’m not quite sure I understand some things though:

Currently I have a two vertex shaders in one program. Only one of them contains a main() call. They are not made using the method Dark Photon mentions, but rather I pass two shader handles to my Shader Program (using glAttachShader twice )

In the example above the code seems compile and work fine with me calling to the GetShadowMapCoords() from general.vert and having it defined in shared.vert.

So it’s OK to reference to externally defined functions, but not to externally defined structures?

If so then I guess passing two strings to glShaderSource is just as easy :slight_smile:

Im using following approach:


// common VS and FS stuff (vryings, uniforms, ...)
#ifdef ___VERTEX_SHADER
// vertex shader code
#endif

#ifdef ___FRAGMENT_SHADER
// fragment shader code
#endif


Then pass #define ___VERTEX_SHADER or #define ___FRAGMENT_SHADER
as aditional code when you compile shader source.

There’s a difference. What you’re doing is something like:

 glCreateShaderObjectARB( GL_VERTEX_SHADER_ARB );
 glShaderSourceARB( shader, 1, &src_str, NULL );
 glCompileShader( shader );
 glAttachObjectARB( program, shader );

for each of your source bits. What you may not realize is that

  1. [li] the source you provide to glShaderSource is the source code for the vertex shader, and [*] to clarify the italics previous, you can only have at most one shader for each shader domain (vertex, geometry, fragment, etc.) in a shader program (e.g. you can’t have two vertex shaders)

Contrast this with the technique I suggested (multiple strings to glShaderSource). These strings actually end up being concatenated by the driver into a single string that is used for the source for the vertex shader. So this technique should work for you.

Thanks for the replies again.

I am still puzzled by the fact that if i remove this part:

struct light
{
	vec4 position;
	vec3 colour;
};
uniform light lightSource;

from the shared.vert,

and uniform light lightSource; from general.vert Then it compiles with no errors, I can call the GetShadowMapCoords() function defined in shared.vert from within general.vert and my shadowmaps work correctly.

it only seems to cause errors when I introduce the struct.

http://www.opengl.org/sdk/docs/man/xhtml/glAttachShader.xml

this also states that:

“It is permissible to attach multiple shader objects of the same type because each may contain a portion of the complete shader. It is also permissible to attach a shader object to more than one program object.”

I’m not sure about all that have been said but you can have several shaders per stage so that if you want to have a functions library you can have a separate file and separate shader objects and attach both shader to a program.

The only annoying thing with this is that you probably want to use you functions library for both vertex and fragment shader but you have to create two shaders from the same source, one for the vertex shader and one for the fragment shader …

I guess it isn’t very clear…

I don’t mind right now if I have a separate Shader Objects for Vert and Frag shaders. What i want is to have one shared vertex shader object to use across all my vertex shaders, which seems to work fine, so long as i don’t try to reference to any structs defined in it, so is there any way i can refer to those structs?

I see … sorry I haven’t tried with structure, just functions so I’m not able to help :stuck_out_tongue:

James, Dark Photon gave the solution in his first post:

You write all shared data and function in one file, for example, shared.vert. Then you load this source file and concatenate its content to all vertex shaders that need it.

If I understand you correctly here, you are wrong. You can attach multiple shader objects to a vertex program as long as there is only one main function among all shader files.
So you can concatenate the shared.vert shader object (the one I talk about in my last post) attaching it to the vertex program in addition to the actual vertex shader source file.

Wow! You’re absolutely right! Didn’t know about that one… Sorry about that.

If I read you right, the compile error may have been because you declared lightSource in both shared.vert and generic.vert, and these definitions collided (?) What’s the error message?

Yeah, my bad. Thanks for the correction!

The puzzling thing about these semantics is that it means glCompileShader in practice can’t compile didly squat, because what is prepended or appended to each “shader” (which is actually a “shader chunk”) via prior/later attach could totally change how the chunk compiles (or even “if” it is compiled) into the full shader. …Which helps explain the reports of vendors deferring all shader compilation to the Link stage. That behavior makes sense now.

Also, unless I’m missing something, it doesn’t state the order that these shader chunks are placed in when concatenated with multiple glAttachShader calls.

Yes, and it probably what I am going to use.

But the question now is how do I get the method I was originally using to work with structs? It works fine with functions and standard data types…

Thanks for the help so far guys! I’ll have a look at what error the compiler is throwing tonight.

Yes, That’s a shame. It looks like that functions defined in one shader source file are implicitly declared as external in another shader source file. I do not see why it could not be the same with structures and global variables.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.