OpenGL学习(4)

来源:互联网 发布:淘宝质量叫高的女装店 编辑:程序博客网 时间:2024/05/21 06:42

给图形上色

对于图形的上色有两种基本的方法:直接使用glColor~() 系列的函数 使用shader脚本。下文将简要介绍下这两种方法。

1.直接使用glColor~() 系列的函数

方法:在相应的坐标顶点使用该函数,如下程序所示

<span style="white-space:pre"></span>glBegin(GL_TRIANGLES);glColor3f(1.0f,0.0f,0.0f);//set the redglVertex3f(-1.0f,-1.0f,0.0f);glColor3f(0.0f,1.0f,0.0f);//set the greenglVertex3f(1.0f,-1.0f,0.0f);glColor3f(0.0f,0.0f,1.0f);//set the blueglVertex3f(0.0f,1.0f,0.0f);glEnd();

需要说明的是,每一个glColor~() 函数都是从开始使用处生效,在出现另一个glColor~() 函数时失效

调试运行结果:如图1所示


图1

小结:

这种方法在程序理解和写法上比较简单,但传输效率比较低;在多顶点的情况下,程序比较冗长;

2.使用shader脚本

方法:通过将颜色写在frangment(片元)脚本上,来实现图形着色
首先,编写读取shader脚本的程序。该程序包括如下:
(1)利用glCreateShader() 函数创建 vertex shader (顶点着色器)和 fragment shader(片元着色器)
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

(2)利用getline() 函数读取 vertex shader 和 fragment shader

<span style="white-space:pre"></span>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();}else//Open vertex shader source code failed{printf("Failed to open %s. Are you in the right directory ? \n", vertex_file_path);return ;}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();}else{printf("Failed to open %s. Are you in the right directory ? \n", fragment_file_path);return ;}

(3-1)使用glCompileShader() 函数编译vertex shader,并根据其日志判断是否存在代码语法错误

<span style="white-space:pre"></span>GLint Result = GL_FALSE;int InfoLogLength;printf("Compiling shader : %s\n", vertex_file_path);char const * VertexSourcePointer = VertexShaderCode.c_str();glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);glCompileShader(VertexShaderID);glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); if ( InfoLogLength > 0 ){std::vector<char> VertexShaderErrorMessage(InfoLogLength+1);glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);printf("%s\n", &VertexShaderErrorMessage[0]);}

(3-2)同样,使用glCompileShader() 函数编译fragment shader,并根据其日志判断是否存在代码语法错误

<span style="white-space:pre"></span>printf("Compiling shader : %s\n", fragment_file_path);char const * FragmentSourcePointer = FragmentShaderCode.c_str();glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);glCompileShader(FragmentShaderID);glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);if ( InfoLogLength > 0 ){std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1);glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);printf("%s\n", &FragmentShaderErrorMessage[0]);}

(4)使用glLinkProgram() 函数,将shader 和程序Link起来

<span style="white-space:pre"></span>printf("Linking program\n");m_uiProgramID = glCreateProgram();glAttachShader(m_uiProgramID, VertexShaderID);glAttachShader(m_uiProgramID, FragmentShaderID);glLinkProgram(m_uiProgramID);

(5)再次检查脚本,并释放相关shader

<span style="white-space:pre"></span>glGetProgramiv(m_uiProgramID, GL_LINK_STATUS, &Result);glGetProgramiv(m_uiProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);if ( InfoLogLength > 0 ){std::vector<char> ProgramErrorMessage(InfoLogLength+1);glGetProgramInfoLog(m_uiProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);printf("%s\n", &ProgramErrorMessage[0]);}glDetachShader(m_uiProgramID, VertexShaderID);glDetachShader(m_uiProgramID, FragmentShaderID);//Delete the vertex and fragment shaderglDeleteShader(VertexShaderID);glDeleteShader(FragmentShaderID);

其次,编写vertex shader 和 fragment shader。
(1)关于vertex shader:基本包括,OpenGL版本声、定义存储顶点变量、传输顶点数据

#version 330 corelayout(location = 0) in vec3 vertexPosition_modelspace;void main(){gl_Position =  vec4(vertexPosition_modelspace,1);}

(2)关于fragment shader:基本包括,OpenGL版本声明、定义存储颜色变量、设定颜色数据

#version 330 coreout vec3 color;void main(){color = vec3(1,0,0);}

最后,通过glUseProgram() 函数来激活所载入的shader。剩余步骤如前使用VBO画三角形的方法一样,即“使能顶点属性数组->绑定缓冲区->设置顶点属性值->画图形->禁止顶点属性数组”

glUseProgram(m_uiProgramID);

运行调试结果:如图2所示

图2

小结:

使用shader来进行着色,充分地利用GPU进行上色,极大地提高了编码的灵活性;但是在程序的理解上比较难,写法上也比较繁琐;需要说的是,对于读取shader的程序只要在一组shader(包括vertex shader 和 fragment shader)中,只要调用一次。




0 0
原创粉丝点击