Upcoming Events
Southwest Gaming Expo
11/20 - 11/22 @ Dallas, TX

Workshop on Network and Systems Support for Games (NetGames 2009)
11/23 - 11/25 @ Paris, France

ICIDS 2009 Interactive Storytelling
12/9 - 12/11 @ Guimarães, Portugal

Global Game Jam
1/29 - 1/31  

More events...


Quick Stats
6724 people currently visiting GDNet.
2341 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!



Link to us

Link to us

  Intel sponsors gamedev.net search:   

Creating a GLSL Library


A Texturing Example

The vertex shader used in this example isn't very exciting so lets just get it out of the way.

/**
 * \file Texturing.vert
 */
void main()
{
    gl_TexCoord[0] = gl_MultiTexCoord0;
   
    gl_Position = ftransform();
}
All the vertex shader does is copy the multi-texture coordinate over for the fragment shader to use. The attribute array gl_MultiTexCoord0 is not available in the fragment shader so we need to populate the gl_TexCoord[0] value with it. Then the vertex position gets transformed according to the current model view matrix.

Now its time to write our Texturing library function.

There are six options for how to texture a geometry in OpenGL

  • GL_REPLACE
  • GL_MODULATE
  • GL_DECAL
  • GL_BLEND
  • GL_ADD
  • GL_COMBINE
Each of these options has a different calculation for texturing that can be replicated in GLSL. So lets create a function that does just that.
/**
 * \file Texturing.frag
 */
const int REPLACE  = 0;
const int MODULATE = 1;
const int DECAL    = 2;
const int BLEND    = 3;
const int ADD      = 4;
const int COMBINE  = 5;

void applyTexture2D(in sampler2D texUnit, in int type, in int index, inout vec4 color)
{
    // Read from the texture
    vec4 texture = texture2D(texUnit, gl_TexCoord[index].st);
   
    if (type == REPLACE)
    {
        color = texture;
    }
    else if (type == MODULATE)
    {
        color *= texture;
    }
    else if (type == DECAL)
    {
        vec3 temp = mix(color.rgb, texture.rgb, texture.a);
       
        color = vec4(temp, color.a);
    }
    else if (type == BLEND)
    {
        vec3 temp = mix(color.rgb, gl_TextureEnvColor[index].rgb, texture.rgb);
       
        color = vec4(temp, color.a * texture.a);
    }
    else if (type == ADD)
    {
        color.rgb += texture.rgb;
        color.a   *= texture.a;
       
        color = clamp(color, 0.0, 1.0);
    }
    else
    {
        color = clamp(texture * color, 0.0, 1.0);
    }
}
At the top of the code we create a set of constant integers to denote what type of texturing we want to apply to the geometry. The function itself takes four arguments. The first is a sampler2D which is the texture unit holding the texture we want to apply. Second is the type which is one of the constant integers we defined. Third is the index of the texture coordinates we wish to use. And finally color is the current color of the texel which will be modified and returned from the function. The code itself is taken from the Orange Book and can also be created using 3Dlabs ShaderGen tool.

So now we have a function that will replicate OpenGL's texturing facility. Now we just need to create the other fragment shader that uses this function.

/**
 * SingleTexture.frag
 */

void applyTexture2D(in sampler2D texUnit, in int type, in int index, inout vec4 color);

uniform sampler2D TexUnit0;
uniform int TexturingType;

void main()
{
    vec4 color = gl_Color;
   
    applyTexture2D(TexUnit0, TexturingType, 0, color);
   
    gl_FragColor = color;
}
The most important thing to remember when creating a shader library is to use forward declarations. The applyTexture2D function is in a different file so when this file is compiled the compiler needs to have knowledge that there is a function called applyTexture2D and what its parameters are. When the shaders are linked together the linker will figure out the rest.

Other than that the shader is fairly straightforward. There are two uniforms, the sampler2D which just points to the texture unit we wish to use, and the integer TexturingType which denotes what OpenGL texturing to emulate. The main function just takes the color of the vertex and passes that along with TexUnit0, TexturingType and the index of the texture coordinates to the function. The result of which is used as the fragment color.

Its worth noting that OpenGL does not provide a mechanism to query what the environment of the texture is (minus the texture environment color, gl_TextureEnvColor[]). So if you send via glTexEnv that you want to use GL_ADD, there is no way inside the shader to determine that is being requested by the program.



A Multi-Texturing Example

Contents
  Introduction
  A Texturing Example
  A Multi-Texturing Example
  A One-Sided Per-Pixel Lighting Example
  The Phong Lighting Shader
  A Two-Sided Per-Pixel Lighting Example
  Conclusion

  Source code
  Printable version
  Discuss this article