【计算机图形学-2】OpenGL图形编程总览
图形系统总览图形API处在应用接口和底层硬件的中间,负责:控制显卡的编程接口、计算与存储资源,输入显示内容,如三维场景/模型,生成输出图像。图形开发史两种主流图形API严格来讲,OpenGL并不是一个API,它仅仅是一个由Khronos组织制定并维护的规范。OpenGL规范严格规定了每个函数该如何执行,以及它们的输出值。至于内部具体每个函数是如何实现的,由OpenGL库的开发者自行决定。值得一提的
图形系统总览
图形API处在应用接口和底层硬件的中间,负责:控制显卡的编程接口、计算与存储资源,输入显示内容,如三维场景/模型,生成输出图像。
图形开发史
两种主流图形API
严格来讲,OpenGL并不是一个API,它仅仅是一个由Khronos组织制定并维护的规范。OpenGL规范严格规定了每个函数该如何执行,以及它们的输出值。至于内部具体每个函数是如何实现的,由OpenGL库的开发者自行决定。值得一提的是,2009年兴起的OpenGL 3.1并不向下兼容。在OpenGL 3.1以前,OpenGL使用立即渲染模式,这个模式下绘制图形很方便。OpenGL的大多数功能都被库隐藏起来,开发者很少有控制OpenGL如何进行计算的自由,且绘制效率较低。从OpenGL3.2开始,开始废弃立即渲染模式,开发者在OpenGL的核心模式下开发,这样就完全移除了旧的特性。
OpenGL编程和着色器语言
OpenGL的编程,相对于普通编程难度较大,需要先有一些前置知识做铺垫:
-
两个重要的概念——vao和vbo(顶点数组对象和顶点缓冲对象)
早期的OpenGL为了将模型的顶点数据传送到显卡,需要逐个顶点进行(冗余问题),如果还需要额外的信息(纹理坐标和法线)的话,当模型比较复杂时,将导致大量函数的调用,传输开销是相当大的!为了解决这个问题引入了VBO(Vertex Buffer Object),VBO可以将顶点数据保存在显存中,绘制时直接从显存中取数据,减少了数据传输的开销。一句话总结就是:vbo保存要传递给GPU的数据。
虽然通过VBO我们可以将顶点属性数据保存在显存中,但是当绘制时,问题又来了,需要调用好几个函数,过程挺复杂的。为了解决这个问题,OpenGL又引入了==VAO(Vertex Array Object)==来关联VBO中的数据,有了VAO,任何数组形式的GL函数调用都会添加到VAO的绘制列表当中(直到解除VAO绑定),当需要绘制的时候,我们仅需要重新绑定VAO,那么之前创建的绘制列表将会重新激活,使得绘制代码更加简洁。一句话总结:vao定义了GPU读取vbo中数据的方式。
-
重要工具——着色器
OpenGL着色器有几种,最重要也是最常用的是顶点着色器和片元着色器,顶点着色器对顶点信息进行处理,片元着色器对片元进行处理。最简单的着色器长下面这样:
gl_Position默认是归一化的裁剪空间坐标,xyz各个维度的范围为-1到1,仅能在顶点着色器中使用,既是输入也是输出。 -
OpenGL库
-
OpenGL的渲染管线(Pipeline)
图元与观察
图元:一般指基本图形元素,显卡处理流水线能够理解的几何与图像数据单元分为几何图元与光栅图元两类。
常见图元种类:
-
点图元
GL_POINTS -
多边形图元:
GL_TRIANGLES
GL_TRIANGLE_SRTIP
GL_TRIANGLE_FAN
GL_QUADS
GL_QUAD_STRIP
GL_POLYGON
点图元就是一个点一个点地绘制;多边形图元按照一定的顺序绘制,示意图如下:
生成图元时,我们总是希望图元好绘制一些,因此,像一些角度极小,特别尖锐的图形,在绘制系统中是不希望看到的。传统是采用三角剖分来解决。三角剖分解决的问题是:解决复杂非凸多边形的绘制问题。
相机:OpenGL中的相机默认被放置在世界坐标系的原点,指向z轴的负方向;默认的视景体是一个中心在原点,边长为2的立方体。
属性和颜色
属性:属性是OpenGL中状态的一部分,确定对象的外观,例如颜色、点的大小、线段的宽度以及虚实模式、多边形的模式。
颜色:能理解RGB即可,注意颜色的每个分量在帧缓冲区中是分开存储的。
OpenGL程序结构
为了能绘制图形,除了OpenGL,我们还需要其他的一些框架:
- 由于不同显卡公司的不同产品对OpenGL标准的实现以及OpenGL的扩展都不相同,因此需要一个能够发现并加载这些库的接口。GLEW提供了有效的运行机制,以寻找和识别用户平台所支持的全部 OpenGL 高级扩展函数。也就是说,只要包含一个 glew.h 头文件,用户就能使用以 gl、glu、glext 等开头的全部函数。
- 在使用OpenGL绘制图形前,需要先创建OpenGL运行环境和用于显示的窗口。然而,这些操作在每个系统上并不一样,OpenGL有目的地从这些操作抽象出去。这意味着用户不得不自己处理创建窗口,定义OpenGL上下文以及处理用户输入。FreeGLUT主要用来创建窗口,初始化 OpenGL 环境,管理用户鼠标、键盘的输入,使 OpenGL 程序变得简单和提升可移植性。(时下比较流行的另外一个窗口框架是GLFW)
总而言之,它们的关系可以用下面这幅图概括:
OpenGL编程概貌如下:
初始化窗口:
#include <glew.h>
#include <GL/glut.h>
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(0, 0);
glutCreateWindow("simple OpenGL example");
glewExperimental = GL_TRUE;
glewInit();
init();
glutDisplayFunc(display); // 绘制回调函数
glutMainLoop(); // 进入GLUT事件处理循环
return 0;
}
绑定数据及指定绘制方式部分:
GLuint abuffer;
glGenVertexArrays(1, &abuffer);
glBindVertexArray(abuffer);
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
绘制:
void mydisplay(void) {
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_POINTS, 0, N);
glFlush();
}
图形编程的交互
交互主要是通过键鼠交互,一般查文档就行了。一般流程是,得有一个注册了的Listener,这个Listener监听事件,如果某事件发生了就调用相应的Handler,处理相应。GLUT采用的就是事件驱动模型进行响应。
双缓冲
现代显示器的刷新频率一般在60-100Hz之间,单缓存会出现数据更新频率跟不上屏幕刷新频率,导致闪屏,采用双缓冲可以解决这个问题。双缓冲就是让写数据操作与刷新操作异步,前端缓冲直接与显示设备交互,后端缓冲存储需要显示的内容。
总结:图形绘制系统的任务流水线
更多推荐
所有评论(0)