【OpenGL】Shader概述
来源:互联网 发布:破壁机 原汁机 知乎 编辑:程序博客网 时间:2024/05/21 22:28
【OpenGL】Shader概述 http://blog.csdn.net/candycat1992/article/details/8829601
目录(?)[+]
这篇文章讲述了Shader是如何编译和链接,最终在OpenGL程序中使用的。当然,不了解这些我们仍然可以正常工作,但是作为初学者,了解这些会让我更能明白自己在干嘛。。。
综述
哈,大名鼎鼎的Shader终于让我给见到了……之前在学习Unity3D的时候就被群里的大牛耳濡目染说Shader如何如何重要,现在终于轮到自己领教了。吐槽完毕,进入正题。
Shader的编译器被内嵌到OpenGL库的内部,而且必须在运行OpenGL程序时才能编译。目前还没有可以提前编译Shader的工具。在最新的OpenGL4.1中好像正在改善。
目前的学习中,我使用的是这个教程提供的一个载入shader的代码。代码不长,功能不全,只能同时载入vertex shader和fragment shader(这里是保存在两个单独的文件里,后缀分别的vertexshader和fragmentshader,后缀不重要,即便是txt也可以,重要的是内容使用的是GLSL语法),但是对于初学者够用了。(实际上,我们通常需要至少两个shader。)代码如下:
- GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path){
- // Create the shaders
- GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
- GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
- // Read the Vertex Shader code from the file
- std::string VertexShaderCode;
- std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
- if(VertexShaderStream.is_open())
- {
- std::string Line = "";
- while(getline(VertexShaderStream, Line))
- VertexShaderCode += "n" + Line;
- VertexShaderStream.close();
- }
- // Read the Fragment Shader code from the file
- std::string FragmentShaderCode;
- std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
- if(FragmentShaderStream.is_open()){
- std::string Line = "";
- while(getline(FragmentShaderStream, Line))
- FragmentShaderCode += "n" + Line;
- FragmentShaderStream.close();
- }
- GLint Result = GL_FALSE;
- int InfoLogLength;
- // Compile Vertex Shader
- printf("Compiling shader : %sn", vertex_file_path);
- char const * VertexSourcePointer = VertexShaderCode.c_str();
- glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
- glCompileShader(VertexShaderID);
- // Check Vertex Shader
- glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
- glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
- std::vector VertexShaderErrorMessage(InfoLogLength);
- glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
- fprintf(stdout, "%sn", &VertexShaderErrorMessage[0]);
- // Compile Fragment Shader
- printf("Compiling shader : %sn", fragment_file_path);
- char const * FragmentSourcePointer = FragmentShaderCode.c_str();
- glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
- glCompileShader(FragmentShaderID);
- // Check Fragment Shader
- glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
- glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
- std::vector FragmentShaderErrorMessage(InfoLogLength);
- glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
- fprintf(stdout, "%sn", &FragmentShaderErrorMessage[0]);
- // Link the program
- fprintf(stdout, "Linking programn");
- GLuint ProgramID = glCreateProgram();
- glAttachShader(ProgramID, VertexShaderID);
- glAttachShader(ProgramID, FragmentShaderID);
- glLinkProgram(ProgramID);
- // Check the program
- glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
- glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
- std::vector ProgramErrorMessage( max(InfoLogLength, int(1)) );
- glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
- fprintf(stdout, "%sn", &ProgramErrorMessage[0]);
- glDeleteShader(VertexShaderID);
- glDeleteShader(FragmentShaderID);
- return ProgramID;
- }
为了举例,我们以下都使用下面两个shader。
第一个shader是一个顶点着色器,vertex shader,文件名为ExampleShader.vertexshader。
- #version 400
- in vec3 VertexPosition;
- in vec3 VertexColor;
- out vec3 Color;
- void main()
- Color = VertexColor;
- gl_Position = vec4( VertexPosition, 1.0 );
- }
这里简单解释一下。它接受两个输入和一个输出,并使用输入VertexPosition给gl_position赋值,使用VertexColor给输出Color赋值,而Color将会传递给下面的片段着色器。
- #version 400
- in vec3 Color;
- out vec4 FragColor;
- void main() {
- FragColor = vec4(Color, 1.0);
- }
顶点着色器会在每个顶点上调用一次,而片段着色器则会在每个像素上调用一次。
----------------------------------------------------------------分割线--------------------------------------------------------------------
编译一个Shader
- // Create the shaders
- GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
- GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
然后将shader源代码(source code)复制到shader对象中。由于这里是从文件里读入代码,因此先将源代码分别读入到一个string类型的变量里(VertexShaderCode和FragmentShaderCode),再把指针传递给shader对象:
- // Read the Vertex Shader code from the file
- std::string VertexShaderCode;
- std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
- if(VertexShaderStream.is_open())
- {
- std::string Line = "";
- while(getline(VertexShaderStream, Line))
- VertexShaderCode += "n" + Line;
- VertexShaderStream.close();
- }
- char const * VertexSourcePointer = VertexShaderCode.c_str();
- glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
最后,编译shader。通常我们需要检查一下shader是否编译成功,不成功的话再打出错误信息,这通过两个变量Result和InfoLogLength来实现:
- GLint Result = GL_FALSE;
- int InfoLogLength;
- glCompileShader(VertexShaderID);
- // Check Vertex Shader
- glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
- glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
- std::vector VertexShaderErrorMessage(InfoLogLength);
- glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
- fprintf(stdout, "%sn", &VertexShaderErrorMessage[0]);
上面的筛选的vertex shader的编译过程,当然fragment shader的编译是一样的。
链接一个Shader
- GLuint ProgramID = glCreateProgram();
- glAttachShader(ProgramID, VertexShaderID);
- glAttachShader(ProgramID, FragmentShaderID);
最后,进行链接。
- glLinkProgram(ProgramID);
和之前需要检查编译状态类似,我们也需要检查链接状态,如果链接不成功,就打出提示信息。
- // Check the program
- glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
- glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
- std::vector ProgramErrorMessage( max(InfoLogLength, int(1)) );
- glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
- fprintf(stdout, "%sn", &ProgramErrorMessage[0]);
删除一个Shader
- glDeleteShader(VertexShaderID);
- glDeleteShader(FragmentShaderID);
指定使用一个Shader Program
删除一个Shader Program
备注
- 【OpenGL】Shader概述
- 【OpenGL】Shader概述
- 【OpenGL】Shader概述
- OpenGL Shader
- opengl shader
- opengl shader
- OpenGL概述
- OpenGL 概述
- OpenGL概述
- OpenGL概述
- OpenGL概述
- OpenGL概述
- OpenGL ES 2.0 - Shader
- OpenGL Geometry Shader
- OpenGL Shader基本概念
- OpenGL Shader基本概念
- OpenGL中shader使用
- opengl shader 使用札记
- LintCode 字符串转化成正数(atoi)
- 028.For 循环
- Android多媒体学习七:访问网络上的Audio对应的M3U文件,实现网络音频流的播放
- lua语言实现面向对象编程
- 【一步一步的积累】Neighbourhood Components Analysis
- 【OpenGL】Shader概述
- 029.For Error 死循环
- 黑马52期最新android视频完整高清不加密
- Extjs首日工作总结
- 左连接右连接 left join right join
- 黑马程序员_java异常
- 030.For 循环代替 While 循环
- android arm
- 返回键当Home键使用方法