OpenGL缓存数据

简述

缓存对象(buffer  object)在OpenGL中十分重要,几乎所有的功能都需要用到它。常见操作包括它的创建,数据的输入, 数据的输出,销毁。

 

创建

在OPenGL中可以使用函数glGenBuffers()来创建缓存对象,调用之后只是得到了一个缓存对象名称的数组,这些名称只是个标记,并不是真正的缓存对象,需要绑定到OPenGL系统中才会创建出来,可以调用函数glBindVertexArray()来绑定。

void  glGenBuffers(GLsizei n, GLuint *buffers)

返回值:void

参  数:n  需要返回缓存对象的个数

buffers 缓存对象名

 

void  glBindBuffer(GLenum target, GLuint buffer)

返回值:void

参  数:target  绑定的目标,缓存目标可以根据实际情况设置,以达到最优的内存管理

buffer  缓存对象名


缓存绑定的目标

目标

用途

GL_ARRAY_BUFFER

可以用来保存glVertexAttribPointer()设置的顶点数组数据

GL_COPY_READ_BUFFER GL_COPY_WRITYE_BUFFER

这两个目标是一对互相匹配的结合点,用于拷贝缓存之间的数据,并且不会引起OpenGL的状态变化,也不会产生任何特殊形式的OPenGL调用

GL_DRAW_INDIRECT_BUFFER

如果采取间接绘制,那么这个目标用于存储绘制命令的参数

GL_ELEMENT_ARRAY_BUFFER

绑定这个目标的缓存可以包含顶点索引数据,用于glDrawElements()等索引形式的绘制命令

GL_PLXEL_PACK_BUFFER

这一缓存目标用于从图象对象中读取数据,例如纹理和帧缓存数据,相关OPenGL命令包括glGetTexImage()和glReadPixels()等

GL_PLXEL_UNPACK_BUFFER

这一缓存目标与GL_PLXEL_PACK_BUFFER正好相反,它可以作为glTexImage2D()等命令的数据源使用

GL_TEXTURE_BUFFER

纹理缓存也就是直接绑定到纹理对象的缓存,这样就可以直接在着色器中读取他们的信息,GL_TEXTURE_BUFFER可以提供一个操控此类缓存的目标,但还需要将缓存关联到纹理,才能确保能够使用

GL_TRANSFORM_FEEDBACK_BUFFER

transform feedback是OpenGL提供的一种便捷方案,它可以在管线的顶点处理部分结束时,将经过变换的顶点重新捕获,并将部分属性写入到缓存对象中,通常在几何着色器中使用较多

GL_UNFORM_BUFFER

这个目标可以用于创建uniform缓存对象的缓存数据

 

输入数据

缓存对象经过glBindBuffer()绑定后,只是创建了一块没有任何有效数据的缓存区域,还得向其中输入一些数据才能使用。OpenGL输入数据的方式有多种,比如直接显式的传递数据,或者用新的数据替换缓存对象中已有的部分数据等。

(1)在分配内存的时候读入数据,可以通过glBUfferData()函数来完成,

void  glBUfferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage)

返回值:void

参  数:target  缓存绑定的目标

size    数据大小

data   首地址

usage  缓存用途标识符

glBUfferData()函数式真正的为缓存对象分配存储空间的,如果新的数据大小比缓存对象当前分配的还要大,那么缓存对象的大小将从新设置更大的空间,反之,如果会设置更小的空间。

OpenGL对于缓存对象存储数据中的最优分配方案的管理,除了依赖初始化绑定时的参数target目标,还有一个参数就是glBUfferData()中的usage。usage必须是内置的标识符,标识符具体如下

分解的标识符

意义

_STATIC_

数据存储内容只写入一次,然后多次使用

_DYNAMIC_

数据存储内容会被反复写入和反复使用

_STREAM_

数据存储内容只写入一次,不会频繁使用

_DRAW_

数据存储内容由应用程序负责写入,作为OPenGL绘制和图像命令的数据源

_READ_

数据存储内容通过OPenGL反馈的数据写入,然后在应用程序进行查询是返回这些数据

_COPY_

数据存储内容通过OPenGL反馈的数据写入,作为OPenGL绘制和图像命令的数据源

具体实现

//顶点位置

float points[] = {

0.0f, 0.0f, 1.0f, 0.0f, 0.0f,

0.4f, 0.0f, 0.0f, 1.0f, 0.0f,

0.346f, 0.2f, 0.0f, 0.0f, 1.0f,

0.2f, 0.346f, 0.0f, 0.0f, 1.0f,

0.0f, 0.4f, 1.0f, 0.0f, 1.0f,

-0.2f, 0.346f, 1.0f, 1.0f, 1.0f,

};

//缓存对象

unsigned int buffer;

//创建缓存对象

glGenBuffers(1, &buffer);

//绑定

glBindBuffer(GL_ARRAY_BUFFER, buffer);

//分配空间,并传入数据

glBufferData(GL_ARRAY_BUFFER, sizeof(points), &points, GL_STATIC_DRAW);

 

(2)缓存的部分初始化

如果有两个数组,一个包含顶点数据,另一个包含颜色信息,需要将这些数据进行紧凑的打包,并且存入一个缓存对象让OpenGL使用,在数组之间的数据,内存可能不是连续的,一次无法使用glBufferData()一次输入所有数据。这时候需要引入另外一个函数glBufferSubData()。这两个函数结合使用,就可以对一个缓存对象初始化了。

void  glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data)

返回值:void

参  数:target  缓存绑定的目标

offset  地址偏移量

size    数据大小

data   数据

 

具体实现

//顶点位置

float points[] =

 {

0.0f, 0.0f, 1.0f, 0.0f, 0.0f,

0.4f, 0.0f, 0.0f, 1.0f, 0.0f,

0.346f, 0.2f, 0.0f, 0.0f, 1.0f,

0.2f, 0.346f, 0.0f, 0.0f, 1.0f,

0.0f, 0.4f, 1.0f, 0.0f, 1.0f,

-0.2f, 0.346f, 1.0f, 1.0f, 1.0f,

};

//顶点颜色

float color[] =

{

1.0f, 0.0f, 0.0f,

0.0f, 1.0f, 0.0f,

0.0f, 0.0f, 1.0f,

0.0f, 0.0f, 1.0f,

1.0f, 0.0f, 1.0f,

1.0f, 1.0f, 1.0f,

}

 

//缓存对象

unsigned int buffer;

//创建缓存对象

glGenBuffers(1, &buffer);

//绑定

glBindBuffer(GL_ARRAY_BUFFER, buffer);

//分配空间,第三个参数为NULL,只分配空间没有传入数据

glBufferData(GL_ARRAY_BUFFER, sizeof(points) + sizeof(color) , NULL, GL_STATIC_DRAW);

//传入顶点位置信息

glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(points), points);

//传入顶点颜色信息

glBufferSubData(GL_ARRAY_BUFFER, sizeof(points),, sizeof(color), color);


(3)通过映射缓存对象输入数据

目前为止的输入数据函数glBufferSubData()和glBindBuffer()都会进行数据拷贝操作。如果需要反复修改数据时,那么效率就太低了。其实还可以通过获取缓存的指针,直接在应用程序中对OPenGL管理的内存进行操作,对应的函数就是glMapBuffer()和glUmMapBuffer()。glMapBuffer()用于映射缓存,glUmMapBuffer()用于解除映射。

void*  glMapBuffer(GLenum target, GLenum access)

返回值:返回一个指向绑定到target的缓存对象的内存,如果失败则返回空

参  数:target  缓存绑定的目标

access  访问模式

 

GLboolean  glUmMapBuffer(GLenum target)

返回值:如果解除映射成功则返回GL_TRUE

参  数:target  缓存绑定的目标

 

访问模式

宏标识符

意义

GL_READ_ONLY

对映射的内存进行只读操作

GL_WRITE_ONLY

对映射的内存进行只写操作

GL_READ_WRITE

对映射的内存进行读或写操作

 

具体实现

//顶点位置

float points[] = {

0.0f, 0.0f, 1.0f, 0.0f, 0.0f,

0.4f, 0.0f, 0.0f, 1.0f, 0.0f,

0.346f, 0.2f, 0.0f, 0.0f, 1.0f,

0.2f, 0.346f, 0.0f, 0.0f, 1.0f,

0.0f, 0.4f, 1.0f, 0.0f, 1.0f,

-0.2f, 0.346f, 1.0f, 1.0f, 1.0f,

};

//缓存对象

unsigned int buffer;

//创建缓存对象

glGenBuffers(1, &buffer);

//绑定

glBindBuffer(GL_ARRAY_BUFFER, buffer);

//分配空间,但不传入数据

glBufferData(GL_ARRAY_BUFFER, sizeof(points), NULL, GL_STATIC_DRAW);

//内存映射

void* data = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);

//把数据写入指针

memcpy(data , points, sizeof(points));

//解除映射

glUmMapBuffer()

 

输出数据

既然可以把数据写入缓存当然也能从缓存读取数据,可以使用函数glGetBufferSubData()从绑定的缓存中直接读取数据。也可以使用内存映射的方式读取,通过glBufferData()函数返回一个指向缓存的指针,再从中读取数据。

void  glGetBufferSubData(GLenum  target, GLintptr offset, GLsizeiptr  size, GLvoid* data)

返回值:返回一个指向绑定到target的缓存对象的内存,如果失败则返回空

参  数:target  缓存绑定的目标

offset  首地址偏移量

size    回读数据的大小

data    传出参数,返回读到的数据

 

 

销毁

在完成对缓存数据的处理后,可以丢弃缓存数据了。要丢弃缓存对象的部分和全部数据,可以使用gllnvalidateBufferData()和gllnvalidateBufferSubData()。

void  gllnvalidateBufferData(GLuint  buffer)

void  gllnvalidateBufferSubData(GLuint  buffer, GLintptr offset, GLsizeiptr length)

返回值:void

参  数:buffer缓存对象

offset首地址偏移量

length丢弃数据的大小


参见:《OpenGL编程指南》第八版第3章

你可能感兴趣的:(OpenGL笔记,OpenGL笔记)