您的位置:首页 > 运维架构

New程序媛OpenGL全解析之—第一个OpenGL程序解析

2018-03-28 15:07 323 查看
大家好!本期丹丹将给大家解析第一个OpenGL程序




本期视频的链接地址是:https://www.bilibili.com/video/av21319715
大家也可以直接在bi站首页搜索:New程序媛 ,即可看到相应视频

本期的资源和代码下载链接是:链接:https://pan.baidu.com/s/1w4PiW8gNwiIu9gIOxUW_VA 密码:mpfz

视频和文章一起搭配效果更好哦~首先咱们来看看今天代码的完整版:








代码运行起来的效果如下图:



接下来的工作就是逐句来做解析啦!

第一个模块我们要来看的就是main 函数,因为main函数是我们的程序入口函数。


glutInit:该函数的调用是,glut提供的负责初始化的函数,它必须是应用程序调用的第一个glut函数。glutInitDisplayMode:设置了程序所使用的窗口类型,GLUT_DOUBIE表示使用了双缓冲,GLUT_RGBA表示设置窗口使用RGBA颜色。
glutInitWindowSize:设置窗口的大小。glutCreateWindow:创建窗口,如果当前的系统环境可以满足glutDisplayMode的显示模式要求。glewInit: glew库的初始化glutDisplayFunc:它设置了显示会调函数,即glut在每次更新窗口内容的时候会自动执行的函数。Init:自定义的一个初始化函数。glutMainLoop:这是一个无限之行的循环,他会负责一直处理窗口和操作系统的用户输入等操作,比如它会判断窗口是否需要进行重绘,如果需要它就会自动调用glutDisplayFunc注册的函数。
接下来看看绘制的顶点数据初始化:


vertices数组:顶点数据的定义,我们一共定义了四个顶点,每个顶点有xyz 三个分量indices数组 :索引数据的定义,索引号是从0开始,索引0表示的是加载到程序中顶点数据中的第一个顶点,而数组0 1 3则表示绘制顺序是分别取到0号1号3号顶点依次绘制VAO: 表示vertex array object  的IDVBO: 表示vertex buffer object 的IDEBO: 表示elements buffer object的ID
知识点:很多 OpenGL命令都是 glGen*的形式,它们负责分配不同类型的 OpenGL对象的名称。这里的名称就是类似C语言中的一个指针变量,我们必须分配内存并且用名称引用它之后,名称才有意义。在 OpenGL中,这个分配的机制叫做绑定对象( bind an object),它是通过一系列 glBind*形式的函数集合去实现的。如果绑定到一个已经创建的顶点数组对象中,那么会激活这个顶点数组对象,并且直接影响对象中所保存的顶点数组状态。
有了这些知识点,我们就来一起看看InitData函数:
glGenVertexArrays(1, &VAO); 分配一个顶点数组对象,ID保存在VAOglGenBuffers(1, &VBO);分配一个顶点缓存对象,ID保存在VBOglGenBuffers(1, &EBO);分配一个索引缓存对象,ID保存在EBOglBindBuffer(GL_ARRAY_BUFFER, VBO);绑定了一个顶点数组对象。glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);指定上句绑定buffer对象的具体数据glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);绑定了一个索引数组对象。glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);指定上句绑定buffer对象的具体数据glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);该函数的调用是告诉OpenGL从内存中如何取数据。
接下来的三条语句就是将数据内容解绑,也就是重置为零ID,即为不绑定和操作任何数据。glEnableVertexAttribArray(0);glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); 
有了数据,我们要来看的就是对应的着色器代码啦。知识点:对于每一个 OPENGL程序,当它所使用的 OPENGL版本高于或等于3.1时,都需要指定至少两个着色器:顶点着色器和片元着色器。对于 OPENGL程序员而言,着色器就是使用 OPENGL着色语言( OPENGL Shading Language,GLSL)编写的一个小型函数。GLSL是构成所有 OPENGL着色器的语言,它与C++语言非常类似,尽管GLSL中的所有特性并不能用于 OPENGL的每个着色阶段。我们可以以字符串的形式传输GLSL着色器到 OPENGL。今天我们的例子中也正是这样使用的。着色器的详细内容我们会在接下来的推送中给大家详细讲解。
首先看到我们的vertexShaderSource(顶点着色器)和fragmentShaderSource(片元着色器)定义:


#version 330core  指定了我们所用的 Opengl着色语言的版本。330表示430版本。可能大家会疑惑,我们不是讲4.3版本么?没关系,此处改成430即可。layout(location=0),是布局限定,目的是为变量提供元数据。我们可以使用布局限定符来设置很多不同的属性,其中有些是与不同的着色阶段相关的。在这里,设置 position的位置属性 location为0。in字段,它指定了数据进入着色器的流向,还可以声明变量为out。片元着色器中我们就使用的是out,表示输出数据。
position和color都是我们自己声明的变量名,顾名思义就是位置和颜色。而gl_Positon则是顶点着色器的指定输出位置。
我们在着色器的main()函数中实现它的主体部分。 Opengl的所有着色器,无论是处于哪个着色阶段,都会有一个main()函数。对于顶点着色器而言,它所实现的就是将输入的顶点位置复制到顶点着色器的指定输出位置gl_Position中。而片元着色器的作用则是将输出的颜色设置为指定的颜色,颜色分量的四个值分别是RGBA。
知识点:Opengl着色器程序的编写与C语言等基于编译器的语言非常类似。我们使用编译器来解析程序,检查是否存在错误,然后将它翻译为目标代码。然后,在链接过程中将一系列目标文件合并,并产生最终的可执行程序。在程序中使用GLSL着色器的过程与之类似,只不过编译器和链接器都是 OPENGL API的一部分而已。

程序中通过下面的步骤我们对每个着色器程序进行设置。对于每个着色器对象:1)创建一个着色器对象。2)将着色器源代码编译为对象。3)验证着色器的编译是否成功。然后需要将多个着色器对象链接为一个着色器程序,包括:1)创建一个着色器程序。
2)将着色器对象关联到着色器程序。
3)链接着色器程序。
4)判断着色器的链接过程是否成功完成。
5)使用着色器来处理顶点和片元。

好了,那咱们再来看看着色器代码部分:


glCreateShader:根据给定的参数创建着色器对象。glShaderSource:指定着色器对象的源代码内容。glCompileShader:编译。glGetShaderiv:根据我们给定的参数,判断编译是否成功。glCreateProgram:创建一个着色器程序。glAttachShader:将着色器对象关联到着色器程序。glLinkProgram:链接着色器程序。glGetProgramiv:判断着色器的链接过程是否成功完成。glDeleteShader:删除释放指定的着色器对象。
好啦,数据初始化完成,着色器也初始化完成啦




接着就是咱们的Init函数进行统一调用了glClearColor:指定了背景色
RenderScene函数逐句解析:glClear:指定每次渲染清空掉的是颜色缓冲区的内容。glUseProgram:使用指定的着色器程序。glBindVertexArray:绑定对应的顶点数组,参数为0是解绑。glDrawElements:按照指定图元和指定索引数组绘制对应的图形。glutSwapBuffers:从后台缓冲区刷新到前台缓冲区。
好啦~咱们的第一个程序就解析工作完毕!码起来~~~~希望小伙伴们多多捧场,添加关注并介绍给身边的小伙伴哦

丹丹也期待大家的意见和建议,欢迎小伙伴们积极留言
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息