GLSL - first steps

Hi there,

i need some help in applying a shader (my first try) to an existing colored object.
I copied a simple toon-shader-function from a tutorial:


#define _V_SHADER                                              "
" \
"   varying vec3 normalVec;                                     
" \
"   void main ()                                                
" \
"   {                                                           
" \
"       normalVec = normalize (gl_NormalMatrix * gl_Normal);    
" \
"       gl_Position = ftransform ();                            
" \
"   }                                                               "                              
        
#define _F_SHADER                                                                  "
" \
"   varying vec3 normalVec;                                                         
" \
"   void main ()                                                                    
" \
"   {                                                                               
" \
"       float intensity;                                                            
" \
"       vec4 color;                                                                 
" \
"       intensity = dot (vec3 (gl_LightSource [0].position), normalVec);            
" \
"       if      (intensity > 0.90) {  color = vec4 (1.00, 0.56, 0.0, 1.0);  }       
" \
"       else if (intensity > 0.60) {  color = vec4 (0.64, 0.35, 0.0, 1.0);  }       
" \
"       else if (intensity > 0.30) {  color = vec4 (0.37, 0.17, 0.0, 1.0);  }       
" \
"       else                       {  color = vec4 (0.12, 0.07, 0.0, 1.0);  };      
" \
"       gl_FragColor = color;                                                       
" \
"   }                                                                                   "                              

The implementation is preformed in two steps / functions (handles are already created in the constructor of the clsShaderBase-Object):


void clsShaderBase::Update() {         
    const char *vv = _V_SHADER;       // vv & ff will be parameters later
    const char *ff = _F_SHADER;
    GLint success;

    success = 0;
    glShaderSource  (vsHandle, 1, &vv, NULL); 
    glCompileShader (vsHandle); 
    glGetShaderiv   (vsHandle, GL_COMPILE_STATUS, &success);
    if (success == GL_FALSE) handleErr("GLSL Vertex-compile error", GL_COMPILE_STATUS); 

    success = 0;
    glShaderSource  (fsHandle, 1, &ff, NULL); 
    glCompileShader (fsHandle);
    glGetShaderiv   (fsHandle, GL_COMPILE_STATUS, &success);
    if (success == GL_FALSE) handleErr("GLSL Fragment-compile error", GL_COMPILE_STATUS); 

    glAttachShader  (ShaderProgramHandle, vsHandle); 
    glAttachShader  (ShaderProgramHandle, fsHandle); 
}

void clsShaderBase::Apply() {   
    glLinkProgram   (ShaderProgramHandle); 
    GLint success = 0;
    glGetProgramiv  (ShaderProgramHandle, GL_LINK_STATUS, &success);
    if(success == GL_FALSE) handleErr("GLSL Link error", GL_LINK_STATUS); 
}

Apply() is called just before glBegin(GL_QUADS), but nothing changes in the rendered image and no error-handling is called.

Any idea what is wrong??

Regards,
Frank

maybe i’m wrong, but i think you are mixing up old and new openGL pipeline
“applying a shader to an existing object” ?

you dont apply shaders to anything like objects, shaders execute vertices you have to deliver in “pipes” or attributes
such attributes are described using vertex array objects, vertices are stored in buffer objects

you dont call “glBegin(GL_QUADS)” anymore, you just:

// activate your shader
glUseProgram(myshader);

// and bind your “pipes” / attributes
glBindVertexArray(myVAO);

// and then just execute the shader on a number of vertices:
glDrawArrays(GL_TRIANGLES, 0, 100);
// starting with the 0. vertex (the begining of the stored vertices)
// execute the shader for 100 vertices
// build triangles out of those vertices

Seems that you’re right. I did not know that two different pipelines.

So i obviously hve to figure out how to convert my existing object vertices into a Vertex-Array-Object??

This is perfectly valid provided you’re using OpenGL 2.x or the compatibility profile.

Use of shaders versus the fixed-function pipeline is orthogonal to the use of VBOs versus client-side vertex arrays or glBegin/glEnd.

You can use shaders with glBegin/glEnd or VBOs with the fixed-function pipeline.

You can’t use glVertexAttribPointer() to provide data for the compatibility attributes gl_Normal, gl_Color or gl_MultiTexCoord*, but you can use it (with attribute zero) to provide data for gl_Vertex (which is used by the ftransform() function).

You don’t appear to be calling glUseProgram(), which is what causes rendering to use a given shader program rather than the fixed-function pipeline.

Thanks, GClements.

I inserted ‘glUseProgram (ShaderProgramHandle);’ into the Apply()-Function like this:


void clsShaderBase::Apply() {   
    glUseProgram    (ShaderProgramHandle); 
    glLinkProgram   (ShaderProgramHandle); 
    GLint success = 0;
    glGetProgramiv  (ShaderProgramHandle, GL_LINK_STATUS, &success);
    if(success == GL_FALSE) handleErr("GLSL Link error", GL_LINK_STATUS); 
}

Now i have a visible result. So i can start to figure out the details.

But two new questions appeared now:

  1. obviously ‘glUseProgram’ has to be called before ‘glLinkProgram’ (otherwise there is no result). Is this right?
  2. the fragment-shader always executes
if      (intensity > 0.90) {  color = vec4 (1.00, 0.56, 0.0, 1.0);  }

. So ‘intensity’ seems to be >0.9 always. Any idea why?

Thanks for your help!

Regards,
Frank

  1. No. You create your shader program. You attach to it the compiled vertex and fragment shaders. Then you link it. Once it is linked and no errors happened, you can use it. See this for example. Focus only on how the shader is created.

Also, compile and link your shader only once. I can see from your update code that it looks like you do it for each frame.

  1. This depends on where your light is and how the normals are set, regarding your code:

intensity = dot (vec3 (gl_LightSource [0].position), normalVec);

Any information on these maybe ?

That’s it, Silence.
Now it works. The point was, that i had no vertex-normals at all, while i used my own lightning-algorithm and i thought that the line

normalVec = normalize (gl_NormalMatrix * gl_Normal);

perfomes the normalisation, for the shaders.

Thanks for your help, guys!

Regards,
Frank