http://blog.csdn.net/racehorse/article/details/6616256

设置GLSL

这一节讲述在OpenGL中配置GLSL,假设你已经写好了顶点shader和像素shader。如果你还没有准备好,可以从如下网址获得相关内容:

http://www.3dshaders.com/home/

http://www.opengl.org/sdk/tools/ShaderDesigner/

http://developer.amd.com/archive/gpu/rendermonkey/pages/default.aspx

在OpenGL中,GLSL的shader使用的流程与C语言相似,每个shader类似一个C模块,首先需要单独编译(compile),然后一组编译好的shader连接(link)成一个完整程序。

这里将忽略ARB扩展,只列举OpenGL2.0的代码。建议使用GLEW库:

http://glew.sourceforge.net/

下面的代码检查OpenGL 2.0是否可用:

  1. #include <GL/glew.h>
  2. #include <GL/glut.h>
  3. void main(int argc, char **argv)
  4. {
  5. glutInit(&argc, argv);
  6. ...
  7. glewInit();
  8. if (glewIsSupported("GL_VERSION_2_0"))
  9. printf("Ready for OpenGL 2.0\n");
  10. else
  11. {
  12. printf("OpenGL 2.0 not supported\n");
  13. exit(1);
  14. }
  15. setShaders();
  16. glutMainLoop();
  17. }

下图显示了创建shader的必要步骤,函数的具体使用方法将在下面各小结描述:

创建shader

下图显示了创建shader的步骤:

首先创建一个对象作为shader的容器,这个创建函数将返回容器的句柄。

  1. GLuint glCreateShader(GLenum shaderType);
  2. 参数:
  3. ·shaderType – GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.

你可以创建许多shader,但记住所有的顶点shader只能有一个main函数,所有像素shader也一样。

下一步将添加源代码。shader的源代码是一个字符串数组,添加的语法如下:

  1. void glShaderSource(GLuint shader, int numOfStrings, const char **strings, int *lenOfStrings);
  2. 参数:
  3. ·shader – the handler to the shader.
  4. ·numOfStrings – the number of strings in the array.
  5. ·strings – the array of strings.
  6. ·lenOfStrings – an array with the length of each string, or NULL, meaning that the strings are NULL terminated.

最后编译shader:

  1. void glCompileShader(GLuint shader);
  2. 参数:
  3. •shader – the handler to the shader.

创建程序

下图显示了获得一个可以运行的shader程序的步骤:

首先创建一个对象,作为程序的容器。此函数返回容器的句柄。

  1. GLuint glCreateProgram(void);

你可以创建任意多个程序,在渲染时,可以在不同程序中切换,甚至在某帧返回固定功能流水线。比如你想用折射和反射shader绘制一个茶杯,然后回到固定功能生成立方体环境贴图(cube map)显示背景。

下面将把上一节编译的shader附加到刚刚创建的程序中。方法如下:

  1. void glAttachShader(GLuint program, GLuint shader);
  2. 参数:
  3. ·program – the handler to the program.
  4. ·shader – the handler to the shader you want to attach.

如果同时有顶点shader和片断shader,你需要把它们都附加到程序中。你可以把多个相同类型(顶点或像素)的shader附加到一个程序中,如同一个C程序可以有多个模块一样,但它们只能有一个main函数。

你也可以把一个shader附加到多个程序,比如你想在不同程序中使用某个相同的shader。

最后一步是连接程序。方法如下:

  1. void glLinkProgram(GLuint program);
  2. 参数:
  3. ·program – the handler to the program.

在连接操作之后,shader的源代码可以被修改并重编译,并不会影响到整个程序。

程序连接后,可以调用glUseProgram来使用程序。每个程序都分配了一个句柄,你可以事先连接多个程序以备使用。

  1. void glUseProgram(GLuint prog);
  2. 参数:
  3. ·prog – the handler to the program you want to use, or zero to return to fixed functionality.

当一个程序被使用后,如果被再次连接,它将被自动替换并投入使用,所以没有必要再次调用上面这个函数。如果使用的参数为0,表示将使用固定功能流水线。

 例子

下面的代码包含了上面描述的所有步骤,参数p,f,v是全局的GLuint型变量。

  1. void setShaders()
  2. {
  3. char *vs,*fs;
  4. v = glCreateShader(GL_VERTEX_SHADER);
  5. f = glCreateShader(GL_FRAGMENT_SHADER);
  6. vs = textFileRead("toon.vert");
  7. fs = textFileRead("toon.frag");
  8. const char *vv = vs;
  9. const char *ff = fs;
  10. glShaderSource(v, 1, &vv, NULL);
  11. glShaderSource(f, 1, &ff, NULL);
  12. free(vs);free(fs);
  13. glCompileShader(v);
  14. glCompileShader(f);
  15. p = glCreateProgram();
  16. glAttachShader(p, v);
  17. glAttachShader(p, f);
  18. glLinkProgram(p);
  19. glUseProgram(p);
  20. }

GLUT版的完整例子如下:

http://lighthouse3d.com/wptest/wp-content/uploads/2011/03/glutglsl_2.0.zip

完整例子中包含了shader代码及文本文件读入程序。

错误处理

调试shader是很困难的。目前还没有像printf这样的东西,虽然未来可能出现有调试功能的开发工具。

编译阶段的状态可以用如下函数获得:

  1. void glGetShaderiv(GLuint object, GLenum type, int *param);
  2. 参数:
  3. ·object – the handler to the object. Either a shader or a program
  4. ·type – GL_COMPILE_STATUS.
  5. ·param – the return value, GL_TRUE if OK, GL_FALSE otherwise.

连接阶段的状态可以用如下函数获得:

  1. void glGetProgramiv(GLuint object, GLenum type, int *param);
  2. 参数:
  3. ·object – the handler to the object. Either a shader or a program
  4. ·type – GL_LINK_STATUS.
  5. ·param – the return value, GL_TRUE if OK, GL_FALSE otherwise.

如 果发生错误,就需要从InfoLog中找到更多的信息。这个日志保存了最后一次操作的信息,比如编译时的警告、错误,连接时发生的各种问题。这个日志甚至 可以告诉你硬件是否支持你的shader。不幸的是InfoLog没有一个规范,所以不同的驱动/硬件可能产生不同的日志信息。

为了获得特定shader或程序的日志,可以使用如下程序:

  1. void glGetShaderInfoLog(GLuint object, int maxLen, int *len, char *log);
  2. void glGetProgramInfoLog(GLuint object, int maxLen, int *len, char *log);
  3. 参数:
  4. ·object – the handler to the object. Either a shader or a program
  5. ·maxLen – The maximum number of chars to retrieve from the InfoLog.
  6. ·len – returns the actual length of the retrieved InfoLog.
  7. ·log – The log itself.

GLSL规范有必要在这里进行一些改进:你必须知道接收InfoLog的长度。为了找到这个准确的值,使用下面的函数:

  1. void glGetShaderiv(GLuint object, GLenum type, int *param);
  2. void glGetProgramiv(GLuint object, GLenum type, int *param);
  3. 参数:
  4. ·object – the handler to the object. Either a shader or a program
  5. ·type – GL_INFO_LOG_LENGTH.
  6. ·param – the return value, the length of the InfoLog.

下面的函数可以用来打印InfoLog的内容:

  1. void printShaderInfoLog(GLuint obj)
  2. {
  3. int infologLength = 0;
  4. int charsWritten  = 0;
  5. char *infoLog;
  6. glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
  7. if (infologLength > 0)
  8. {
  9. infoLog = (char *)malloc(infologLength);
  10. glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
  11. printf("%s\n",infoLog);
  12. free(infoLog);
  13. }
  14. }
  15. void printProgramInfoLog(GLuint obj)
  16. {
  17. int infologLength = 0;
  18. int charsWritten  = 0;
  19. char *infoLog;
  20. glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
  21. if (infologLength > 0)
  22. {
  23. infoLog = (char *)malloc(infologLength);
  24. glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
  25. printf("%s\n",infoLog);
  26. free(infoLog);
  27. }
  28. }

清理

前面的小节讲到了附加一个shader到一个程序中,这里的调用是将shader从程序中分离:

  1. void glDetachShader(GLuint program, GLuint shader);
  2. 参数:
  3. ·program – The program to detach from.
  4. ·shader – The shader to detach.

注意,只有没有附加到任何程序的shader可以被删除,删除shader和程序的调用如下:

  1. void glDeleteShader(GLuint id);
  2. void glDeleteProgram(GLuint id);
  3. 参数:
  4. ·id – The hanuler of the shader or program to delete.

如果一个shader还附加在某个程序中,这个shader并不能真正删除,只能标记为删除。当这个shader从所有程序中分离之后,才会被最终删除。

【GLSL教程】(二)在OpenGL中使用GLSL 【转】的更多相关文章

  1. JavaScript 入门教程二 在HTML中使用 JavaScript

    一.使用 <script> 元素的方式有两种:直接在页面中嵌入 JavaScript 代码和引用外部 JavaScript 文件. 二.使用内嵌方式,一般写法为: <script t ...

  2. 【GLSL教程】(三)在OpenGL中向shader传递信息 【转】

    http://blog.csdn.net/racehorse/article/details/6634830 引言 一个OpenGL程序可以用多种方式和shader通信.注意这种通信是单向的,因为sh ...

  3. OpenGL 4.0 GLSL 基础教程概览——VAO和VBO常用操作接口

    (一) OpenGL  4.3 最新渲染管线图 从OpenGL 2.0 到 OpenGL 3.0变化非常大,但从OpenGL 3.0 到OpenGL 4.0 变化不是太大. 着色器程序直接运行在GPU ...

  4. GLSL 在OpenGL中向shader传递信息【转】

    http://blog.csdn.net/hgl868/article/details/7872219 引言 一个OpenGL程序可以用多种方式和shader通信.注意这种通信是单向的,因为shade ...

  5. OpenGl中使用着色器的基本步骤及GLSL渲染简单示例

    OpenGL着色语言(OpenGL Shading Language,GLSL)是用来在OpenGL中着色编程的语言,是一种具有C/C++风格的高级过程语言,同样也以main函数开始,只不过执行过程是 ...

  6. 【GLSL教程】(七)逐像素的光照 【转】

    http://blog.csdn.net/racehorse/article/details/6662540 逐像素的方向光(Directional Light per Pixel) 这一节将把前面的 ...

  7. 【GLSL教程】(六)逐顶点的光照 【转】

    引言 在OpenGL中有三种类型的光:方向光(directional).点光(point).聚光(spotlight).本教程将从方向光讲起,首先我们将使用GLSL来模仿OpenGL中的光. 我们将向 ...

  8. 【GLSL教程】(五)卡通着色 【转】

    http://blog.csdn.net/racehorse/article/details/6641623 引言 卡通着色可能是最简单的非真实模式shader.它使用很少的颜色,通常是几种色调(to ...

  9. 【GLSL教程】(一)图形流水线 【转】

    http://blog.csdn.net/racehorse/article/details/6593719 这是一些列来自lighthouse3d的GLSL教程,非常适合入门.我将边学习边翻译该教程 ...

随机推荐

  1. Python 操作 SQLite 数据库

    写在之前 SQLite 是一个小型的关系型数据库,它最大的特点在于不需要单独的服务.零配置.我们在之前讲过的两个数据库,不管是 MySQL 还是 MongoDB,都需要我们安装.安装之后,然后运行起来 ...

  2. 用Vundle管理Vim插件

    作为程序员,一个好用的Vim,是极其重要的,而插件能够使原本功能羸弱的Vim变得像其他功能强大的IDE一样好用.然而下载.配置插件的过程比较繁琐,大家往往需要自己进行下载/配置等操作,如果还涉及到更新 ...

  3. hihoCoder #1763 道路摧毁

    题目大意 A 国一共有 $n$ 个城市且有 $n-1$ 条双向道路,且任意两个城市都可以通过道路互相到达. 现在 B 国给出了两个城市的集合 $X,Y$,你需要摧毁若干条 A 国的道路,使得任意一个在 ...

  4. linux系统——网络调试工具

    http://blog.csdn.net/chinalinuxzend/article/details/1799279 1.网络调试工具概说: 如 果我们把一台机器接入网络中,通过网络配置工具的配置这 ...

  5. flake8(代码规范利器)

    flake8(代码规范利器) 概述 flake8是下面三个工具的封装: 1)PyFlakes 2)Pep8 3)NedBatchelder’s McCabe script Flake8的下载地址:ht ...

  6. OpenJudge 2727 仙岛求药

    总时间限制:  1000ms 内存限制:  65536kB 描述 少年李逍遥的婶婶病了,王小虎介绍他去一趟仙灵岛,向仙女姐姐要仙丹救婶婶.叛逆但孝顺的李逍遥闯进了仙灵岛,克服了千险万难来到岛的中心,发 ...

  7. 网页制作教程:td也可以溢出隐藏显示【转】

    原文发布时间为:2010-02-05 -- 来源于本人的百度文章 [由搬家工具导入] <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Stri ...

  8. C#、.Net学习资料免注册下载基地。。。

    原文发布时间为:2008-11-28 -- 来源于本人的百度文章 [由搬家工具导入] http://club.topsage.com/forumdisplay.php?fid=121&filt ...

  9. duilib入门简明教程 -- 前言(1) (转)

    原文转自 :http://www.cnblogs.com/Alberl/p/3341956.html     关于duilib的介绍就不多讲了,一来不熟,二来小伙伴们想必已经对比了多个界面库,也无需赘 ...

  10. android中提示&对话框----AlertDialog

    AlertDialog(对话框) 一.对话框的基本使用流程 step1:创建AlertDialog.Buider; step2:调用setIcon()设置图标,setTitle()或者setCusto ...