目标 1. 清除窗口
2.强制完成所有尚未执行的绘图操作
3.在2d或3d空间绘制图元
4.打开、关闭、查询状态
5.控制图元显示
6.在实心物体表面适当位置指定法线向量
7.用顶点数组和缓冲区对象存储和访问几何数据。
8.同时保存和恢复几个状态变量。
1.1 3种基本操作:清除窗口、绘制几何图形、绘制光栅对象。
2. 绘图工具箱:
2.1 清除RGBA模式的窗口
glClearColor(R, G, B, A); //将当前清除颜色设置成为一个状态变量 glClearDepth(1.0); //指定深度缓冲区中每个像素要设置的值 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); // 表示要清除的缓冲区为颜色缓冲区和深度缓冲区
2.2 指定颜色
glColor3f(R,G,B);
2.3 强制完成绘图操作
void glFlush(void); void glFinish(void);
2.4 坐标系统工具箱
当窗口发生改变的时候,会发送一个时间作为通知。在glutReshapeFunc()中注册的那个函数会被调用。并且必须注册一个回调函数完成下面任务:
1)重新建立一个矩形区域,把它作为新的渲染画布。
2)定义一个用于绘制物体的坐标系统。
//一个2d的glutReshapeFunc(reshape)回调函数 void reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei) h);//调整用于绘图的像素矩形,使它占据整个窗口 glMatrixMode(GL_PROJECTION); //接下来的三行代码表示让坐标系的左下角为原点(0,0) glLoadIdentity(); gluOrtho2D(0.0, (GLdouble)w, 0.0, (GLdouble)h); }
3 描述图元:点、直线、多边形
3.1 矩形:
void glRect{sifd}(x1, y1, x2, y2);
3.2 指定顶点:
void glVertex[234]{sifd}(); //注意只有在glBegin 和glEnd之间时才有效
void glVertex[234]{sifd}v();
3.3 几何图元:
将一组顶点放在glBegin 和glEnd之间, 传递给glBegin的参数决定了利用这些顶点所构成的几何图元的类型;
有GL_POINTGL_LINESGL_LINE_STRIPGL_LINE_LOOPGL_TRIANGLESGL_TRIANGLES_STRIPGL_TRIANGLE_FANGL_QUADSGL_QUAD_STRIPGL_POLYGON
glBegin(GL_POLYGON); glVertex2f(0, 0); glVertex2f(0, 3); glVertex2f(3, 4); glEnd();
在glBegin和glEnd之间还可以用另外的一些函数来指定顶点的额外的属性数据, 例如:颜色glColor*(); 法线向量glNormal*(); 纹理坐标glTexCoord*();等
4. 基本状态管理
物体在渲染的时候可能会用到光照、纹理、隐藏表面消除、雾或者其他的状态
这都是由函数 void glEnable(); 和 void glDisalbe();来控制 , 例如有GL_BLEND, GL_DEPTH_TEST, GL_FOG, GL_LINE_STIPPE, GL_LIGHTING等。
查询GLboolean glIsEnable(GLenum capability); 它返回GL_TRUEGL_FALSE, 还可以查询其他类型的。
5. 显示点、直线和多边形
5.1 点
void glPointSize();
5.2 直线
线宽: void glLineWidth(GLfloat width);
点画线: void glLineStipple(GLint factor, GLushort pattern) ; 必须掉用glEnable(GL_LINE_STIPPLE)来启用点画线功能。
5.3 多边形细节
点、轮廓、实心:void glPolygonMode(GLenum face, GLenum mode); 参数face可以是GL_FRONT_AND_BACK, GL_FRONT, GL_BACK. 参数mode可以是GL_POINT, GL_LINE,GL_FILL
反转和剔除多边形表面:void glFrontFace(GLenum mode), mode表示哪面为正面 GL_CCW表示逆时针方向为正面, GL_CW表示顺时针方向为正面。
剔除:glEnable(GL_CULL_FACE); void glCullFace(GLenum mode);
点画多边形:glEnable(GL_POLYGON_STIPPLE); void glPolygonStipple();
5.4 法线
void glNormal*()
5.5 标记多边形的边界边
void glEdgeFlag(GL_TRUE) 表示其后的顶点为边界边的起点。
6. 顶点数组(我认为是顶点相关的属性数组)
使用顶点数组对几何图形进行渲染需要三个步骤:
1)激活顶点数组:顶点坐标(数组)、表面法线、RGBA颜色,辅助颜色、颜色索引、雾坐标、纹理坐标、多边形边界标志
void glEnableClientState(GLenum array);//GL_VERTEX_ARRAY, etc.
void glDisableClientState();
2)把数据放入数组中。
void glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid* pointer);//size是每个顶点的坐标数量2/3/4,stride是连续顶点之间的字节偏移量。type为GL_INT等,pointer是第一个顶点的内存位置
void glColorPointer()void glSecondaryColorPointerglIndexPointerglNormalPointerglFogCoordPointerglTexCoordPointerglEdgeFlagPointer
static GLint vertics[] = { 25, 25, 100, 325, 175,25 } static GLfloat colors[] = { 1.0, 0.2, 0.2, 0.2, 0.2, 1.0, 0.8, 1.0, 0.2 } glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); glColorPointer(3, GL_FLOAT, 0, colors); glVertexPointer(2, GL_INT, 0, vertices);
3)用这些数据绘制几何图形:解引用和渲染。
解引用:客户端的数组中数据被提取发送到服务器,然后发送到图形处理管线进行渲染。
a. void glArrayElement(GLint ith); 获取当前已启用数组(可以是多个)的第ith个顶点数据。
glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_VERTEX_ARRYA); glColorPointer(3, GL_FLOAT, 0, colors); glVertexPointer(2, GL_INT, 0, vertices); glBegin(GL_TRIANGLES) glArrayElement(2); glArrayElement(3); glArrayElement(5); glEnd();
b. void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); // mode表示要创建那种图元GL_POLYGON/GL_LINE_LOOP/GL_LINES/GL_POINTS, count表示解引用数组元素的个数,type表示类型为GL_UNSIGNED_BYTE等, indices表示元素的内存索引位置。
c. void glMultiDrawElements(GLenum mode, GLsizei *count, GLenum type, const GLvoid **indices, GLsizei primcount); //调用primcount个glDrawElements()函数
static GLubyte oneIndices[] = {0, 1, 2, 3, 4, 5, 6}; static GLubyte twoIndices[] = {7, 1, 8, 9, 10, 11} static GLsizei count[] = {7, 6}; static GLvoid * indices[2] = {oneIndices, twoIndices}; glMultiDrawElements(GL_LINE_STRIP, count, GL_UNSIGNED_BYTE, indices, 2);
d. void glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);//
e. void glDrawArrays(GLenum mode, GLint first, GLsizei count); //
f. void glMultiDrawArrays(GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
4)图元重启索引:
void glPrimitiveRestartIndex(GLuint index);
指定一个顶点数组元素索引,用来表示一个新的图元在渲染时的开始位置。当顶点数组元素索引的处理中遇到和index匹配的一个值的时候,就没有顶点数据要处理了,当前的图形图元就终止了,相同类型的一个新的图元开始了。通过调用glEnable()或者glDisable来控制图元重启GL_PRIMITIVE_RESTART。
5)实例化绘制
void glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount); 相当于以下效果:
for(i = 0; i < primcount; i++) { gl_instanceID = i; glDrawArrays(mode, first, count); } gl_InstanceID = 0;
void glDrawElementsInstanced();
6) 混合数组
void glInterleavedArray(GLenum format, GLsizei stride, const GLvoid * pointer);
7. 缓冲区对象
1)创建缓冲区对象:利用opengl分配缓冲区对象标识符,调用void glGenBuffers(GLsizei n, GLuint *buffers);//buffers 数组返回n个当前未使用的名称,表示缓冲区对象
调用GLboolean glIsBuffer(GLuint buffer);来判断一个标志符是否是当前被使用的缓冲区对象标识符
2) 激活缓冲区对象:为了激活缓冲区对象,首先需要将它绑定,使用void glBindBuffer(GLenum target, GLuint buffer); //target必须要设置成GL_ARRYA_BUFFERGL_ELEMENT_ARRAY_BUFFER... , buffer指定了要绑定的缓冲区对象。
3) 数据分配和初始化缓冲区对象: 一旦绑定了缓冲区对象就需要保留空间以存储数据,通过调用void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage); //将客户机中data指示的数据size个复制到服务器缓冲区。
4)更新缓冲区对象的数据值:void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid * data);//用data指向的数据更新与target相关联的当前绑定缓冲区对象中offset开始的size个字节数据。
GLvoid *glMapBuffer(GLenum target, Glenum access); 这个函数返回一个指向缓冲区对象的指针。
在完成了对数据存储的访问以后可以调用glUnmapBuffer()来取消对这个缓冲区的映射。
GLfloat*data; data = (GLfloat*) glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); if(data!=(GLfloat*)NULL) { for(i = 0; i<8 ; i++) { data[3*i + 2]*=2.0;//modify Z value glUnmapBuffer(GL_ARRAY_BUFFER); } } else{}
GLvoid* glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);如果在access标志中使用了GL_MAP_FLUSH_EXPLICIT_BIT的话,还需要调用glFlushMappedBufferRange()向opengl表明映射缓冲区中的范围需要修改。
5)在缓冲区对象之间复制数据
void glCopyBufferSubData(GLenum readbuffer,GLenum writebuffer, GLintptr readoffset, GLintptr writeoffset, GLsizeiptr size);
6) 清除缓冲区对象 glDeleteBuffers();
#define VERTICES 0 #define INDICES 1 #define NUM_BUFFERS 2 GLuint buffer[NUM_BUFFERS]; GLfloat vertices[][3] = { {-1.0, -1.0, -1.0}, {1.0, -1.0, -1.0}, {1.0, 1.0, -1.0}, ... {-1.0, 1, 1} } GLubyte indices[][4] = { {0, 1, 2, 3} ... {1, 5, 6, 2} } glGenBuffers(NUM_BUFFERS, buffers); glBindBuffer(GL_ARRAY_BUFFER, buffers[VERTICES]); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glVertexPointer(3, 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, 24, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
8、顶点数组对象
1)创建顶点数组对象,调用void glGenVertexArrays(GLsizei n, GLuint *array); //返回n个当前未使用的名字,用作数组arrays中的顶点数组对象。
2)使用GLvoid glBindVertexArray(GLuint array);
3)glDeleteVertexArrays();
9. 属性组
使用glPushAttrib()和glPopClientAttrib()来操作属性组。例如:GL_LINE_BIT包括了GL_LINE_SMOOTH在内的5个状态。
OPENGL有两个属性堆栈,除了原来的属性堆栈,还有一个客户堆栈,是通过glPushClientAttrib()和glPopClientAttrib()来函数访问的。