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() 方法 ...
随机推荐
- C#中web页面之间传递数组参数
一直以来用到的都是在url地址中传递string类型,那么如果是数组类型的该怎么传递呢? ]; arryStr[] = "a"; arryStr[] = "b" ...
- vm虚拟机安装雨林木风ghost镜像
每次安装总是提示没办法加载镜像,或者镜像不存在,总之就是读取不到光驱里的镜像文件. 这是需要注意的两点:cd光驱模式设置为IDE,不能是scsi和sata两种模式,然后再进入winpe系统就行.
- RY哥查字典
时间限制: 1 s 空间限制: 16000 KB 题目等级 : 钻石 Diamond 题目描述 Description RY哥最近新买了一本字典,他十分高兴,因为这上面的单词都十分的和谐,他天天查字典 ...
- 使用SAXReader读取ftp服务器上的xml文件(原创)
根据项目需求,需要监测ftp服务器上的文件变化情况,并将新添加的文件读入项目系统(不需要下载). spring配置定时任务就不多说了,需要注意的一点就是,现在的项目很多都是通过maven构建的,分好多 ...
- Next Permutation
Implement next permutation, which rearranges numbers into the lexicographically next greater permuta ...
- 注册noip.com动态域名的步骤
1.先打开这个网址 http://www.noip.com/ 2.点击页面右上绿色的Sing Up,进行注册 3.会出现这个页面,把这些填上 Create my hostname later这一项不打 ...
- 控制器(Controller) – ASP.NET MVC 4 系列
创建一个 ASP.NET MVC 4 Web Application 项目,将程序命名为 MvcMusicStore,如下图: 控制器 MVC 模式中,控制器主要负责响应用 ...
- HashMap 与 HashTable的区别
1.HashTable的方法是同步的,HashMap未经同步,所以在多线程场合要手动同步HashMap这个区别就像Vector和ArrayList一样.可以用synchronized实现HashMap ...
- Changing SID Server 2012
Changing SID Server 2012 Windows Server > Windows Server 2012 General Question 0 Sign in to vote ...
- 利用百度云免费备份SQL数据库
我们开发了一个会员管理系统,随着使用的人越来越多,异地备份数据库就显得十分重要,万一硬盘出问题了怎么办呢.所以就着手做这个工作. 首先呢,找到了几个专门用来提供备份数据库的网站,一年好几百,好贵.放弃 ...