Modern OpenGL ES: ndk编程——画一个三角形之Shader工程

OpenGL ES2.0以后,想画一个东西必须使用 shader来完成。  而使用shader需要创建shader工程。使用shader来画一个东西的大体步骤如下:
1 创建和编译shader 
2 创建和链接shader工程
3 为shader工程设置 uniform 和 attrubte变量
4 Shader编译 并链接到工程,成最终的可执行文件


Vertex Shader 和 Fragment Shader
OpenGL 有很多种Shader对象,但我们需要经常使用的只有两种,一种是 光栅化之前的Vertex Shader ,一种是光栅化之后的Fragment Shader
光栅化,就是将OpenGL中定义的 物体的顶点映射到屏幕像素的过程。

光栅化之前,我们需要定义所画物体的顶点,顶点包括 位置,颜色等属性, 通过这些属性能实现物体的不同方向和位置,以及不同的表像、光照,这些都是通过 Vertex Shader来完成的

光栅化之后,我们需要将所画物体映射为屏幕的像素,最终现实出来图像,这一步我们可以决定现实 图像的哪一部分,如果两个图像叠加在一起,那么它们的混合模式是怎样的? 这些都是通过 Fragment Shader完成的


创建和编译Shader对象
 1 创建Shader
     GLuint glCreateShader(GLenum type)
       参数: 要创建的shader类型,如GL_VERTEX_SHADER, GL_FRAGMENT_SHADER
       返回: 返回这个Shader对象的句柄
       功能: 获得了该shader的句柄后,我们就可以进一步对它操作了,如送入shader source, 编译shader, 删除shader。

 2 删除Shader
    void glDeleteShader(GLuint shader)
     参数: 删除的shader句柄
     注意: 如果该shader已经依附了一个shader工程,那么调用该函数并不能立即删除shader对象,知道该对象不再使用
  
 3 提供shader源码
   void glShaderSource(GLuint shader,  GLsizei count,  const GLchar* const *string,  const  GLint *length)

   参数: 
       shader:
        count:  shader 源码字串的个数。  一个完整的shader 源码可能会有很多个字符串组成
        const GLchar* const *string: 指向一组shader源码字符串
        length: shader源码的字数,如果NULL,就是字符串到NULL时结束

4 编译源码
   shader对象,一旦被赋值了字符串
   void glCompileShader(GLuint shader)
   
5 获取shader信息
   void  glGetShaderiv(GLuint shader, GLenum pname, GLint *params)
  参数:
    shader: 
     pname: 要获取信息的类型:
      GL_COMPILE_STATUS
      GL_DELETE_STATUS
      GL_INFO_LOG_LEGTH
      GL_SHADER_SOURCE_LENGTH
      GL_SHADER_TYPE
   params:
     用一个 整数来代表结果
  
  GL_COMPILE_STATUS 表示要查询编译信息, params如果是 GL_TRUE, 表示编译成功, 反之,失败

6  获取shader日志信息
    如果第5步获取的信息失败, 会将错误信息写的日志里,通过以下函数获取
    void glGetSahderInfoLog(GLuint shader,  GLsizei maxLength, GLsizei *length, GLchar *infoLog)
    参数:
      shader : 
      maxLength: 需要存储 info log的buffer大小
      length: 需要写进info的长度。 如果不知道长度,可以是NULL
     infoLog: 指向log字符串的buffer。

创建和链接工程:
   继创建完shader对象之后,我们需要创建shader工程了。 shader工程更像是 一个 容纳了shader对象的容器,假如shader好比.obj的话,那么shader工程还具有将它们按照 管线流程,将这些.obj编译链接成一个 .o文件。

 1 创建 shader工程
    GLuint glCreateProgram()
    如创建shader对象一样, 创建了一个program的句柄
2  删除shader工程
    void glDeleteProgram(GLuint program)

3  需要将shader对象添加到 shader program这个容器中
   void glAttachShader(GLuint program, GLuint shader)
4 Link完,或者Link失败,都需要删除shader工程里的shader对象
   void glDetachShader(GLuint program, GLuint shader)
5 链接这些shader对象
  void glLinkProgram(GLuint program)
 Link的目的是要将这些shader对象 变为一个GPU能执行的可执行文件

6  与获取shader信息一样,也可以获取shader工程信息
    void glGetProgramiv(GLuint program, GLenum pname, GLint *params)
     参数:
       program:
       pname: 
          GL_ACTIVE_ATTRIBUTES  // 激活的(使用的)attribute变量的个数
          GL_ACTIVE_ATTRIBUTE_MAX_LENGTH //attribute名字的最大长度  
          GL_ACTIVE_UNIFORM_BLOCK
          GL_ACTIVE_UNIFORM_BLOCK_MAX_LENGTH
          GL_ACTIVE_UNIFORMS
          GL_ACTIVE_UNIFORM_MAX_LENGTH
          GL_ATTACHED_SHADERS  // 依附的 shader数
          GL_DELETE_STATUS
          GL_INFO_LOG_LENGTH  
          GL_LINK_STATUS   // 检测链接是否成功
         GL_PROGRAM_BINARY_RETERIEVABLE_HINT
         GL_TRANSFORM_FEEDBACK_BUFFER_MODE   
         GL_TRANSFORM_FEEDBACK_VARYINGS  //在feedback 阶段输出的变量数
         GL_TRANSFORM_FEEDBACK_VARING_MAX_LENGTH
         GL_VALIDATE_STATUS


  7 获取shader工程日志
    void glGetProgramInfoLog(GLuint program, GLsizei maxLength, GLsizel *length, GLchar *infoLog)
    参数:
    program:
    maxLength: 存储的最大buffer大小
    length:   需要写入的字符长度,如果不知道天下null
    infoLog: 字符串

 8  一旦创建好, 我们就可以渲染该shader工程了。 这之前,还需要确定shader工程是否有效
     void glValidateProgram(GLuint program)

 9 使用shader工程
   void glUseProgram(GLuint program)
 

   


     
    
       
  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章