(转)【GLSL教程】(二)在OpenGL…

设置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是否可用:

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

#include <GL/glew.h> #include <GL/glut.h>void main(int argc, char **argv){ glutInit(&argc, argv); ... glewInit(); if (glewIsSupported("GL_VERSION_2_0")) printf("Ready for OpenGL 2.0\n"); else { printf("OpenGL 2.0 not supported\n"); exit(1); } setShaders(); glutMainLoop();}

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



创建shader

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



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

view plain copy to clipboard print ?
  1. GLuint glCreateShader(GLenum shaderType);  
  2. 参数:  
  3. ?shaderType GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.  

GLuint glCreateShader(GLenum shaderType); 参数: ?shaderType - GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.你可以创建许多shader,但记住所有的顶点shader只能有一个main函数,所有像素shader也一样。

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

view plain copy to clipboard print ?
  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.  

void glShaderSource(GLuint shader, int numOfStrings, const char **strings, int *lenOfStrings); 参数:?shader - the handler to the shader. ?numOfStrings - the number of strings in the array. ?strings - the array of strings. ?lenOfStrings - an array with the length of each string, or NULL, meaning that the strings are NULL terminated.最后编译shader:

view plain copy to clipboard print ?
  1. void glCompileShader(GLuint shader);  
  2. 参数:  
  3. •shader the handler to the shader.  

void glCompileShader(GLuint shader); 参数:•shader - the handler to the shader.


创建程序

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



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

view plain copy to clipboard print ?
  1. GLuint glCreateProgram(void);  

GLuint glCreateProgram(void);

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

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

view plain copy to clipboard print ?
  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.  

void glAttachShader(GLuint program, GLuint shader); 参数:?program - the handler to the program. ?shader - the handler to the shader you want to attach.如果同时有顶点shader和片断shader,你需要把它们都附加到程序中。你可以把多个相同类型(顶点或像素)的shader附加到一个程序中,如同一个C程序可以有多个模块一样,但它们只能有一个main函数。

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

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

view plain copy to clipboard print ?
  1. void glLinkProgram(GLuint program);  
  2. 参数:  
  3. ?program the handler to the program.  

void glLinkProgram(GLuint program); 参数: ?program - the handler to the program.在连接操作之后,shader的源代码可以被修改并重编译,并不会影响到整个程序。

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

view plain copy to clipboard print ?
  1. void glUseProgram(GLuint prog);  
  2. 参数:  
  3. ?prog the handler to the program you want to use, or zero to return to fixed functionality.  

void glUseProgram(GLuint prog); 参数: ?prog - the handler to the program you want to use, or zero to return to fixed functionality.当一个程序被使用后,如果被再次连接,它将被自动替换并投入使用,所以没有必要再次调用上面这个函数。如果使用的参数为0,表示将使用固定功能流水线。

 例子

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

view plain copy to clipboard print ?
  1. void setShaders()  
  2.  
  3.     char *vs,*fs;  
  4.   
  5.     glCreateShader(GL_VERTEX_SHADER);  
  6.     glCreateShader(GL_FRAGMENT_SHADER);    
  7.   
  8.     vs textFileRead("toon.vert");  
  9.     fs textFileRead("toon.frag");  
  10.   
  11.     const char *vv vs;  
  12.     const char *ff fs;  
  13.   
  14.     glShaderSource(v, 1, &vv, NULL);  
  15.     glShaderSource(f, 1, &ff, NULL);  
  16.   
  17.     free(vs);free(fs);  
  18.   
  19.     glCompileShader(v);  
  20.     glCompileShader(f);  
  21.   
  22.     glCreateProgram();  
  23.   
  24.     glAttachShader(p, v);  
  25.     glAttachShader(p, f);  
  26.   
  27.     glLinkProgram(p);  
  28.     glUseProgram(p);  
  29.  

void setShaders(){ char *vs,*fs; v = glCreateShader(GL_VERTEX_SHADER); f = glCreateShader(GL_FRAGMENT_SHADER); vs = textFileRead("toon.vert"); fs = textFileRead("toon.frag"); const char *vv = vs; const char *ff = fs; glShaderSource(v, 1, &vv, NULL); glShaderSource(f, 1, &ff, NULL); free(vs);free(fs); glCompileShader(v); glCompileShader(f); p = glCreateProgram(); glAttachShader(p, v); glAttachShader(p, f); glLinkProgram(p); glUseProgram(p);}GLUT版的完整例子如下:

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

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

 

错误处理

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

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

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

void glGetShaderiv(GLuint object, GLenum type, int *param); 参数:?object - the handler to the object. Either a shader or a program ?type - GL_COMPILE_STATUS. ?param - the return value, GL_TRUE if OK, GL_FALSE otherwise.连接阶段的状态可以用如下函数获得:

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

void glGetProgramiv(GLuint object, GLenum type, int *param); 参数:?object - the handler to the object. Either a shader or a program ?type - GL_LINK_STATUS. ?param - the return value, GL_TRUE if OK, GL_FALSE otherwise.如果发生错误,就需要从InfoLog中找到更多的信息。这个日志保存了最后一次操作的信息,比如编译时的警告、错误,连接时发生的各种问题。这个日志甚至可以告诉你硬件是否支持你的shader。不幸的是InfoLog没有一个规范,所以不同的驱动/硬件可能产生不同的日志信息。

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

view plain copy to clipboard print ?
  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 shader or 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.  

void glGetShaderInfoLog(GLuint object, int maxLen, int *len, char *log); void glGetProgramInfoLog(GLuint object, int maxLen, int *len, char *log);参数: ?object - the handler to the object. Either a shader or a program ?maxLen - The maximum number of chars to retrieve from the InfoLog. ?len - returns the actual length of the retrieved InfoLog. ?log - The log itself.GLSL规范有必要在这里进行一些改进:你必须知道接收InfoLog的长度。为了找到这个准确的值,使用下面的函数:

view plain copy to clipboard print ?
  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 shader or program  
  5. ?type GL_INFO_LOG_LENGTH.  
  6. ?param the return value, the length of the InfoLog.  

void glGetShaderiv(GLuint object, GLenum type, int *param); void glGetProgramiv(GLuint object, GLenum type, int *param);参数: ?object - the handler to the object. Either a shader or a program ?type - GL_INFO_LOG_LENGTH.?param - the return value, the length of the InfoLog.

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

view plain copy to clipboard print ?
  1. void printShaderInfoLog(GLuint obj)  
  2.  
  3.     int infologLength 0;  
  4.     int charsWritten  0;  
  5.     char *infoLog;  
  6.    
  7.     glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength);  
  8.    
  9.     if (infologLength 0)  
  10.      
  11.         infoLog (char *)malloc(infologLength);  
  12.         glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);  
  13.         printf("%s\n",infoLog);  
  14.         free(infoLog);  
  15.      
  16.   
  17.   
  18. void printProgramInfoLog(GLuint obj)  
  19.  
  20.     int infologLength 0;  
  21.     int charsWritten  0;  
  22.     char *infoLog;  
  23.    
  24.     glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength);  
  25.    
  26.     if (infologLength 0)  
  27.      
  28.         infoLog (char *)malloc(infologLength);  
  29.         glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);  
  30.         printf("%s\n",infoLog);  
  31.         free(infoLog);  
  32.      
  33.  

void printShaderInfoLog(GLuint obj) { int infologLength = 0; int charsWritten = 0; char *infoLog; glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength); if (infologLength > 0) { infoLog = (char *)malloc(infologLength); glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog); printf("%s\n",infoLog); free(infoLog); }} void printProgramInfoLog(GLuint obj){ int infologLength = 0; int charsWritten = 0; char *infoLog; glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength); if (infologLength > 0) { infoLog = (char *)malloc(infologLength); glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog); printf("%s\n",infoLog); free(infoLog); }}

清理

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

view plain copy to clipboard print ?
  1. void glDetachShader(GLuint program, GLuint shader);  
  2. 参数:  
  3. ?program The program to detach from.  
  4. ?shader The shader to detach.  

void glDetachShader(GLuint program, GLuint shader); 参数:?program - The program to detach from. ?shader - The shader to detach.注意,只有没有附加到任何程序的shader可以被删除,删除shader和程序的调用如下:

view plain copy to clipboard print ?
  1. void glDeleteShader(GLuint id);  
  2. void glDeleteProgram(GLuint id);  
  3. 参数:  
  4. ?id The hanuler of the shader or program to delete 

void glDeleteShader(GLuint id); void glDeleteProgram(GLuint id);参数: ?id - The hanuler of the shader or program to delete.

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


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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值