创建和编译着色器

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

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


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

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

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

void glDeleteShader(GLuint shader)

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

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


####加载着色器源码

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

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

####编译着色器

void glCompileShader(GLuint shader)

  1. shader :着色器对象句柄

####获取编译状态

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

  1. shader :着色器句柄
  2. pname :需要查询的信息.GL_COMPILE_STATUS|GL_DELETE_STATUS|GL_INFO_LOG_LENGTH|GL_SHADER_SOURCE_LENGTH|GL_SHADER_TYPE
  3. 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)

  1. shader :handle to the shader object to get the info log for
  2. maxLength :the size of the buffer to store the info log in
  3. 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
  4. 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)

  1. shader :指定查询的着色器
  2. bufsize :the number of bytes available in the array source for returning the shaders source
  3. length :the length of the returned shader string
  4. source :指定存储着着色器源码的GLchar类型数组 --- --- <a id='cocobuildshader' name='cocobuildshader'> </a> ####[cocos2d-x编译着色器示例](#top) --- cocos2d-x编译着色器的代码主要封装在GLProgram类中,下面就来看看GLProgram中的compileShader方法。
  5. bool GLProgram::compileShader(GLuint * shader, GLenum type, const GLchar* source)
  6. {
  7. GLint status;
  8. if (!source)
  9. {
  10. return false;
  11. }
  12. const GLchar *sources[] = {
  13. "uniform mat4 CC_PMatrix;\n"
  14. "uniform mat4 CC_MVMatrix;\n"
  15. "uniform mat4 CC_MVPMatrix;\n"
  16. "uniform mat3 CC_NormalMatrix;\n"
  17. "uniform vec4 CC_Time;\n"
  18. "uniform vec4 CC_SinTime;\n"
  19. "uniform vec4 CC_CosTime;\n"
  20. "uniform vec4 CC_Random01;\n"
  21. "uniform sampler2D CC_Texture0;\n"
  22. "uniform sampler2D CC_Texture1;\n"
  23. "uniform sampler2D CC_Texture2;\n"
  24. "uniform sampler2D CC_Texture3;\n"
  25. "//CC INCLUDES END\n\n",
  26. source,
  27. };
  28. *shader = glCreateShader(type);//创建着色器
  29. glShaderSource(*shader, sizeof(sources)/sizeof(*sources), sources, nullptr);//加载着色器源码
  30. glCompileShader(*shader);//编译着色器源码
  31. glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);//获取编译状态
  32. if (! status)//如果编译失败
  33. {
  34. GLsizei length;
  35. glGetShaderiv(*shader, GL_SHADER_SOURCE_LENGTH, &length);//获取着色器源码长度
  36. GLchar* src = (GLchar *)malloc(sizeof(GLchar) * length);//创建保存源码空间
  37. glGetShaderSource(*shader, length, nullptr, src);//获取着色器源码
  38. CCLOG("cocos2d: ERROR: Failed to compile shader:\n%s", src);//打印出错的编译源码
  39. if (type == GL_VERTEX_SHADER)//顶点着色器
  40. {
  41. CCLOG("cocos2d: %s", getVertexShaderLog().c_str());//打印顶点着色器出错log
  42. }
  43. else//片元着色器
  44. {
  45. CCLOG("cocos2d: %s", getFragmentShaderLog().c_str());//打印片元着色器出错log
  46. }
  47. free(src);//回收保存源码空间
  48. return false;;
  49. }
  50. return (status == GL_TRUE);
  51. } 关于打印顶点或者片元着色器出错log的方法,其实就是上文提到的事先得先通过`glGetShaderiv`查询`GL_INFO_LOG_LENGTH`,获取log的长度,再通过`glGetShaderInfoLog`获取info日志,只不过cocos封装了下,方便调用。
  52. //获取顶点着色器log
  53. std::string GLProgram::getVertexShaderLog() const
  54. {
  55. return this->logForOpenGLObject(_vertShader, (GLInfoFunction)&glGetShaderiv, (GLLogFunction)&glGetShaderInfoLog);//传入的是指向glGetShaderiv方法的指针以及指向glGetShaderInfoLog方法的指针
  56. }
  57. //获取片元着色器log
  58. std::string GLProgram::getFragmentShaderLog() const
  59. {
  60. return this->logForOpenGLObject(_fragShader, (GLInfoFunction)&glGetShaderiv, (GLLogFunction)&glGetShaderInfoLog);
  61. }
  62. //上诉两个方法其实调用的都是同一个方法`logForOpenGLObject`,只不过传入的参数不同,分别是顶点着色器的句柄以及片元着色器的句柄,至于其他两个参数,传的是一样的。
  63. std::string GLProgram::logForOpenGLObject(GLuint object, GLInfoFunction infoFunc, GLLogFunction logFunc) const
  64. {
  65. std::string ret;
  66. GLint logLength = 0, charsWritten = 0;
  67. infoFunc(object, GL_INFO_LOG_LENGTH, &logLength);//回调glGetShaderiv方法,获取log长度
  68. if (logLength < 1)
  69. return "";
  70. char *logBytes = (char*)malloc(logLength);//根据logLength长度开辟一片空间保存log
  71. logFunc(object, logLength, &charsWritten, logBytes);//回调glGetShaderInfoLog获取log内容,保存在logBytes中
  72. ret = logBytes;//将logBytes赋值给ret
  73. free(logBytes);//回收保存log的空间
  74. return ret;
  75. }

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


####Reference

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


PREVIOUS     NEXT