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() 方法 ...
随机推荐
- jsp中target="_blank"的用法
对于点击查询按钮或a标签等,打开一个新页面并显示结果的做法如下: 1.form表单: 在form标签上加target="_blank"后,点击搜索按钮,显示查询结果时会打开一个新页 ...
- C#循环语句练习2
1.羽毛球拍15元,球3元,水2元,有200元,每一种至少买一件,问有几种买法? 2.洗发水15元,牙刷5元,香皂2元,有150元,每一种至少买一件,问有几种买法? 3.用100元钱买100只鸡,公鸡 ...
- 数论 UVA 10791
这道题目是关于满足同意最小公倍数的所有数对中两数之和的最小值. 题目大意是给你一个数n,要求你求出在所有以n为最小公倍数的数对中两数之和的最小值. 方法:将n进行质因数分解,再将所有分解出的质因子加起 ...
- pyqt4:在线程Qthread中使用定时器Qtimer
GUI main 部分,主app类中的__init__初始化方法中添加 实例化线程 self.s2_thread=Worker2() 初始化一个定时器 self.log_get=QtCore.QTim ...
- React组件性能优化
转自:https://segmentfault.com/a/1190000006100489 React: 一个用于构建用户界面的JAVASCRIPT库. React仅仅专注于UI层:它使用虚拟DOM ...
- jquery对象和dom对象的相互转换
更好的学习jquery,要区分好jquery对象和dom对象的区别. 先具体说说dom.举个例子 <html> <head></head> <body> ...
- C语言字符串操作总结大全(超详细)
本篇文章是对C语言字符串操作进行了详细的总结分析,需要的朋友参考下 1)字符串操作 strcpy(p, p1) 复制字符串 strncpy(p, p1, n) 复制指定长度字符串 strcat( ...
- 10天学会phpWeChat——第七天:创建一个自适应PC网站+H5移动端的模块
本教程基于phpWeChat核心框架1.1.0+版本.下载地址:http://s.phpwechat.com/app_38026ed22fc1a91d92b5d2ef93540f20 通过前面六讲的系 ...
- FCN网络的训练——以SIFT-Flow 数据集为例
参考文章: http://blog.csdn.net/u013059662/article/details/52770198 caffe的安装配置,以及fcn的使用在我前边的文章当中都已经提及到了,这 ...
- cxxnet在windows下配置遇到的问题
I compiled the dmlc-core and rabbit. When I compile the new version of CXXNET, there are compile err ...