着色器和程序

  • 一、前言
  • 二、着色器和程序
    • 2.1 创建和编译一个着色器
      • 2.1.1 创建着色器
      • 2.1.2 删除着色器
      • 2.1.3 提供着色器源代码
      • 2.1.4 编译色器
      • 2.1.4 查询有关着色器对象的信息
        • 2.1.4.1 查询`GL_COMPILE_STATUS`
        • 2.1.4.2 查询`GL_SHADER_TYPE`
        • 2.1.4.3 查询`GL_DELETE_STATUS`
      • 2.1.5 获取信息日志
  • 三、加载着色器示例

一、前言

在博客 【我的OpenGL学习进阶之旅】你好,三角形:一个OpenGL ES 3.0示例。 分别使用C++ Native & Java 两种方式来实现 中,我们介绍了绘制一个三角形的简单程序。

在那个例子中,我们创建了两个着色器对象(一个顶点着色器,一个片段着色器)和一个程序对象,以渲染三角形。

着色器对象和程序对象是使用OpenGL ES 3.0着色器的基本概念。

接下来,我们要讲解的主题,如下所示:

  • 着色器和程序对象概述
  • 创建和编译着色器
  • 创建和链接程序
  • 获取和设置统一变量
  • 获取和设置属性
  • 着色器编译器和程序二进制代码

二、着色器和程序

需要创建两个基本对象才能用着色器进行渲染:着色器对象和程序对象。

理解着色器对象和程序对象的最佳方式就是将它们比作C语言的编译器和链接程序。 C编译器为一段源代码生成目标代码(例如,.obj或者.o文件)。在创建目标文件之后,C链接程序将对象文件链接为最后的程序。

OpenGL ES 在着色器的表现上使用类似的方式。

  1. 着色器对象是包含单个着色器的对象。
  2. 源代码提供给着色器对象,然后着色器对象被编译为一个目标形式(类似与.obj文件)。
  3. 编译之后,着色器对象可以连接到一个程序对象。程序对象可以连接多个着色器对象。
  4. 在OpenGL ES中,每个程序对象必须连接一个顶点着色器和一个片段着色器(不多也不少),这和桌面OpenGL不同。
  5. 程序对象被链接为用于渲染的最后“可执行程序”。

获得连接后的着色器对象的一般过程包括6个步骤:

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

如果没有错误,就可以在任何时候通知GL使用这个程序绘图。

这篇博客我们先介绍着色器相关的知识。

2.1 创建和编译一个着色器

2.1.1 创建着色器

使用着色器对象的第一步是创建着色器,这可以用glCreateShader完成。

 GLuint glCreateShader (GLenum type);


参数 type : 创建的着色器类型可以是GL_VERTEX_SHADER或者GL_FRAGMENT_SHADER

调用glCreateShader 将根据传入的 type 参数创建一个新的顶点着色器或者片段着色器。 返回值是指向新着色器对象的句柄。

2.1.2 删除着色器

当完成着色器对象时,可以使用glDeleteShader 删除

void glDeleteShader (GLuint shader);

参数shader表示: 要删除的着色器对象的句柄。

注意,如果一个着色器链接到一个程序对象,那么调用glDeleteShader不会立刻删除着色器,而且将着色器标记为删除,在着色器不再连接到任何程序对象时,它的内存将被释放

2.1.3 提供着色器源代码

一旦创建着色器对象,下一件事通常是使用glShaderSource提供着色器源代码

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

参数讲解:

  • shader
    指向着色器对象的句柄
  • count
    着色器源字符串的数量。着色器可以由多个源字符串组成,但是每个着色器只能有一个main函数。
  • string
    指向保存数量为count的着色器源字符串的数组指针。
  • length
    指向保存每个着色器字符串大小且元素数量为count的整数数组指针。如果lengthNULL,着色器字符串将被认定为空。如果length不为NULL,则它的每个元素保存对应string数组的着色器的字符数量。如果任何元素的length值均小于0,则该字符串被认定以null结束。

2.1.4 编译色器

指定着色器源代码之后,下一步是用glCompileShader编译着色器。

void glCompileShader (GLuint shader);

参数 shader 表示: 需要编译的着色器对象句柄。

2.1.4 查询有关着色器对象的信息

调用glCompileShader将编译已经保存在着色器对象的着色器源代码。
和常规的语言编译器一样,编译之后你想知道的第一件事是不是没有错误。你可以使用glGetShaderiv查询这一信息和其他有关着色器对象的信息。

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
    指向查询结果的整数存储位置的指针。

2.1.4.1 查询GL_COMPILE_STATUS

要检查着色器是否编译成功,可以用pname参数GL_COMPILE_STATUS在着色器对象上调用glGetShaderiv
如果着色器编译成功,结果将是GL_TRUE。如果编译失败,结果将是GL_FALSE,编译错误将写入信息日志

信息日志是由编译器写入并包含错误信息或者警告的日志。
即使编译操作成功,也会在信息日志中写入信息。要检索信息日志,可以使用GL_INFO_LOG_LENGTH查询它的长度。

日志本身可以用glGetShaderInfoLog检索。

2.1.4.2 查询GL_SHADER_TYPE

查询GL_SHADER_TYPE 将返回着色器类型:GL_VERTEX_SHADER或者GL_FRAGMENT_SHADER

2.1.4.3 查询GL_DELETE_STATUS

查询GL_DELETE_STATUS 返回着色器是否用glDeleteShader 标记为删除。

2.1.5 获取信息日志

编译着色器并检查信息日志长度之后,你可能希望检索信息日志(特别是在编译失败时查看原因)。为此,首先需要查询GL_INFO_LOG_LENGTH并分配一个足以存储信息日志的字符串。
然后,用glGetShaderInfoLog检索信息日志。

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


参数说明:

  • shader
    需要获取信息日志的着色器对象句柄
  • bufSize
    保存信息日志的缓冲区大小
  • length
    写入的信息日志的长度(减去null终止符)。如果不需要知道长度,这个参数可以为NULL
  • infoLog
    指向保存信息日志的字符缓冲区的指针。

信息日志没有任何强制的格式或者必须的信息。但是,大部分OpenGL ES 3.0实现将返回错误信息,包括编译器发现的错误源代码行号。有些实现还在日志中提供警告或者附件信息。

比如我的博客 【我的OpenGL学习进阶之旅】解决着色器编译错误:#version directive must occur on the first line of the shader中描述的,产生的信息:

2021-11-15 15:09:07.406 26065-26107/opengles3.book.hello_Triangle E/ESShader: ERROR: 0:2: '' : #version directive must occur on the first line of the shader ERROR: 0:9: 'in' : storage qualifier supported in GLSL ES 3.00 only  

三、加载着色器示例

到现在为止,我们已经说明了创建着色器、编译、找出编译状态和查询信息日志所需的所有函数。

下面写一个示例,来加载一个着色器。

/*** Loads the given source code as a shader of the given type.** 负责 加载着色器源代码、编译并检查错误。他返回一个着色器对象*/
static GLuint loadShader(GLenum shaderType, const char** source) {// Create the shader objectGLuint shader;GLint compiled;// Create the shader object// shaderType 可以是  GL_VERTEX_SHADER  或者  GL_FRAGMENT_SHADERshader = glCreateShader(shaderType);if (shader == 0) {return 0;}// Load the shader sourceglShaderSource(shader, 1, source, nullptr);// Compile the shaderglCompileShader(shader);// Check the compile statusglGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);if (!compiled) {GLint infoLen = 0;glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);if (infoLen > 1) {char* infoLog = (char*)malloc(sizeof(char) * infoLen);// 检索信息日志glGetShaderInfoLog(shader, infoLen, nullptr, infoLog);LOGE("Error compiling shader:\n%s\n", infoLog);free(infoLog);}// 删除ShaderglDeleteShader(shader);return 0;}return shader;
}

【我的OpenGL学习进阶之旅】着色器和程序(上)------着色器相关推荐

  1. 【我的OpenGL学习进阶之旅】介绍一下 绘制图元

    目录 一.绘制图元 1.1 `glDrawArrays` 1.1.1 `glDrawArrays`API说明 1.1.2 `glDrawArrays`API示例 1.2 `glDrawElements ...

  2. 【我的OpenGL学习进阶之旅】C++如何加载TGA文件?

    一.TGA文件相关介绍 通过前面的博客 [我的OpenGL学习进阶之旅]什么是TGA文件以及如何打开TGA文件? 地址:https://ouyangpeng.blog.csdn.net/article ...

  3. 【我的OpenGL学习进阶之旅】【持续更新】关于学习OpenGL的一些资料

    目录 一.相关书籍 OpenGL 方面 C方面 NDK 线性代数 二.相关博客 2.0 一些比较官方的链接 2.1 OpenGL着色器语言相关 2.2 [[yfan]](https://segment ...

  4. 【我的OpenGL学习进阶之旅】OpenGL ES 3.0新功能

    目录 1.1 纹理 1.2 着色器 1.3 几何形状 1.4 缓冲区对象 1.5 帧缓冲区 OpenGL ES 2.0 开创了手持设备可编程着色器的时代,在驱动大量设备的游戏.应用程序和用户接口中获得 ...

  5. 【我的OpenGL学习进阶之旅】着色器编译器和程序二进制码

    目录 一.着色器编译器 二.程序二进制码 2.1 glGetProgramBinary 2.2 glProgramBinary 一.着色器编译器 当你要求OpenGL ES 编译和链接着色器的时候,光 ...

  6. 【我的OpenGL学习进阶之旅】解决着色器语法错误:The shader uses varying u_Color, but previous shader does not write to it

    一.错误描述 在加载完顶点着色器和片段着色器,然后link生成program的时候,出现了错误,如下所示: 2021-12-31 09:34:01.072 15937-16006/com.oyp.op ...

  7. 【我的OpenGL学习进阶之旅】解决着色器编译错误:#version directive must occur on the first line of the shader

    目录 一.问题描述 二.分析错误 三.解决问题 三.总结 一.问题描述 今天编写一个OpenGL ES的demo,发现没有任何图元输出. 查看日志,发现报了如下错误: 2021-11-15 15:09 ...

  8. 【我的OpenGL学习进阶之旅】着色器GLSL运行时报错: ERROR: 0:40: ‘gl_FragColor‘ : undeclared identifier

    一.错误描述 把从一段GLSL2.0的代码改造成GLSL3.0代码的时候,运行报错,如下所示: [GLUtils.cpp][loadShader][42]: GLUtils::loadShader e ...

  9. 【我的OpenGL学习进阶之旅】解决关于在OpenGL ES开发中GLSurfaceView调用了onPause和onResume方法,然后息屏亮屏之后GLSurfaceView黑屏的问题

    目录 一.问题描述 二.分析问题 2.1 排查onPause和onResume方法 2.2 注释掉onPause和onResume方法 2.3 GLSurfaceView 关于Activity生命周期 ...

最新文章

  1. [bzoj2456]mode
  2. 密码学系列之:加密货币中的scrypt算法
  3. java interestops_Java Channel.setInterestOps方法代码示例
  4. mybatis笔记之一次插入多条数据sql语句写法
  5. mysql用大白话解释_大白话 golang 教程-22-关系型数据库访问
  6. 在mac上制作PDF的基础教程
  7. Python服务器管理模块psutil学习使用
  8. Debian下的内核编译
  9. 千方百剂医药管理系统对接第三方WMS系统(天力士物流)
  10. 麒麟软件、麒麟操作系统、银河麒麟、中标麒麟、优麒麟、国产操作系统下载。
  11. 基于JavaWeb的网上订餐网站设计与实现 毕业论文+任务书+外文翻译及原文+答辩PPT+项目源码及数据库文件
  12. 国外问卷调查回答问题有什么技巧?
  13. 咖啡产品介绍PPT模板
  14. 一、ubuntu16.04下无法连接wifi(试遍所有方法及解决方案)
  15. xf86-video-intel源码分析6 —— intel_device.c和intel_driver.h(1)
  16. 除了高通和博通,还有哪些Wi-Fi6路由器芯片方案可选
  17. 该死webgl_该死的简单可扩展菜单,没有任何额外的依赖
  18. OFCMS 发布1.1.2 java cms ofcms
  19. halcon 焊点检测案例
  20. 《未来简史》—央美设计思维推荐书籍

热门文章

  1. C语言学习第十五课(文件操作)
  2. 医学影像半监督分割--基于数据扰动
  3. 灵动微电子MM32L0130系列MCU具有出色的低功耗表现
  4. 信号默认处理动作及可重入函数
  5. 【深度】小红书的变法方法,分别怎么操作
  6. 新版QQ秒强制聊天网站源码
  7. 微信小程序获取Onenet图片
  8. 10月29日10月30日
  9. 在aspx.cs文件无法引用的aspx文件中的某个控件
  10. 100以内两个整数的(随机产生)的加法运算练习程序