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() 方法 ...
随机推荐
- STM32下载调试驱动问题
No Cortex-m SW device found解决办法 16.07.14 今天工作,遇到一个问题:用jlink采用SW下载模式时,一直显示No Cortex-m SW device found ...
- 关于Unity中SteamVR_Controller.Input的错误
当我在看某鸥的视频的时候,里面讲到用Unity做一个贪食蛇后,加入SteamVR插件,并且能用手柄控制蛇的移动.当我跟着上面一步一步做的时候,发现我代码都写完后,启动报错,而视频里面的老师讲的缺没有报 ...
- EF 未应用自动迁移,因为自动迁移会导致数据丢失的解决办法
在 工具->库程序包管理器->程序包管理器控制台 窗口里运行 Add-Migration Initial 指令再输入Update-Database执行
- python logging模块
1.logging模块提供了四个组件logger:日志类,有两个功能1)配置日志的等级,处理器handler,过滤器filterlogger.setLevel(logging.INFO)logger. ...
- java-装箱/拆箱-字符串转换成基本数据类型
一.理解java中包的含义及种类 java是一个面向对象编程,即一切皆是对象,那么有一个矛盾,从数据上划分知道java中的数据分为基本数据类型和引用数据类型,但是基本数据类型如何是一个对象呢?此时,就 ...
- python之元编程(元类实例)
本实例是元类实例,功能是记录该的子类的类名,并以树状结构展示子类的类名. RegisterClasses继承自type,提供的功能是在__init__接口,为类创建了childrens的集合,并类名保 ...
- Python单元测试和Mock测试
单元测试 测试可以保证你的代码在一系列给定条件下正常工作 测试允许人们确保对代码的改动不会破坏现有的功能 测试迫使人们在不寻常条件的情况下思考代码,这可能会揭示出逻辑错误 良好的测试要求模块化,解耦代 ...
- D3树状图异步按需加载数据
D3.js这个绘图工具,功能强大不必多说,完全一个Data Driven Document的绘图工具,用户可以按照自己的数据以及希望实现的图形,随心所欲的绘图. 图形绘制,D3默认采用的是异步加载,但 ...
- [JBoss] - 解决URI提交时乱码问题
JBoss 7 AS解决url提交数据乱码的问题: 打开jboss-as-7.1.1.Final\standalone\configuration\standalone.xml文件,在<exte ...
- Spring事务配置的五种方式
Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource.TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分. DataSo ...