创建和编译着色器

| 分类 cocos2d-x  | 标签 opengles  cocos2d-x 

本文为xiedantibu在学习opengles的笔记 ,转载请注明作者及出处! ###目录 —-     创建着色器
    加载着色器源码
    编译着色器
    获取编译状态
    调用info日志
    获取着色器源码
    cocos2d-x编译着色器示例
    Reference


####创建着色器GLuint glCreateShader(GLenum type)

type:着色器的类型 GL_VERTEX_SHADER或者GL_FRAGMENT_SHADER.

使用glCreateShader你能依据输入参数创建一个顶点着色器或片段着色器,返回值是个新着色器的句柄,是一个非零的整数值,如果为0则说明发生了错误。不使用了,用glDeleteShader删除它。

void glDeleteShader(GLuint shader)

shader:要删除的着色器句柄.

如果着色器正连接着一个项目对象,glDeleteShader不会立刻删除着色器,而是设置删除标记,一旦着色器不再连接项目对象,才删除着色器使用的内存。


####加载着色器源码

void glShaderSource(GLuint shader, GLsizei count,const char** string,const GLint* length)

shader :着色器对象句柄
count  :着色器源码的字符数,着色器由字符串组成,每个着色器仅有一个主函数main
string :一个由count行GLchar类型的字符串组成的数组,用来表示着色器的源代码数据,string中的字符串可以是NULL结尾的,也可以不是
length :可以是以下三种值的一种。如果length是NULL,那么我们假设string给出的每行字符串都是NULL结尾的。否则,length中必须有count个元素,它们分别表示string中对应行的长度。如果length数组中的某个值是一个整数,那么它表示对应的字符串中的字符数。如果某个值是负数,那么string中的对应行假设为NULL结尾

####编译着色器

void glCompileShader(GLuint shader)

shader :着色器对象句柄

####获取编译状态

void glGetShaderiv(GLuint shader, GLenum pname,GLint *params)

shader :着色器句柄
pname  :需要查询的信息.GL_COMPILE_STATUS|GL_DELETE_STATUS|GL_INFO_LOG_LENGTH|GL_SHADER_SOURCE_LENGTH|GL_SHADER_TYPE
Params :返回查询结果的整型指针

使用GL_COMPILE_STATUS参数查询编译是否成功,成功返回GL_TRUE,失败返回GL_FALSE。如失败,编译错误被写入 info日志。info日志记录了编译器的任何错误和警告。 即使编译成功,同样也有info日志,可以使用GL_INFO_LOG_LENGTH查询 info日志长度。 可以调用glGetShaderInfoLog调用info日志。使用GL_SHADER_TYPE查询着色器类型是GL_VERTEX_SHADER或者GL_FRAGMENT_SHADER.使用GL_SHADER_SOURCE_LENGTH查询着色器源码长度,即使着色器为空。使用GL_DELETE_STATUS查询着色器是否被glDeleteShader标记删除。


####调用info日志

void glGetShaderInfoLog(GLuint shader, GLsizei maxLength, GLsizei *length, GLchar *infoLog)

shader :handle to the shader object to get the info log for
maxLength :the size of the buffer to store the info log in
length :the length of the info log written (minus the null terminator). If the length does not need to be known, this parameter can be NULL
infoLog :pointer to the character buffer to store the info log in

要使用glGetShaderInfoLog调用info日志,首先要通过glGetShaderiv查询GL_INFO_LOG_LENGTH,因为只有分配足够的字符串才能存储info log。


####获取着色器源码void glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source)

shader :指定查询的着色器
bufsize :the number of bytes available in the array source for returning the shader’s source
length :the length of the returned shader string
source :指定存储着着色器源码的GLchar类型数组 ---  --- <a id='cocobuildshader' name='cocobuildshader'> </a> ####[cocos2d-x编译着色器示例](#top) --- cocos2d-x编译着色器的代码主要封装在GLProgram类中,下面就来看看GLProgram中的compileShader方法。

bool GLProgram::compileShader(GLuint * shader, GLenum type, const GLchar* source)
{
GLint status;
if (!source)
{
    return false;
}
const GLchar *sources[] = {
    "uniform mat4 CC_PMatrix;\n"
    "uniform mat4 CC_MVMatrix;\n"
    "uniform mat4 CC_MVPMatrix;\n"
    "uniform mat3 CC_NormalMatrix;\n"
    "uniform vec4 CC_Time;\n"
    "uniform vec4 CC_SinTime;\n"
    "uniform vec4 CC_CosTime;\n"
    "uniform vec4 CC_Random01;\n"
    "uniform sampler2D CC_Texture0;\n"
    "uniform sampler2D CC_Texture1;\n"
    "uniform sampler2D CC_Texture2;\n"
    "uniform sampler2D CC_Texture3;\n"
    "//CC INCLUDES END\n\n",
    source,
};
*shader = glCreateShader(type);//创建着色器
glShaderSource(*shader, sizeof(sources)/sizeof(*sources), sources, nullptr);//加载着色器源码
glCompileShader(*shader);//编译着色器源码
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);//获取编译状态
if (! status)//如果编译失败
{
    GLsizei length;
    glGetShaderiv(*shader, GL_SHADER_SOURCE_LENGTH, &length);//获取着色器源码长度
    GLchar* src = (GLchar *)malloc(sizeof(GLchar) * length);//创建保存源码空间
    glGetShaderSource(*shader, length, nullptr, src);//获取着色器源码
    CCLOG("cocos2d: ERROR: Failed to compile shader:\n%s", src);//打印出错的编译源码    
    if (type == GL_VERTEX_SHADER)//顶点着色器
    {
        CCLOG("cocos2d: %s", getVertexShaderLog().c_str());//打印顶点着色器出错log
    }
    else//片元着色器
    {
        CCLOG("cocos2d: %s", getFragmentShaderLog().c_str());//打印片元着色器出错log
    }
    free(src);//回收保存源码空间

    return false;;
}
return (status == GL_TRUE);
} 关于打印顶点或者片元着色器出错log的方法,其实就是上文提到的事先得先通过`glGetShaderiv`查询`GL_INFO_LOG_LENGTH`,获取log的长度,再通过`glGetShaderInfoLog`获取info日志,只不过cocos封装了下,方便调用。

//获取顶点着色器log
std::string GLProgram::getVertexShaderLog() const
{
return this->logForOpenGLObject(_vertShader, (GLInfoFunction)&glGetShaderiv, (GLLogFunction)&glGetShaderInfoLog);//传入的是指向glGetShaderiv方法的指针以及指向glGetShaderInfoLog方法的指针
}
//获取片元着色器log
std::string GLProgram::getFragmentShaderLog() const
{
return this->logForOpenGLObject(_fragShader, (GLInfoFunction)&glGetShaderiv, 	(GLLogFunction)&glGetShaderInfoLog);
}
//上诉两个方法其实调用的都是同一个方法`logForOpenGLObject`,只不过传入的参数不同,分别是顶点着色器的句柄以及片元着色器的句柄,至于其他两个参数,传的是一样的。

std::string GLProgram::logForOpenGLObject(GLuint object, GLInfoFunction infoFunc, GLLogFunction logFunc) const
{
std::string ret;
GLint logLength = 0, charsWritten = 0;
infoFunc(object, GL_INFO_LOG_LENGTH, &logLength);//回调glGetShaderiv方法,获取log长度
if (logLength < 1)
    return "";
char *logBytes = (char*)malloc(logLength);//根据logLength长度开辟一片空间保存log
logFunc(object, logLength, &charsWritten, logBytes);//回调glGetShaderInfoLog获取log内容,保存在logBytes中
ret = logBytes;//将logBytes赋值给ret
free(logBytes);//回收保存log的空间
return ret;
}

####在本文中主要是结合cocos2d-x,回顾下着色器的创建和编译,以及在编译出错的情况下,查询编译状态以及出错信息的处理。。。


####Reference

青春是一场大雨,即使感冒了,还盼回头再淋一次...image...微笑永远是一个人身上最好看的东西...


PREVIOUS     NEXT