OpenGL学习笔记3——缓冲区对象
在GL中特别提出了缓冲区对象这一概念,是针对提高绘图效率的一个手段。由于GL的架构是基于客户——服务器模型建立的,因此默认所有的绘图数据均是存储在本地客户端,通过GL内核渲染处理以后再将数据发往GPU显示。假设这样一种情况,有一批数据并不经常更改而数目又挺大,如果按照通常的做法无非是不断重复不断重复发送数据,整个操作主要内容变成了传输数据。针对这种窘况,GL内核允许客户将客户端的数据直接在GPU显存区域开辟一段缓冲区存储,存储具备这种特点的数据。
此时,考虑另一种极端情况,绘图数据需要实时渲染更新,此时若也使用缓冲区对象则其资源、操作开销的优势就没有那么明显,这种情况不如按照通常的手段。
另外,说起缓存区很容易让人联想到内存,下意识认为new或者malloc也能动态开辟内存,这其实是一个误区。首先,应用程序都是加载在内存里运行无需你再开辟缓存,本身就是缓存;其次,硬件制造商针对GL内核开放显存访问接口使得我们只需用一些函数就能直接访问显存。
下面就以一个按键缩放立方体的例子说明如何使用GPU的显存,相关函数的使用在代码旁边都做了简单解释。
注意点:
(1)新添glext扩展库,用于支持访问显存。具体添加方法参照第一篇《OpenGL学习笔记0——安装库》
(2)GL根据缓冲区对象的类型将相同的类型的缓冲区对象“连续存放”——同是定点类的数据存放在一起,同是索引类的数据存放在一起,展现给用户的是连续存放的显存。猜想,显存驱动或者GL内核通过类似“句柄”这种操作隐藏了同类数据在缓存中分开存储的这一事实。因此在调用缓冲区数据进行绘图操作时候要特别特别小心偏移量的问题,默认NULL是某类缓冲区对象起始地址。这样的做法带来的缺点是需要程序员来定义好偏移地址不能互相覆盖,然而带来的好处就是一类缓冲区只对应唯一一个“指针”(该类起始地址为NULL的内存地址)。因此,在调用的时候你就发现相关的接口是不返回或者接受任何指针的,唯一需要你填写的就是偏移地址。这一点和普通的主板内存申请和释放操作是不太一样的。
- #pragma comment(lib,"glut32.lib")
- #pragma comment(lib,"glut.lib")
- #pragma comment(lib,"GlU32.lib")
- #pragma comment(lib,"glext.lib")
- #include<GL\glut.h>
- #include<GL\glext.h>
- #include<Windows.h>
- //global variables
- GLfloat vertices[] = {
- -0.5f, -0.5f, -0.5f,
- 0.5f, -0.5f, -0.5f,
- -0.5f, 0.5f, -0.5f,
- 0.5f, 0.5f, -0.5f,
- -0.5f, -0.5f, 0.5f,
- 0.5f, -0.5f, 0.5f,
- -0.5f, 0.5f, 0.5f,
- 0.5f, 0.5f, 0.5f,
- };
- GLubyte indices[][] = {
- , , , ,
- , , , ,
- , , , ,
- , , , ,
- , , , ,
- , , , ,
- };
- GLuint VertexBuffer[];
- GLuint VertexIndexBuffer[];
- GLfloat rotate;
- GLfloat* ptr;
- //func protype
- void CubeInit(void);
- void GetKey(unsigned char key, int x, int y);
- void Display(void);
- void Timer0(int id);
- //main func
- int main(int argc, char* argv[])
- {
- glutInit(&argc, argv);
- glutInitDisplayMode(GL_DOUBLE | GLUT_RGBA);
- glutInitWindowSize(, );
- glutCreateWindow("cube-vertex-buffer");
- glutKeyboardFunc(GetKey);
- glutDisplayFunc(Display);
- glutTimerFunc(,Timer0,);
- CubeInit();
- glutMainLoop();
- }
- //创建立方体的顶点数组、开辟一块对应的顶点缓存区
- void CubeInit(void)
- {
- glGenBuffers(,VertexBuffer);//创建用于存储顶点数据的一块缓存区
- glBindBuffer(GL_ARRAY_BUFFER,VertexBuffer[]); //与之绑定
- glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_DYNAMIC_DRAW);//将顶点数据拷贝到该缓存区域
- glGenBuffers(,VertexIndexBuffer);//创建用于存储顶点数组索引的一块缓存区
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,VertexIndexBuffer[]);//与之绑定
- glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);//将顶点数组索引拷贝到该缓
- glEnableClientState(GL_VERTEX_ARRAY);//开启顶点数组
- glVertexPointer(,GL_FLOAT,*sizeof(GLfloat),NULL);//将缓存区的顶点数据缓存内容存储到定点数组里,偏移量为0,即null
- glDrawElements(GL_QUADS,,GL_UNSIGNED_BYTE,NULL);//将缓存区的顶点索引存储进去,偏移量0,即null
- //默认的多边形表面是以填充的形式绘制,此处设置为轮廓线绘制
- glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
- //设定逆时针为正面
- glFrontFace(GL_CCW);
- }
- void Display(void)
- {
- glClearColor(0.0f,0.0f,0.0f,0.0f);
- glClear(GL_COLOR_BUFFER_BIT);
- glDrawElements(GL_QUADS,,GL_UNSIGNED_BYTE,NULL);
- glutSwapBuffers();
- }
- void GetKey(unsigned char key, int x, int y)
- {
- switch (key)
- {
- case'a':
- ptr = (GLfloat*)glMapBuffer(GL_ARRAY_BUFFER,GL_READ_WRITE);
- for (int i =; i <; i ++)
- {
- *(ptr + i) *=0.9f;
- }
- glUnmapBuffer(GL_ARRAY_BUFFER);
- glutPostRedisplay();
- break;
- default:break;
- }
- }
- void Timer0(int id)
- {
- glClear(GL_COLOR_BUFFER_BIT);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- glPushMatrix();
- glLineWidth(2.4);
- //由于采用了矩阵压栈和出栈的处理,使得此处旋转的角度采用全局变量,存储角度
- //旋转角度实则对360°为一个周期。
- rotate += 0.2;
- glRotatef(rotate,,,);
- glRotatef(rotate,,,);
- glRotatef(rotate,,,);
- glDrawElements(GL_QUADS,,GL_UNSIGNED_BYTE,NULL);
- glPopMatrix();
- glutSwapBuffers();
- glutTimerFunc(,Timer0,);//for continue timer counting
- }
OpenGL学习笔记3——缓冲区对象的更多相关文章
- OpenGL学习笔记:拾取与选择
转自:OpenGL学习笔记:拾取与选择 在开发OpenGL程序时,一个重要的问题就是互动,假设一个场景里面有很多元素,当用鼠标点击不同元素时,期待作出不同的反应,那么在OpenGL里面,是怎么知道我当 ...
- JavaScript:学习笔记(9)——Promise对象
JavaScript:学习笔记(9)——Promise对象 引入Promise Primose是异步编程的一种解决方案,比传统的解决方案回调函数和事件更加合理和强大.如下面为基于回调函数的Ajax操作 ...
- 《python基础教程(第二版)》学习笔记 类和对象(第7章)
<python基础教程(第二版)>学习笔记 类和对象(第7章) 定义类class Person: def setName(self,name): self.name=n ...
- JavaScript:学习笔记(10)——XMLHttpRequest对象
JavaScript:学习笔记(10)——XMLHttpRequest对象 XHR对象 使用XMLHttpRequest (XHR)对象可以与服务器交互.您可以从URL获取数据,而无需让整个的页面刷新 ...
- JavaSE中Collection集合框架学习笔记(3)——遍历对象的Iterator和收集对象后的排序
前言:暑期应该开始了,因为小区对面的小学这两天早上都没有像以往那样一到七八点钟就人声喧闹.车水马龙. 前两篇文章介绍了Collection框架的主要接口和常用类,例如List.Set.Queue,和A ...
- Python学习笔记之类与对象
这篇文章介绍有关 Python 类中一些常被大家忽略的知识点,帮助大家更全面的掌握 Python 中类的使用技巧 1.与类和对象相关的内置方法 issubclass(class, classinfo) ...
- Javascript学习笔记——操作浏览器对象
Javascript学习笔记 目前尝试利用javascript去对于一个浏览器对象完成一系列的访问及修改, 浏览器是网页显示.运行的平台,常用的浏览器有IE.火狐(Firefox).谷歌(Chrome ...
- c++学习笔记之类和对象(三、static静态成员变量和静态成员函数)
一.static静态成员变量 对象的内存中包含了成员变量,不同的对象占用不同的内存,这使得不同对象的成员变量相互独立,它们的值不受其他对象的影响.是有时候我们希望在多个对象之间共享数据,对象 a 改变 ...
- Java NIO 学习笔记五 缓冲区补充
1.缓冲区分配 方法 以 ByteBuffer 为例 (1)使用静态方法 ByteBuffer buffer = ByteBuffer.allocate( 500 ); allocate() 方法 ...
随机推荐
- bootstrap-16
进度条----基本样式: Bootstrap框架中对于进度条提供了一个基本的样式,一个100%宽度的背景色,然后高亮颜色表示完成进度.其实制作这样的进度条非常容易,一般是使用两个容器,外容器具有一定的 ...
- CSS样式--实际开发总结
1. div 嵌套,子div中内容超出范围可以设置: display:inline-block; overflow:auto 即可让子div中出现滚轴 2. 让div中内容垂直方向居中 设置: ...
- UML类图分析
继承: 实现: 关联: 依赖: 组合: 聚合:
- 创建js对象的属性和方法
按照如下的创建对象的方法,可以节省内存.记录一下方便日后使用 <!Doctype html><html> <head> <title></titl ...
- dfs序
dfs序比较重要的性质:一棵子树的所有节点在dfs序里是连续一段,主要就是利用这个性质来解题 题型一:对某个点X权值加上一个数W,查询某个子树X里所有点权值和. 解:列出dfs序,实现修改一个数,查询 ...
- tomcat跨域请求
tomcat A请求tomcat B中的数据(本人是在同一台机器上2个tomcat端口不同,在不同机器上有时间会测得) 博主用的是ajax请求 在A 请求B中数据,用下面的方法可以 在被请求的tomc ...
- jquery之实例应用
Query是一个兼容多浏览器的javascript库,核心理念是write less,do more(写得更少,做得更多),对javascript进行了封装,是的更加便捷的开发,并且在兼容性方面十分优 ...
- Head First 设计模式之观察者模式(Observer Pattern)
前言: 这一节开始学习观察者模式,开始讲之前会先像第一节那样通过一个应用场景来引入该模式.具体场景为:气象站提供了一个WeatherData对象,该对象可以追踪获取天气的温度.气压.湿度信息,Weat ...
- Verilog HDL那些事_建模篇笔记(实验七:数码管电路驱动)
1.同步动态扫描 多个数码管的显示采用的是同步动态扫描方法,同步动态扫描指的是:行信号和列信号同步扫描,是一种并行操作. 2.数码管驱动电路实现思路 如果要求数码管显示我们想要的数字,首先需 ...
- nginx(tengine)的一些小优化(持续更新)
1.nginx日志切割脚本 需求来源:nginx本身并没有日志切割的功能,由访问产生的大日志很难进行分析. 实现目的:每天对nginx日志进行切割,并备份至指定文件夹. 简要指令: mv /usr/l ...