Sign in to follow this  

Simple vertex shader

This topic is 1947 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello,

I'm a newbie to vertex shaders. I'm just trying to get my feet wet. I coded the following simple vertex shader:

[source lang="java"]
const GLchar *shadersrc[] = {
"void main()\n",
"{\n",
"gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n",
"}"
};[/source]

I understand that gl_ModelViewProjectionMatrix may be deprecated, but I assume that if it's not working then the above code won't compile - which is not the case. So I assume that all's well.

I'm compiling/linking/using the shader with the following simple code:

[source lang="java"]
nos = sizeof(shadersrc)/sizeof(char*);
shad = glCreateShader (GL_VERTEX_SHADER);
glShaderSource (shad,nos,shadersrc,NULL);
glCompileShader (shad);
glGetShaderiv (shad,GL_COMPILE_STATUS,&iflg);
if(iflg == GL_TRUE) {
printf("Shader successfully compiled\n");
} else {
printf("Shader compilation failed\n");
return;
}
prog = glCreateProgram();
glAttachShader (prog,shad);
glLinkProgram (prog);
glUseProgram (prog);[/source]
I call glGetError() at this point and I get no error.

My understanding is that the above vertex shader should not change anything. However, if I use the above code nothing gets displayed.

Does anybody have a clue to what may be going on?

Thanks.

Share this post


Link to post
Share on other sites
Do you have a pixel shader to go with that vertex shader?

Edit: Well, I guess you don't have to have one. From the docs of glLinkProgram - "If program contains shader objects of type GL_VERTEX_SHADER but does not contain shader objects of type GL_FRAGMENT_SHADER, the vertex shader will be linked against the implicit interface for fixed functionality fragment processing." Edited by web383

Share this post


Link to post
Share on other sites
Well, I added the following code:

[source lang="java"] glGetShaderiv (shad,GL_LINK_STATUS,&iflg);
if(iflg == GL_TRUE) {
printf("link true\n");
} else {
printf("link false\n");
}
}[/source]

and I'm getting "link false". So it compiles, but doesn't link... I'm puzzled.

Share this post


Link to post
Share on other sites
web383: I do NOT have a pixel shader. I saw the same notice about the default pixel shader so I decided to do things one at a time...

Share this post


Link to post
Share on other sites
Yeah... I know... just realized that now.

But I have more information:

1) I added a simple fragment shader, with gl_FragColor = gl_Color.

This fails. Nothing gets displayed.

2) Then I changed to gl_FragColor = vec4(1.,0.,0.,1.);

Then I do get a red dot, as expected.

My questions are:

1) I had called glColor before. Shouldn't this stay in effect so that gl_Color is set to that?
2) Why do I see nothing when I set gl_FragColor to gl_Color? I know I have a gl_Color set because before using the program I display the image with the default (white) color. But when I enable the program nothing shows, unless I set gl_FragColor to, say, red explicitly.

Share this post


Link to post
Share on other sites
Why is you [i]shadersrc[/i] an array of character pointers? If I remember right, this grantees that the POINTERS are in concurrent memory space, but the strings themselves can technically live anywhere in memory (okay, okay, not anywhere but you get the point). They aren't guaranteed to evaluate to <string1><string2>..<string4> in memory and can have garbage in between depending on how the OS optimizes laying out the memory.

I assume your [i]nos [/i]calculation evaluates to 4?

Try modifying it such that

[source lang="cpp"]const GLchar shadersrc[] =
"void main()\n"
"{\n"
"gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
"}";

nos = sizeof(shadersrc);
[/source]

<edit> I could of course be wrong in the use of glShaderSource since I don't have any references in front of me. Edited by Aumnayan

Share this post


Link to post
Share on other sites
Aumnayan,

glShaderSource takes a GLchar** as an argument. And yes... I AM getting nos = 4, so all's well on that end.

I guess my problem really is trying to create a simple fragment shader that does exactly what a program with no fragment shader would do. I thought setting gl_FragColor to gl_Color was sufficient, but apparently that's not the case. But I don't know why...

Share this post


Link to post
Share on other sites
Okay, I've never spent to long with playing with the initialization code and tend to copy/paste from previous applications so I don't have how to use it burned into my head. Do you know what version of GL and GLSL you're using? If it's a latter one (after gl_ModelViewProjectionMatrix has been depreciated) it could be possible that you're GLSL compiler has left the prototype of the variable but the declaration of it was removed. This would allow the compiler to complete but cause the linker to fall on it's backside. Try taking it out, and see if it compiles/links. Even if it dosn't do anything that information will help you get to the bottom of this.

Share this post


Link to post
Share on other sites
Here's the info:

GL version= 2.1.2
GLSL version= 1.20 NVIDIA via Cg compiler

My vertex shader seems to work just fine, so I assume that gl_ModelViewProjectionMatrix is enabled.

My problem is the fragment shader. Apparently, the "default" fragment shader sets the color to (0,0,0), and nothing gets displayed. I would have imagined that the default fragment shader would behave just as if there were no shaders at all, but that's not the case.

So the real questions are: (1) why do I need something more than just gl_FragColor = gl_Color? (2) And, if I do need more, and if my vertex shader is so trivial, then how do I write a fragment shader so that I get the same images I was getting without any shaders?

Share this post


Link to post
Share on other sites
Normally important variables get calculated in the vertex program. With your [i]custom[/i] vertex program (i.e., one that just sets the vertex position), you [i]don't have[/i] that extra information. For example, typically gl_Normal is transformed by gl_NormalMatrix. Normals are important for lighting in the fragment program, but you're [i]not calculating[/i] them in the vertex program! This isn't in itself a problem, but it does explain why, for example, the default OpenGL fragment program can't calculate lighting.

Similarly, your vertex program doesn't calculate texture coordinates and color. The reason gl_Color is zero in your fragment program is because it also is a variable calculated in and interpolated from the vertex program--[i]but you're not setting it in the vertex program[/i]. If you want "gl_FragColor = gl_Color;" to work, you should, in your vertex program, add "gl_FrontColor = gl_Color;" When you call glColor3f(...) or whatnot in your main program, what this does is to specify the value of gl_Color in the vertex program. The vertex program then must pass it to the fragment program--that's what setting gl_FrontColor does. gl_FrontColor gets interpolated across the polygon and stored for each fragment. Then, in the fragment program, you can read the [i]interpolated value[/i] as gl_Color.

If you want to make your custom vertex program emulate OpenGL's default vertex program, that's certainly possible (though there aren't any shortcuts--and there's a lot of outputs OpenGL sets). My personal recommendation is to [i]not[/i] do that, and instead concentrate on implementing what you care about--typically lighting and texturing. The per-pixel Phong model is better than the per-vertex Gouraud shading OpenGL provides. You probably only care about maybe one texture. Just Google "lighting fragment program" or whatever it is you want to implement, and you'll find out how to do what you want to do. Edited by Geometrian

Share this post


Link to post
Share on other sites
Geometrian,

Thanks! That was a true eye opener.

I know I can set the new coordinate location with gl_Position. But what is the output for the normal variable? In other words, what variable will take the value gl_NormalMatrix * gl_Normal?

Share this post


Link to post
Share on other sites
Typically, you use your own defined variables in your vertex and fragment shaders. Before your main function, you can declare variables, such as "out vec3 normal" in your vertex shader. This needs a matching "in vec3 normal" in your fragment shader. Then you can write to your normal variable in your vertex shader and read the value in your fragment shader. You can put as many as you like and use different types as you choose.
There are also other kinds of variables you can declare when writing glsl programs. Uniform variables are read-only globals for both your vertex and fragment shader, which can be set from your program. These are often used to pass additional constant information, like light positions or texture information.

Share this post


Link to post
Share on other sites
I'm somewhat confused... I never really declared gl_Position; that's because this is a reserved name used to pass the vertex location. If I simply declared a variable, say, "pos", how would the program know to use this as the new position?

Likewise, the normal. I was expecting a variable called something like gl_NewNormal - a reserved word that GLSL would know to use as the new normal.

How is it that just declaring a variable called "normal" GLSL will know to use this as the new normal? Is "normal" a reserved word?

I feel like I'm missing some important concept here...

Share this post


Link to post
Share on other sites
Usually you would write both both a vertex and a fragment shader. Writing just a vertex shader, while technically allowed, might be such a rarely used corner case that it does not work in a lot of driver implementations. Just something to keep in mind.

There might be a predefined variable for normals, but since all those predefined variables are gone in the GLSL versions I'm interested in you would have to dig through the appropriate documentations.
Usually you would declare something like "smooth out vec3 position;" in the vertex shader and "smooth in vec3 position;" in the fragment shader. Analogous for different attributes, types and interpolations.

That aside, if you really have to try going the vertex shader-only way, try clearing the back buffer to all red and disabling blending. If the issue is lighting evaluating to 0 or alpha being 0, you should then at least see a black triangle.

Share this post


Link to post
Share on other sites
BitMaster:

Interesting that you mentioned that writing just a vertex shader is a corner case. I say this because right now in my application I can think of no need for a fragment shader. A typical use for me is to interpolate two frames with identical topologies for animation (tweening??).

Most important for me is your comment about "GLSL versions I'm interested in". I know that GLSL is at about version 4.3 now, but on my machine I only have version 1.4. So if I write my code based on the latest version wouldn't I be shutting out a lot of users with older machines? What is a "reasonable" GLSL version to base my code on? Maybe others can comment on this also.

Thanks.

Share this post


Link to post
Share on other sites
[url="http://en.wikipedia.org/wiki/Opengl#OpenGL_1.4"]OpenGL 1.4[/url] is from 2002. That is stone age. Sure you want to limit yourself to that?

Minimum to go for is [url="http://en.wikipedia.org/wiki/Opengl#OpenGL_2.1"]OpenGL 2.1[/url] from 2006, but you miss out a lot of goodies. Preferably would be [url="http://en.wikipedia.org/wiki/Opengl#OpenGL_3.3"]OpenGL 3.3[/url] from 2010. OpenGL 4+ is not important for you now.

Check a FAQ for some basic answers you need: [url="http://www.opengl.org/wiki/Getting_started"]http://www.opengl.org/wiki/Getting_started[/url]

And have a look at [url="http://www.arcsynthesis.org/gltut/"]Learning Modern 3D Graphics Programming[/url] for how to do modern 3D graphics programming.

Share this post


Link to post
Share on other sites
Well, I have everything "almost" working as I want it. The problem I have is that all geometry going through my vertex shader is not being lit - it all looks flat. Here are the important facts:

1) My vertex shader is generating the geometry just as I want it.

2) I do input normals when I draw the geometry

3) If I don't use any shaders when I draw the geometry, other than not getting the changes from the vertex shader, all lighting is fine.

4) Now comes the tricky part: up to now I did NOT have a fragment shader - thinking I wouldn't need one. But maybe I do. Just as there is a gl_Position standard output from the vertex shader, I wish there were a standard normal output. But there isn't one. My hope is that the default fragment shader would just take the normals defined in the application and use them in the default fragment shader - but I guess that's not the case.

So it appears I need a fragment shader after all, just to set gl_FragColor. This will be based on gl_Color - the interpolated pixel color - and the normal, for which I will have to define my own output variable in the vertex shader and use it as input in the fragment shader.

Could somebody confirm with me that this is correct? This means I need to check for all lights defined in the application and do all the dot products in the shader.

Share this post


Link to post
Share on other sites

This topic is 1947 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this