博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
OpenGL 笔记<1> 固定管线实例 + 双缓存测试实例
阅读量:5066 次
发布时间:2019-06-12

本文共 5069 字,大约阅读时间需要 16 分钟。

 

欲以此分类来记录opengl的学习历程,此为第一篇,所以先来一个固定管线的例子,以及对双缓存的测试。

 

一、配置环境

写之前,先进行配置,然后再讲内容。

注:第一部分涉及的代码均忽略。

 

二、所需知识

1. opengl程序结构

    main函数结构大体上由如下几个步骤:

1) glutInit(&argc, argv);    读取命令行参数,初始化glut2) glutInitDisplayMode(unsigned int mode);    设置显示模式(或窗口类型) (本节涉及参数如下)    GLUT_RGB    GLUT_RGBA    GLUT_DOUBLE3) glutInitWindowSize(int, int);    设置窗口规格4) glutInitWindowPosition(int, int);    设置窗口初始位置5) glutCreateWindow(char*);6) if(glewInit()) ....    判断glew是否初始化成功7) init()    初始化数据 ,函数体自己写8) glutDisplayFunc(函数指针);    系统自带的显示回调宏,在glut每次更新窗口内容的时候自动调用。9) glutMainLoop();    无限循环,一直处理窗口消息,如:判断是否需要进行重绘,然后自动调用glutDisplayFunc()中注册的函数(即参数)。

2. 初始化数据

glGen*  系列函数,用于OpenGL 分配不同类型的对象名称。

glBind*  系列函数,将已分配的对象名称进行绑定,设定为当前活动对象。

以VBO(Vertex Buffer Object  顶点缓冲对象)为例,来理解上面两个函数的理念,其中VBO是一个GLuint对象,即无符号整型。

我们程序员想要操控缓冲区,怎么办呢,缓冲区位于系统硬件中,对编程人员是不可见的。所以,opengl建立了一个映射机制,以一个GLuint的数据对象来代表某一缓存区。

其中,缓存区为映射的一端,VBO为另一端,我们首先要创建所需的VBO对象,然后通过glGenBuffers(VBO数量,VBO取址);来激活VBO对象作为某一映射的映射端。

因为程序员创建的GLuint对象,系统默认为一个普通的对象,只有通过glGenBuffers(),才能使系统将其认定为缓存区映射的对象。

而glBindBuffer(分配缓冲区类型,已激活的VBO对象);用于建立此映射,将VBO绑定到一个缓冲区,将当前VBO代表的缓冲区作为当前活动对象。尔后的所有关于缓冲区的操作均对当前VBO对象代表的缓冲区进行操作。

 

glBufferData(缓冲区类型,大小,数据,数据的读写方式);

刚刚说到VBO映射到一块缓冲区,但是里面并没有信息数据,所以要将数据传到缓冲区中,就是上述函数的作用。

 

我们可以通过glBufferData将一组顶点位置坐标信息传入到VBO1代表的缓冲区中,然后将顶点的颜色信息传入到VBO2代表的缓冲区中,当我们渲染的时候,需要颜色信息对颜色信息进行处理加工的时候,我们就通过GLBindBuffer,将VBO2绑定为当前活动对象,反之,同理。

 

上述,以VBO为例讲述了相关的一些概念,其他类似的函数同理。

 

3. 渲染

glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* pointer)

参数解析表
参数名 数值 解释
index GLuint     如:0 顶点着色器中输入变量的location值,就是属性的索引
size GLint       如:2 每个顶点的属性数量,如:x、y
type GLenum  如:GL_FLOAT 顶点属性变量的数值类型
normalized GLboolean  如:GL_FALSE 设定了顶点数据存储前是否进行归一化
stride GLsizei     如:0 相邻属性变量之间间隔的比特长度
pointer GLvoid*    如:BUFFER_OFFSET(0) 数据读取时,开始位置的偏移量

通过该函数告诉管线怎样解析buffer中的数据

 

glDrawArrays(绘制方式,第一个顶点的索引,顶点数量);

void glFlush(void);

强制所有进行中的OpenGL命令立即完成并传输到OpenGL服务端处理。这样就可以保证它们在一定时间内全部完成。

但是,该函数只是强制所有运行中的命令送入服务端而已,它会立即返回,它并不会等待所有的命令完成,而等待确实我们需要做的。。。

glFinish();

它会一直等待所有当前的OpenGL命令立即执行,等待他们全部完成。但是可想而知,它会拖累程序整体性能。

 

三、代码

1 //配置代码  2 #if _MSC_VER>=1900  3 #include "stdio.h"  4 _ACRTIMP_ALT FILE* __cdecl __acrt_iob_func(unsigned);  5 #ifdef __cplusplus  6 extern "C"  7 #endif  8 FILE* __cdecl __iob_func(unsigned i) {  9     return __acrt_iob_func(i); 10 } 11 #endif /* _MSC_VER>=1900 */ 12  14 #include 
15 using namespace std; 16 17 //我们需要包含 "val.h" 和 "LoadShaders.h" 18 //如果你按照之前配置环境那样做了,需要: 19 //#include "vgl.h" 21 22 //我这里是自己将两个文件放到VS库目录里面了,总之,只要正确引用两个文件即可 23 #include
26 27 //顶点缓冲对象初始下标、缓冲对象数量、顶点属性数量、顶点数量 28 enum {Arraybuffers, Numbuffers, AttriNum = 3, VerNum}; 29 30 GLuint buffers[Numbuffers]; //顶点缓冲对象数组 the array of VBOs 31 32 void init(); 33 void Display(); 34 35 int main(int argc, char** argv) 36 { 37 //命令行初始化glut 38 glutInit(&argc, argv); 39 40 //初始化显示模式 41 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); 42 43 //初始化windows 44 glutInitWindowSize(900, 600); 45 glutInitWindowPosition(20, 20); 46 glutCreateWindow("my work 1"); 47 48 //检查glew是否就绪 49 if (glewInit()) 50 { 51 cout << "glew didn't go work!" << glewGetErrorString(glewInit()) << endl; 52 exit(EXIT_FAILURE); 53 } 54 55 //初始化数据 56 init(); 57 58 //渲染 59 glutDisplayFunc(Display); 60 61 glutMainLoop(); 62 63 return 0; 64 } 65 66 void init() 67 { 68 //顶点数据 69 GLfloat vertices[VerNum][AttriNum] 70 { 71 { 0.8,0.8,0 }, 72 { -0.1,0,0}, 73 {
0.8,-0.8,0}, 74 {-0.8,0,0}, 75 }; 76 77 //创建缓冲器 78 glGenBuffers(Numbuffers, buffers); 79 //绑定缓冲器 80 glBindBuffer(GL_ARRAY_BUFFER, buffers[Arraybuffers]); 81 //向缓冲区传递数据 82 glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW); 83 84 //设置清除颜色 85 glClearColor(0, 0, 0, 0); 86 } 87 88 void Display() 89 { 90 //清空颜色缓存 91 glClear(GL_COLOR_BUFFER_BIT); 92 93 //开启顶点属性数组 94 glEnableVertexAttribArray(0); 95 96 glBindBuffer(GL_ARRAY_BUFFER, buffers[Arraybuffers]); 97 98 glVertexAttribPointer(0, AttriNum, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); 99 100 //绘制 两个三角形101 glColor4f(1, 0, 0, 0.3); //设置颜色102 glDrawArrays(GL_TRIANGLES, 0, VerNum);103 glColor4f(0, 0, 1, 0.8);104 glDrawArrays(GL_TRIANGLES, 1, VerNum); 105 //1. 将绘制好的两个三角形放到屏幕前面106 glutSwapBuffers();107 108 //在后面的帧缓存中继续绘制 一个四边形 边框109 glColor4f(1, 0.1, 0.8, 0.0);110 glDrawArrays(GL_LINE_LOOP, 0, VerNum);111 112 //2. 将后面的四边形边框帧缓存放到屏幕前面113 glutSwapBuffers();114 115 //此时,理论上讲,后台的帧缓存应该为原来绘制的两个三角形116 glColor4f(1, 0.1, 0.8, 0.0);117 //我们在其基础上,加上边框118 glDrawArrays(GL_LINE_LOOP, 0, VerNum);119 120 //3. 显示的是两个三角形+边框121 glutSwapBuffers();122 123 //禁用顶点属性数组 这个要最后禁用124 glDisableVertexAttribArray(0);125 126 glFlush();127 }

 

四、效果

标号为1.处得到的效果:(将107-122注释掉)

标号2.处得到的效果(将114-122注释)

标号3.处的效果,即将后面帧缓存中的效果添加到原来帧缓存的图形中得到的效果

 

 

通过这一节的测试,我们真正的看到了双缓存的工作过程,以及内部数据信息。

 

感谢您的阅读,生活愉快~

转载于:https://www.cnblogs.com/lv-anchoret/p/9221504.html

你可能感兴趣的文章
关于Xshell无法连接centos6.4的问题
查看>>
css3动画——基本准则
查看>>
输入月份和日期,得出是今年第几天
查看>>
pig自定义UDF
查看>>
spring security 11种过滤器介绍
查看>>
代码实现导航栏分割线
查看>>
大数据学习系列(8)-- WordCount+Block+Split+Shuffle+Map+Reduce技术详解
查看>>
【AS3代码】播放FLV视频流的三步骤!
查看>>
枚举的使用
查看>>
luogu4849 寻找宝藏 (cdq分治+dp)
查看>>
日志框架--(一)基础篇
查看>>
关于源程序到可运行程序的过程
查看>>
转载:mysql数据库密码忘记找回方法
查看>>
scratch少儿编程第一季——06、人在江湖混,没有背景怎么行。
查看>>
【贪心+DFS】D. Field expansion
查看>>
C# Async与Await的使用
查看>>
Mysql性能调优
查看>>
iOS基础-UIKit框架-多控制器管理-实例:qq界面框架
查看>>
自定义tabbar(纯代码)
查看>>
小程序底部导航栏
查看>>