OpenGL-ES-3-0---着色器源码、实例-与-管线程序源码、实例-的联系与细节-以及-各自的应用流程和相关API

262 阅读5分钟

#应用步骤

  • 着色器和程序对象的概述
  • 创建和编译着色器
  • 创建和链接程序 【本文至此】

  • 获取和设置统一变量
  • 获取和设置属性
  • 着色器编译器和程序二进制代码

#着色器与程序

  • 需要创建两种基本对象才能用着色器进行渲染着色器对象程序对象

  • 要理解着色器与程序之间的关系的话, 可以把它们比作C语言编译器链接程序

  • C编译器 为一段源代码生成 目标代码(如.obj或者.o文件); 创建目标文件之后,C链接程序对象文件 链接为 最后的程序
    OpenGL ES在着色器的表现上 使用类似的方式—— 着色器对象 是 包含单个着色器的对象, 【shader = GLES30.glCreateShader ( type );
    源代码提供给着色器对象, 【 GLES30.glShaderSource ( shader, shaderSrc );
    然后把 着色器对象 编译为一个 目标形式(类似与.obj文件); 【GLES30.glCompileShader ( shader );
    编译之后, 着色器对象 便可以 连接到 一个程序对象程序对象可以连接多个 着色器对象

//向程序中加入顶点着色器 片元着色器
GLES30.glAttachShader ( programObject, vertexShader );
GLES30.glAttachShader ( programObject, fragmentShader );
  • 在OpenGL ES中, 每个程序对象必须连接一个顶点着色器和一个片段着色器, 程序对象 被链接为 用于渲染的最后“可执行程序”;
// 基于顶点着色器与片段着色器创建程序
      programObject = GLES30.glCreateProgram();

      //创建失败,就拜拜
      if ( programObject == 0 )
      {
         return;
      }

      //向程序中加入顶点着色器 片元着色器
      GLES30.glAttachShader...

      // Bind vPosition to attribute 0
      GLES30.glBindAttribLocation ( programObject, 0, "vPosition" );

      // 链接程序
      GLES30.glLinkProgram ( programObject );

      // 把链接成功的 渲染管线程序id 存入数组linked
      GLES30.glGetProgramiv ( programObject, GLES30.GL_LINK_STATUS, linked, 0 );

      //若链接失败则报错 并 删除程序
      if ( linked[0] == 0 )
      {
        ...
      }

      // 保存 链接成功的 渲染管线程序id 到 全局变量
      mProgramObject = programObject;

####即获得链接后的着色器对象 的 一般步骤如下:

  1. 创建一个顶点着色器对象和一个片段着色器对象;
  2. 将 每一套 着色器源代码 连接到 对应的 着色器对象;
  3. 编译着色器对象;
  4. 创建一个程序对象;
  5. 将编译后的着色器对象连接到程序对象;
  6. 链接程序对象;

#####创建和编译一个 着色器对象 (相关API)

  • Create

  • Delete

  • glShaderSource 加载 着色器代码Android API中 只有shaderstring两个参数;

  • compileShader 编译

  • glGetShaderiv 查看 着色器的 编译结果状态或其他的各种信息
    【通过pname控制】注意第三个参数是存放结果的int类型数组,对应params

  • glGetShaderInfoLog Android API只需要提供一个shader实例即可:【API返回结果即Log信息】

  • 来自 OpenGL ES 3.0 | 围绕HelloTriangle实战案例 展开 渲染流程分析 中的例程:

   private int LoadShader ( int type, String shaderSrc )
   {
      int shader;
      int[] compiled = new int[1];

      // Create the shader object
      shader = GLES30.glCreateShader ( type );

      if ( shader == 0 )
      {
         return 0;
      }

      // Load the shader source
      // 加载 着色器代码
      GLES30.glShaderSource ( shader, shaderSrc );

      // Compile the shader
      // 编译 着色器代码
      GLES30.glCompileShader ( shader );

      // Check the compile status
      // 查看 着色器编译结果状态
      GLES30.glGetShaderiv (shader, GLES30.GL_COMPILE_STATUS, compiled, 0 );

      //编译失败,则 报错 并 删除着色器实例
      if ( compiled[0] == 0 )
      {
         Log.e ( TAG, GLES30.glGetShaderInfoLog ( shader ) );
         GLES30.glDeleteShader ( shader );
         return 0;
      }

      //编译成功,则返回 着色器id
      return shader;
   }

#####创建和链接管线程序 (相关API) ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/95862a8de5ac4a7691c58111a60e6f77~tplv-k3u1fbpfcp-zoom-1.image) - Create![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6a018a93afc645b8a163e89855d5a672~tplv-k3u1fbpfcp-zoom-1.image)![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d465ee4b051f4bb6a6eb0fb73b46f4b1~tplv-k3u1fbpfcp-zoom-1.image)
  • delete

  • Attach【着色器实例 连接 管线程序实例】

  • Detach【断开 着色器实例 与 管线程序实例 的连接】

  • 链接(程序对象 成功链接之后,就可使用 程序对象 进行渲染了!)

  • glGetProgramiv 查看 管线程序实例的 编译结果状态或其他的各种信息 【通过pname 标签控制 想要查询的内容params返回存储结果的int类型数组 (类似glGetShaderiv)】

  • glGetProgramInfoLogAndroid API只需要提供一个 管线程序实例 即可【API返回结果即Log信息】:

  • glValidateProgram:用于检查, 一般不使用;

  • glUseProgram:

   ///
   // Initialize the shader and program object
   // 初始化 着色器 和 渲染管线程序
   //
   public void onSurfaceCreated ( GL10 glUnused, EGLConfig config )
   {
      String vShaderStr =
         "#version 300 es 			  \n"
         +   "in vec4 vPosition;           \n"
         + "void main()                  \n"
         + "{                            \n"
         + "   gl_Position = vPosition;  \n"
         + "}                            \n";

      String fShaderStr =
         "#version 300 es		 			          	\n"
         + "precision mediump float;					  	\n"
         + "out vec4 fragColor;	 			 		  	\n"
         + "void main()                                  \n"
         + "{                                            \n"
         + "  fragColor = vec4 ( 0.0, 0.8, 1.0, 1.0 );	\n"
         + "}                                            \n";

      int vertexShader;//加载好的 顶点着色器实例
      int fragmentShader;//加载好的 片段着色器实例
      int programObject;//自定义的渲染管线程序id
      int[] linked = new int[1];//存放链接成功 渲染管线程序id 的数组

      // Load the vertex/fragment shaders
      // 【调用 LoadShader() 】加载着色器实例
      vertexShader = LoadShader ( GLES30.GL_VERTEX_SHADER, vShaderStr );
      fragmentShader = LoadShader ( GLES30.GL_FRAGMENT_SHADER, fShaderStr );

      // Create the program object
      // 基于顶点着色器与片段着色器创建程序
      programObject = GLES30.glCreateProgram();

      //创建失败,就拜拜
      if ( programObject == 0 )
      {
         return;
      }

      //向程序中加入顶点着色器 片元着色器
      GLES30.glAttachShader ( programObject, vertexShader );
      GLES30.glAttachShader ( programObject, fragmentShader );

      // Bind vPosition to attribute 0
      GLES30.glBindAttribLocation ( programObject, 0, "vPosition" );

      // Link the program
      // 链接程序
      GLES30.glLinkProgram ( programObject );

      // Check the link status
      // 把链接成功的 渲染管线程序id 存入数组linked
      GLES30.glGetProgramiv ( programObject, GLES30.GL_LINK_STATUS, linked, 0 );

      //若链接失败则报错 并 删除程序
      if ( linked[0] == 0 )
      {
         Log.e ( TAG, "Error linking program:" );
         Log.e ( TAG, GLES30.glGetProgramInfoLog ( programObject ) );
         GLES30.glDeleteProgram ( programObject );
         return;
      }

      // Store the program object
      // 保存 链接成功的 渲染管线程序id 到 全局变量
      mProgramObject = programObject;

      //指定清除屏幕用的颜色
      GLES30.glClearColor ( 1.0f, 1.0f, 1.0f, 0.0f );
   }

   // /
   // Draw a triangle using the shader pair created in onSurfaceCreated()
   // 使用onSurfaceCreated()中创建好的 着色器对(一对顶点、片段着色器) 画一个三角形
   //
   public void onDrawFrame ( GL10 glUnused )
   {
      // Set the viewport
      // viewport【窗口】
      GLES30.glViewport ( 0, 0, mWidth/2, mHeight/2 );

      // Clear the color buffer
      GLES30.glClear ( GLES30.GL_COLOR_BUFFER_BIT );

      // Use the program object
      // 指定使用某套shader程序
      GLES30.glUseProgram ( mProgramObject );

      // Load the vertex data
      // vertex【顶点】
      // 将顶点位置数据【mVertices】传送进 渲染管线
      GLES30.glVertexAttribPointer ( 0, 3, GLES30.GL_FLOAT, false, 0, mVertices );
      //启用顶点位置数据
      GLES30.glEnableVertexAttribArray ( 0 );

//      GLES30.glDrawArrays ( GLES30.GL_TRIANGLES, 0, 3 );
//      绘制
      GLES30.glDrawArrays ( GLES30.GL_TRIANGLE_STRIP, 0, 3 );
   }










参考自:

  • 《OPENGL ES 3.0编程指南(第2版)》