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() 方法 ...
随机推荐
- asd
弹出输入提示框 :window.prompt(); 24. 指定当前显示链接的位置 :window.location.href="URL" 25. 取出窗体中的所有表单的数量 :d ...
- MySQL字符串处理函数的几种常见用法
1.字符串大小写转化: (1).将tbl_student表的user_name字段所有小写字母,替换为大写: update tbl_student set user_name=UPPER(user_n ...
- sql中对于case when...then...else...end的写法和理解
查询配件主数据表(tbl_part_base_info)的所有数据和配件是否有物料(物料表(tbl_material)中有配件主数据表的part_no,就表示有物料,反之,则表示没有物料),用sql中 ...
- winfrom 限制文本框小数点后两位
private void numWeight_KeyPress(object sender, KeyPressEventArgs e) { if (char.IsNumber(e.KeyChar) | ...
- Android NDK几点回调方式
一.NDK中获取android设备ID的方式 Java代码如下(获取设备ANDROID_ID): final String androidId = Secure.getString(context.g ...
- IDEA IntelliJ常用设置以及快捷键(转)
转载自:http://macrochen.iteye.com/blog/1035680 关于字体的设置 IDEA下使用雅黑Consolas混合字体 快捷贱, 快捷贱 , 快捷键贱 In ...
- LeetCode() Binary Tree Level Order Traversal
感觉我这个思路好 先记录上一层有几个节点 /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeN ...
- Chapter 3: Develop the user experience
Plan for search engine optimization and accessibility 使用analytical tools分析HTML,如SEO toolkit from MS, ...
- Backbone.js学习之Backbone.View(视图)
Backbone.js为复杂WEB应用程序提供模型(models).集合(collections).视图(views)的结构.其中模型用于绑定键值数据和自定义事件:集合附有可枚举函数的丰富API: 视 ...
- 【转】GPU 与CPU的作用协调,工作流程、GPU整合到CPU得好处
在不少人的心目中,显卡最大的用途可能就只有两点--玩游戏.看电影,除此之外,GPU并没有其他的作用了.但是随着微软IE9的正式发布,不少人突然发现,微软一直提到一个名词:GPU硬件加速,从而也让不少人 ...