Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / multimedia / OpenGL

GLSL Shader for Interpolating Two Textures

4.60/5 (5 votes)
24 Jun 2010CPOL2 min read 52K   2.4K  
A simple shader developed in GLSL for interpolating two textures

Introduction

This sample application demonstrates a simple shader for interpolating two textures.

The screenshot of Interpolation of two bitmaps Kerala.bmp and Shrine.bmp.

Screenshot.jpg

Background

Shaders are an very interesting feature in OpenGL. This article shows a simple pixel shader for interpolating two textures.

There are three types of shaders:

  • Fragment or Pixel shader
  • Vertex Shader
  • Geometry Shader

A Pixel Shader is a program which will be processed (executed) for each pixel of a rendering. The output color of each pixel is determined by the shader program.

From GLSL spec,

The fragment processor is a programmable unit that operates on fragment values and their associated data. Compilation units written in the OpenGL Shading Language to run on this processor are called fragment shaders.

Using the Code

First time I created a shader program in CG. At runtime, it requires cg.dll and CGGL.dll. When I deployed my binaries, installation of Cg is necessary for running my application. If we are using GLSL, we can avoid this dependency with Cg.dll and CgGl.dll. Only dependency is that the PC should have shader support.

opengl32.dll exposes functions for basic opengl functionalities, others (GPU dependent functionalities) are implemented as opengl extensions. Opengl provides GL_ARB_fragment_shader extension for pixel shader programs.

GLExtension class handles all opengl extension operations. This class exposes the following functions (the required functions for GLSL pixels shader with texturing).

C++
// This Singleton class hold all function pointers of opengl Extensions.
// Functions similar to opengl extension are provided in this class. 
// All function will call corresponding function pointer.
class GLExtension
{
public:

    GLhandleARB glCreateProgramObjectARB();
    GLhandleARB glCreateShaderObjectARB(GLenum shaderType);
    void glShaderSourceARB( GLhandleARB shader, GLuint number_strings,
                            const GLcharARB** strings, GLint * length);
    void glAttachObjectARB(GLhandleARB program, GLhandleARB shader);
    void glLinkProgramARB(GLhandleARB program);
    void glCompileShader(GLhandleARB program);
    void glUseProgramObjectARB(GLhandleARB program);
    void glDeleteObjectARB(GLhandleARB object);
    void glGetInfoLogARB(GLhandleARB object, GLsizei maxLenght, GLsizei *length, 
	GLbyte*infoLog);
    GLint glGetUniformLocationARB(GLhandleARB program, const GLbyte* name);
    GLint glGetAttribLocationARB(GLhandleARB program, const GLbyte* name);
    void glUniform1iARB(GLuint index, int val);
    void glUniform1fARB(GLuint index, float fval);
    void glActiveTexture(GLenum Texture);

public:

    static GLExtension* GetInstance();
    // pFailedFunction Return NULL is all wglGetProcAddress are success.
    // Else return the name of failed function. Application should delete this buffer.
    bool GetWglProcAddress( TCHAR*& pFailedFunction );

private:

    // Constructor and destructor defined in private section for Singleton behaviour.
    GLExtension(void);
    ~GLExtension(void);
};

GLSLShader class is created to create a GLSL shader with opengl extensions. CreateProgram can create a shader with the help of GLExtension class.

C++
// Shader class handles creating of a Shader, and parameter setting to the 
// GLSL Shader. This class uses GLExtension for calling opengl extension functions.
class GLSLShader
{
public:
    GLSLShader(void);
    // nProgramID_i is the resource ID of Shader.
    // glSlShaderType_i should be GL_FRAGMENT_PROGRAM_ARB, GL_VERTEX_PROGRAM_ARB
    bool CreateProgram( const int nProgramID_i, GLenum glSlShaderType_i );
    bool DeleteShader();
    bool EnableShader();
    bool DisableShader();
    // This function attach a texture to shader parameter.
    // pParamName_i is parameter name given in shader.
    bool SetTexture( const CHAR* pParamName_i, const int nTextureID_i, int nIndex = 0 );
    // This function passes a float value to Shader float parameter.
    bool SetParam( const CHAR* pParamName_i, const float fValue_i );
    ~GLSLShader(void);

private:
   static GLhandleARB m_hProgramObject;
   GLhandleARB m_hShaderHandle;
}; 

Finally, I’ll show interpolation pixel shader, which can interpolate two textures based on an interpolation value.

C++
uniform sampler2D texture1;
uniform sampler2D texture2;
uniform float fInterpValue;
void main()
{
	vec4 Color2 = texture2D(texture2,gl_TexCoord[0].st);
	vec4 Color1 = texture2D(texture1,gl_TexCoord[0].st);
	gl_FragColor = ( 1.0 - fInterpValue )* Color1 + fInterpValue * Color2;
}  

The value of fInterpValue determines the contribution of texture1 and texture2. If fInterpValue is 0, then color1(texture1) will be output and if fInterpValue is 1, then colro2( texture2 ) will be the output.

A scrollbar is created to change the interpolation value. Whenever scrollbar changes its position, it will be updated to shader.

CInterpolationDlg calls GLSetup::InitGL(), GLSetup wraps opengl initialisation and deletion of opengl rendering context. Most of the opengl function calls are avoided from Dialog class.

CInterpolationDlg::OnInitDialog() creates a Timer for displaying 60 frames in a second.

Points of Interest

If we are creating shader from a file, the shader file is also required with binary. Here I'm creating shader from resource. I just added the shader file pixelshader.cg into the resource. GLSLShader::CreateProgram() receives the resource id of pixelshader.cg. Then calls LoadResource() and LockResource() for getting the data from resource. And Interpolation.exe can run without pixelshader.cg, because it's already embedded in Interpolation.exe as a resource.

MC++
bool GLSLShader::CreateProgram( const int nProgramID_i, GLenum glSlShaderType_i )
{
    HRSRC hrResInfo = FindResource( 0, MAKEINTRESOURCE( nProgramID_i ),
	TEXT("IDR_DATA"));
    if( 0 == hrResInfo )
    {
        return false;
    }
    HGLOBAL hRcResource =  LoadResource(0, hrResInfo  );
    const CHAR* pBufferResData = (CHAR* )LockResource( hRcResource );
    m_hShaderHandle = GLExtension::GetInstance()->
	glCreateShaderObjectARB( GL_FRAGMENT_PROGRAM_ARB );
} 

And textures are also created from two bitmaps. Here also bitmap files are hidden as resource and avoided dependency with a bitmap file.

C++
  // Macro for getting function pointers of Extension functions.
#define GET_PROC_ADDRESS(fname, failedFunName)\
{\
    Obj_##fname = (FPTR_##fname)wglGetProcAddress( #fname ); \
    if( 0 == Obj_##fname ) \
    { \
        failedFunName = new TCHAR[strlen(#fname)+1]; \
        wcscpy( failedFunName, L#fname ); \
        return false; \
    } \
}\ 

History

  • Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)