计算机图形学——顶点数组,缓存数组、索引...

╄→尐↘猪︶ㄣ 提交于 2019-11-26 12:59:47

以下操作只保证在兼容模式下可行,整理来自红宝书

  1. 顶点数组:

由于OpenGL需要进行大量的函数调用对几何图元进行渲染,为了减少函数调用次数以及相邻多边形的共享顶点的冗余处理,OpenGL提供了顶点数组函数,

1.1使用顶点数组的一般步骤是:激活最多可达八个数组,可用于存储不同类型的数据:顶点坐标、表面发现法线、RGBA颜色、辅助颜色、颜色索引、雾坐标、纹理坐标以及多边形的边界标志

实现函数:

glEnableClientState(GLenum array)

GLenum array可以是:GL_VERTEX_ARRAY,GL_COLOR_ARRAY,GL_INDEX_ARRAY,GL_NORMAL_ARRAY...等等具体可见红宝书第43页内容,如果使用光照,需要为每个顶点定义一条法线向量,需要同时激活表面法线数组和顶点坐标数组

用glDisableClientState()来关闭

1.2把数据放入数组,数组通过指向它们内存位置的指针进行访问

实现函数:

void glVertexPointer(GLint size(每个顶点的坐标数量,必须是2/3/4),GLenum type(GL_SHORT,GL_INT,GL_FLOAT,GL_DOUBLE),GLsize stride(连续顶点之间的字节偏移量,为零时顶点紧密相连),const GLvoid *pointer(数组中第一个顶点第一个坐标的内存地址))

void glIndexPointer(type,stride,pointer)

void NormalPointer(type,stride,pointer) 

1.3用这些数据绘制几何图形。OpenGL通过对指针进行解引用,从所有被激活的数组中获取数据,可以访问单独的数组元素,创建一个单独数组元素的列表,线性地处理数组元素,使用混合顶点数组

实现函数:

1.解引用单个数组元素:
void glArrayElement(GLint ith);通常在glBegin,end之间调用,这意味着我们后面基本上用不到它
2.解引用数组元素的一个列表:
void glDrawElements(mode(GL_POLYGON,GL_LINE_LOOP,GL_LINES,GL_POINTS),count,type(GL_UNSIGNED_BYTE,GL_UNSIGNED_SHORT,GL_UNSIGNED_INT),indices)
相当于
glBegin(mode);
for(i=0;i<count;i++)
  glArrayElement(indices[i]);
glEnd

**glMultiDrawElements()把几个glDrawElements()调用组合到一个函数调用中
**glDrawRangeElements()允许指定被预先提取的顶点范围

void glDrawArrays(mode,first,count)只能按顺序访问它们

2.缓冲区中的顶点数组,顶点数组可以减少调用函数的次数,但是数据仍然存储在内存里,每次需要顶点数组时,就会从客户机传输到OpenGL服务器,每帧都要传输数据对性能会造成影响,于是引入了缓冲区对象(buffer object)允许把数据存储在服务器中,并且只传输一次(前提是有足够的内存资源可以保存这些数据)如果需要修改数据,则可以更新存储在服务器中的值

要利用缓冲区对象存储顶点数据有以下几个步骤:

2.1为顶点数据创建缓冲区对象

void glGenBuffers(n,GLuint *buffers)

可以在buffers数组里面返回n个当前未使用的名字,表示缓冲区对象

2.2激活缓冲区对象:

也就是要将其绑定,绑定缓冲区对象表示选择未来的操作(数据初始化、渲染)将影响哪个缓冲区,需要多次调用

实现函数:

void glBindBuffer(GLenum target(GL_ARRAY_BUFFER/GL_ELEMENT_ARRAY_BUFFER),GLuint buffer);

glBuffer干的事情:

(1)当buffer是首次使用的GLuint,就创建一个新的缓冲区,把buffer分配给这个缓冲区对象,作为这个缓冲区对象的

名字->你就有了一个叫buffer的缓冲区

(2)当绑定到一个以前创建的缓冲区对象时,这个缓冲区对象就被激活了

把缓冲区对象绑定到0,OpenGL就会停止使用缓冲区对象

2.3用顶点数据分配和初始化缓冲区对象

实现函数:

void glBufferData(GL_ARRAY_BUFFER(顶点数组)/GL_ELEMENT_ARRAY_BUFFER(索引数据),size(存储相关数据需要的内存),*data(如果是NULL就会把申请的这些内存空间留着以后用),usage(GL_STREAM_DRAW,GL_STREAM_READ,GL_STREAM_COPY,GL_STATIC_DRAW...(我们一般用GL_STATIC_DRAW)));

整体实现代码:

GLuint buffers[NUM_BUFFERS];

GLfloat vertices[]={...}

GLuint indices[]={...}

//对数组创建缓存对象名字

glGenbuffers(NUM_BUFFERS,buffers);

//创建缓存对象

glBindBuffers(GL_ARRAY_BUFFER,buffers[VERTICES]);

//给缓存对象赋值

glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);

//创建数组指针

glVertexPointer(2,GL_FLOAT,0,BUFFER_OFFSET(0));

glEnableClientState(GL_VERTEX_ARRAY);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,buffers[INDICES]);

glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);

glDrawElements(GL_QUADS,SIZE_OF_MEMORY,GL_UNSIGNED_INT,BUFFER_OFFSET(0));//BUFFER_OFFSET(0)这里我们写的是NULL,不太清白这个意思,挖个坑先

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!