OpenGL学习日记-2015.3.5

过年前忍不住买了本新版的OpenGL编程指南,主要的目的还是为了系统的学习着色器编程,另外就是接触新版的OpenGL技术和思想。看了几页,就过年了QAQ.回来后也是各种不在状态,不想上班,不想工作,不想写代码。。。昨天终于强迫自己继续看书,也找回了些状态。

书本基础知识的全面性和权威性就不用说了,不过这个源代码就。。。。这第一个例子照着代码来抄结果。。。我想应该是原来的代码一个参数错了,折腾了半天,代码分析是详说。主要是分析代码,有什么说什么,并没有全面的说明着色器的基本内容,想着在着色器的基础知识看的差不多或者更熟悉了再做一次总结。

顶点着手器:

#version 330uniform mat4 model_matrix;uniform mat4 projection_matrix;layout (location = 0) in vec4 position;layout (location = 1) in vec4 color;out vec4 vs_fs_color;void main(void){vs_fs_color = color;gl_Position = projection_matrix * (model_matrix * position);}

第一行是着色器版本说明,以上是对应于OpenGL 3.3版本,在编写着色器程序是虽然使用最新的版本可以使得程序充分利用的Opengl的新特性,当时也同时带来兼容性的问题。所以根据自己的程序需要做一个权衡。

第二三行定义了4×4的矩阵,从字面意义上看,他们分别是透视投影矩阵和,模型视图矩阵,在main与顶点坐标做透视投影变换和模型视图变换。 关于uniform关键字:是个存储限制符,uniform修饰符可以指定一个在应用程序中定义好的变量,他不会再图元处理过程中变化(着色器流水中),它在所有的着色器阶段都是共享的所以它必须是全局的变量(相对于着色器)。任何类型的变量都可以为uniform修饰。!!!重要:着色器无法修改,写入uniform修饰的变量,无法改变它的值。

第四五行定义了两个4维向量,比较生疏的修饰符。glsl声明的解读和c++一样,从右往左读。position是个变量名,vec4说明了这个变量是4维向量,in修饰符代表着变量是一个输入变量(无修饰时,默认值),然后是layout(location = 0),她叫做布局限定符,目的是为了方便给变量提供数据,layout()的还有其他的选项,在这里location相当于设定了变量在着色器程序中的访问位置。

第六行同样定义了一个4维向量,不同的是out修饰符,同理易知代表着这个变量是用于输出数据,这里是给片段着色器提供颜色的输入数据,在下面的片元着色器中将再次看到该变量。

最后是main()函数,每一个着色器都必须有一个main()函数,与c、c++不同的是这个函数没有返回值,没有参数。函数里第一行对输出变量赋予应用程序中传递过来的颜色值,以便传递给片元着色器使用、第二行对gl_Position赋值,这是个OpenGL的内置变量,所有OpenGL的内置变量都是以gl_为前缀。gl_Position表示顶点坐标,最终OpenGL将根据该值绘制每一个顶点。

片元着色器:

#version 330in vec4 vs_fs_color;layout (location = 0) out vec4 color;void main(void){color = vs_fs_color;}

从第二行说起吧,这个变量在顶点着色器中出现过,不同的是修饰符从out变成了in。对,这个变量的值就是从顶点着色器中传递过来的。

最后main函数中输出了颜色color。

两个必要的着色器编写完成,接下来需要进行着色器装配。着色器的装配过程有点像c++程序的编译生成过程,经过了几个阶段,编译,连接,执行。程序使用了书中源码的LoadShaders接口。

typedef struct {GLenumtype;const char* filename;GLuintshader;} ShaderInfo;GLuint LoadShaders( ShaderInfo* );

繁琐的细节就略过,关注于着色器的装配。一下是LoaderShaders.cpp的内容,将在代码注释中详细描述每一步

///////////////////////////////////////////////////////////////////////////////// — LoadShaders.cxx —////////////////////////////////////////////////////////////////////////////////#include <cstdlib>#include <iostream>/#define GLEW_STATIC#include <GL/glew.h>#include "LoadShaders.h"#ifdef __cplusplusextern "C" {#endif // __cplusplus//—————————————————————————-static const GLchar*ReadShader( const char* filename ){#ifdef WIN32 FILE* infile; fopen_s( &infile, filename, "rb" );#elseFILE* infile = fopen( filename, "rb" );#endif // WIN32if ( !infile ) {#ifdef _DEBUGstd::cerr << "Unable to open file '" << filename << "'" << std::endl;#endif /* DEBUG */return NULL;}fseek( infile, 0, SEEK_END );int len = ftell( infile );fseek( infile, 0, SEEK_SET );GLchar* source = new GLchar[len+1];fread( source, 1, len, infile );fclose( infile );source[len] = 0;return const_cast<const GLchar*>(source);}//—————————————————————————-GLuintLoadShaders( ShaderInfo* shaders ){if ( shaders == NULL ) { return 0; }GLuint program = glCreateProgram(); //1.first,创建着色器程序实例。返回整形,类似于指针一样的东西。ShaderInfo* entry = shaders;while ( entry->type != GL_NONE ) {GLuint shader = glCreateShader( entry->type ); //根据信息(枚举值),创建对应的着色器。entry->shader = shader;const GLchar* source = ReadShader( entry->filename ); //读取着色器字符串if ( source == NULL ) {for ( entry = shaders; entry->type != GL_NONE; ++entry ) {glDeleteShader( entry->shader ); //读取文件出错,删除着色器对象。entry->shader = 0;}return 0;}glShaderSource( shader, 1, &source, NULL ); //将shader,着色器对象与相应的着色器字符串关联。delete [] source; //删除着色器字符串,glShaderSource应该会做一个拷贝的操作,保存了字符串信息。glCompileShader( shader ); //编译着色器GLint compiled;glGetShaderiv( shader, GL_COMPILE_STATUS, &compiled ); //检查编译是否成功,输出编译信息。if ( !compiled ) {#ifdef _DEBUGGLsizei len;glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &len ); //获取编译日志的长度GLchar* log = new GLchar[len+1];glGetShaderInfoLog( shader, len, &len, log ); //取得日志std::cerr << "Shader compilation failed: " << log << std::endl; //打印delete [] log;#endif /* DEBUG */return 0;}glAttachShader( program, shader ); //装配,将着色器对象关联都着色器程序中//???一个着色器可以关联多个同一类型的着色器么?如多个顶点着色器你,不过好像没有什么意义++entry;}#ifdef GL_VERSION_4_1if ( GLEW_VERSION_4_1 ) {// glProgramParameteri( program, GL_PROGRAM_SEPARABLE, GL_TRUE ); //需要多个着色器程序时使用4.1以上的OpenGL}#endif /* GL_VERSION_4_1 */glLinkProgram( program ); //连接各个模块成完整的着色器程序。GLint linked;glGetProgramiv( program, GL_LINK_STATUS, &linked );//检查连接过程是否成功,获取失败是的日志爱if ( !linked ) {#ifdef _DEBUGGLsizei len;glGetProgramiv( program, GL_INFO_LOG_LENGTH, &len );GLchar* log = new GLchar[len+1];glGetProgramInfoLog( program, len, &len, log );std::cerr << "Shader linking failed: " << log << std::endl;delete [] log;#endif /* DEBUG */for ( entry = shaders; entry->type != GL_NONE; ++entry ) {glDeleteShader( entry->shader );//连接出现错误,删除相应着色器entry->shader = 0;}return 0;}return program;}//—————————————————————————-#ifdef __cplusplus}#endif // __cplusplus

总结来说: 1、glCreateProgram()创建一个着色器程序。

2、glCreateShader() 根据着色器不同阶段创建需要的着色器。

3、glShaderSource()把着色器字符串提交到OpenGL等待编译。

4、glCompileShader()编译着色器。

5、glAttachShader()把编译好的着色器与着色器程序关联,装配的过程。

6、glLinkProgram()连接装配好的着色器成为一个可使用的着色器程序。

7、glUseProgram()激活对应的着色器,使他对应用程序生效。

接下来是程序主体,最终效果绘制4个排列的彩色三角形

世上再美的风景,都不及回家的那段路。

OpenGL学习日记-2015.3.5

相关文章:

你感兴趣的文章:

标签云: