65.9K
CodeProject 正在变化。 阅读更多。
Home

用于插值两个纹理的 GLSL 着色器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.60/5 (5投票s)

2010年6月23日

CPOL

2分钟阅读

viewsIcon

53162

downloadIcon

2493

一个用 GLSL 开发的简单着色器, 用于插值两个纹理

引言

这个示例应用程序演示了一个用于插值两个纹理的简单着色器。

Kerala.bmpShrine.bmp 两个位图插值的截图。

Screenshot.jpg

背景

着色器是 OpenGL 中一个非常有趣的功能。本文展示了一个用于插值两个纹理的简单像素着色器。

着色器有三种类型

  • 片段着色器或像素着色器
  • 顶点着色器
  • 几何着色器

像素着色器是一个程序,它将为渲染的每个像素进行处理(执行)。每个像素的输出颜色由着色器程序确定。

根据 GLSL 规范,

片段处理器是一个可编程单元,它对片段值及其相关数据进行操作。为该处理器编写的 OpenGL 着色语言编译单元称为片段着色器。

Using the Code

我第一次使用 CG 创建着色器程序。运行时,它需要 cg.dllCGGL.dll。当我部署二进制文件时,运行我的应用程序需要安装 Cg。如果使用 GLSL,我们可以避免与 Cg.dllCgGl.dll 相关的依赖。唯一的依赖是 PC 应该支持着色器。

opengl32.dll 暴露了基本 OpenGL 功能的函数,其他(GPU 依赖的功能)作为 OpenGL 扩展实现。OpenGL 提供了 GL_ARB_fragment_shader 扩展用于像素着色器程序。

GLExtension 类处理所有 OpenGL 扩展操作。该类暴露了以下函数(使用纹理的 GLSL 像素着色器所需的函数)。

// 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 类来使用 OpenGL 扩展创建 GLSL 着色器。CreateProgram 可以借助 GLExtension 类创建着色器。

// 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;
}; 

最后,我将展示插值像素着色器,它可以根据插值值插值两个纹理。

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;
}  

fInterpValue 的值决定了 texture1 texture2 的贡献。如果 fInterpValue 0,则输出 color1(texture1),如果 fInterpValue 1,则输出 colro2( texture2 )

创建了一个滚动条来更改插值值。每当滚动条更改其位置时,它将被更新到着色器。

CInterpolationDlg 调用 GLSetup::InitGL()GLSetup 封装了 OpenGL 初始化和 OpenGL 渲染上下文的删除。大多数 OpenGL 函数调用都避免在对话框类中进行。

CInterpolationDlg::OnInitDialog() 创建了一个 Timer ,用于每秒显示 60 帧。

关注点

如果从文件创建着色器,则还需要将着色器文件与二进制文件一起提供。这里我从资源创建着色器。我只是将着色器文件 pixelshader.cg 添加到资源中。GLSLShader::CreateProgram() 接收 pixelshader.cg 的资源 ID。然后调用 LoadResource()LockResource() 从资源获取数据。并且 Interpolation.exe 可以在没有 pixelshader.cg 的情况下运行,因为它已经作为资源嵌入到 Interpolation.exe 中。

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 );
} 

纹理也是从两个位图创建的。这里位图文件也隐藏为资源,并避免了对位图文件的依赖。

  // 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; \
    } \
}\ 

历史

  • 初始版本
© . All rights reserved.