录十六

持之以恒

创建和链接着色程序

之前我们已经创建并编译了必要的着色器对象,接着就需要将它们连接器起来,创建一个可执行的着色程序

一、定义着色程序类

class MCProgram
{
public:
    MCProgram();
    virtual ~MCProgram();
    
    //获取着色程序句柄
    unsigned int  GetHandle(){return m_Handle;}

private:
    //着色程序句柄
    unsigned int m_Handle;
};

二、创建着色程序

(1)创建着色程序

首先,需要调用glCreateProgram函数,创建一个空的着色程序,供后续使用。

GLuint glCreateProgram()

该函数没有任何参数,调用之后会返回一个非零的整数,即着色程序句柄;如果发生错误返回0。

(2)附加着色器对象

创建了着色程序之后,就要调用glAttachShader函数,把所需着色器对象关联到这个程序中,以创建可可执行的着色程序。

void glAttachShader(GLuint program, GLuint shader)
  • program — 着色程序的句柄

  • shader — 需要关联的着色器对象的句柄

着色器对象可以再任何时候关联到着色程序中,但是它的功能只能在着色程序成功连接后才可以使用。一个着色程序对象可以同时关联多个着色程序

void glDetachShader(GLuint program, GLuint shader)
  • program —着色程序的句柄

  • shader — 解除关联的着色器对象句柄

(3)链接着色程序

在所有需要的着色器对象都被关联到着色程序之后,就可以调用glLinkProgram函数,将这些对象链接成一个可执行的着色程序。

void glLinkProgram(GLuint program)

program — 着色程序的句柄

三、状态检查

void glGetProgramiv(GLuint program, GLenum pname,
                     GLint *params)
  • program — 着色程序的句柄

  • pname — the parameter to get information about; can be

    • GL_ACTIVE_ATTRIBUTES

    • GL_ACTIVE_ATTRIBUTE_MAX_LENGTH

    • GL_ACTIVE_UNIFORM_BLOCK

    • GL_ACTIVE_UNIFORM_BLOCK_MAX_LENGTH

    • GL_ACTIVE_UNIFORMS

    • GL_ACTIVE_UNIFORM_MAX_LENGTH

    • GL_ATTACHED_SHADERS

    • GL_DELETE_STATUS

    • GL_INFO_LOG_LENGTH

    • GL_LINK_STATUS

    • GL_PROGRAM_BINARY_RETRIEVABLE_HINT

    • GL_TRANSFORM_FEEDBACK_BUFFER_MODE

    • GL_TRANSFORM_FEEDBACK_VARYINGS

    • GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH

    • GL_VALIDATE_STATUS

  • params — 查询结果返回的地址

void glGetProgramInfoLog(GLuint program, GLsizei maxLength,
                          GLsizei *length,
                          GLchar *infoLog)
  • program — 着色程序的句柄

  • maxLength — 存储日志信息的缓存长度

  • length — 日志信息的长度(不包含null终止符),如果不需要获取长度,参数可以传NULL

  • infoLog — 获取日志信息的缓存地址

bool  MCProgram::CheckStatus(unsigned int handle)
{
    //获取链接状态
    GLint Success;
    GL30::glGetProgramiv(handle, GL30::GL_LINK_STATUS, &Success);

    if (!Success) 
    {
        //获取Log长度
        GLint infoLen;  
        GL30::glGetProgramiv(handle, GL30::GL_INFO_LOG_LENGTH, &infoLen);

        if (infoLen > 0)  
        {  
            char* pLogMsg = new char[infoLen];  
            //获取链接失败时的Log信息
            GL30::glGetProgramInfoLog(handle, infoLen, NULL, pLogMsg);
            printf("Error linking shader program: \n%s\n", pLogMsg);

            delete[] pLogMsg;
        }
        return false;
    }
    return true;
}

四、安装着色程序

在着色程序连接成功之后,就可以调用glUseProgram函数,启动这个着色程序。

void glUseProgram(GLuint program)

program — 着色程序的句柄

启动我们所创建的着色程序之后,OpenGL的功能就从固定管线切换到了可编程管线。为了恢复固定管线功能,可以向这个函数传递0作为program参数。

void MCProgram::UseProgram()
{
	GL30::glUseProgram(m_Handle);
}

五、删除着色程序

当着色器程序被使用完之后,还需要调用glDeleteProgram函数将其删除,释放系统资源。

 void glDeleteProgram(GLuint program)
  • program — 着色程序的句柄

如果这个着色程序当前没有被使用,执行glDeleteProgram函数时,这个着色程序会被立即删除。否则,就这个着色程序将被标记为删除状态,当它不在使用时将自动被删除。

void MCProgram::DeleteProgram()
{
    if(m_Handle != 0)
    {
        GL30::glDeleteProgram(m_Handle);
        m_Handle = 0;
    }
}

六、配套代码

bool MCProgram::CreateProgram(MCShader* vsShader, MCShader* psShader)
{
    //第一步:创建Program
    unsigned int programObj = GL30::glCreateProgram();
    if(programObj == 0)
    {
        return false;
    }

    //第二步:附加着色程序
    GL30::glAttachShader(programObj, vsShader->GetHandle());
    GL30::glAttachShader(programObj, psShader->GetHandle());

    //第三步:链接着色程序
    GL30::glLinkProgram(programObj);

    //检查链接是否成功
    if(CheckStatus(programObj))
    {
        m_Handle = programObj;

        return true;
    }
    else
    {
        GL30::glDeleteProgram(programObj);  

        return false;
    }
}

源码下载: LinkProgram

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

Copyright © 1999-2019, lu16.com, All Rights Reserved