OpenGL固定管线与可编程管线对比

很久没碰OpenGL了,因为之前看过《交互式计算机图形学 基于OpenGL着色器的自顶向下方法(第6版) 》(后面简称《图》),觉得自己已经掌握了OpenGL基础,而且红宝书第8版写得太文绉绉了,又厚,像本工具书,当时也没有急用OpenGL编程,因此也没想看下去。

到了现在,我遇到了某些项目,发觉自己的OpenGL基础还是太贫乏了,用压箱底的知识貌似也无法写一些有用的程序。而且看到现在网上有些有用的程序还是用的OpenGL旧管线,我竟然看不懂。其实本来我是想对比一下新旧管线之间的差异,然后把网上的旧管线程序移植到新管线程序中的,可是苦于当时找不到相同功能下新旧管线的代码,因此就搁置了很久。而且我也不想看旧的红宝书,还那么厚。

以前听说网上有一个OpenGL的入门教程,简单易懂,叫nehe,于是我就搜了一下。但是发现nehe的教程是2000年的古老教程,也用的旧管线,一看,纳闷了,竟然用的Windows窗口编程。我是学过MFC的,知道MFC非常恶心,于是没有看下去的欲望了。

而现在,我随意翻了翻,发现了原来nehe更新了教程

http://nehe.gamedev.net/news/new_opengl_tutorial_site/88001/

http://www.opengl-tutorial.org/download/

而且用的新的管线,好了,那就精彩了,可以把nehe的新旧例子做一个对比,就能知道怎么移植了。然而非常坑爹的是,nehe不知为什么很不喜欢glut,在新旧例子里面,宁愿把代码复杂化也不用glut,我也是呵呵了。

Nehe的旧例子用Windows窗口,新例子用glfw,就是不用glut。明明glut最简洁,明明红宝书新旧版和《图》用的也是glut,业界普遍认同的常用工具啊,为什么就不用呢?我也是醉了。

Nehe的新旧例子代码可以从我这里下载

链接:http://pan.baidu.com/s/1o8ySMng密码:hrcy

好了,现在可以对比一下OpenGL的新旧管线究竟有什么不同(分别与glut新管线编程对比)。

Nehe的旧版例子使用Windows窗口,自创了三个函数ReSizeGLScene,InitGL,DrawGLScene。还是比较符合OpenGL的编程规范的(无论是新旧管线都有这三个老面孔函数)。

ReSizeGLScene会在处理函数WndProc中调用。

InitGL会在CreatGLWindow窗口中调用

DrawGLScene会在WinMain最后的自创死循环中调用

Windows窗口能使用OpenGL在于在CreateWindowEx函数中设置了PFD_SUPPORT_OPENGL

而新版的glut例子就非常简洁

ReSizeGLScene通常对应的是自创函数reshape,有现成的回调函数注册glutReshapeFunc《图》P73

InitGL通常对应的是自创函数init

DrawGLScene通常对应的是自创函数display,有现成的回调函数注册glutDisplayFunc《图》P58

在InitGL中,glClearColor《图》P51,glEnable(GL_DEPTH_TEST)在新版本的init都是有保留的,其余都会通过手动编写模视矩阵和着色器代码来替代。

新版本的init的处理流程都是先准备好顶点、颜色、纹理等数据,创建GPU缓存,然后把数据管线装配到GPU缓存中。

在DrawGLScene中,glClear《图》P60在新版本的display中是有保留的。在旧管线中,比较有标志性的是函数glLoadIdentity,表示模视矩阵重置为单位矩阵,这表示摄像机坐标系与世界坐标系重合。在OpenGL中,摄像机坐标系的Z轴方向是屏幕朝外的,因此我们将会看到重置后是一个XOY坐标系。而在新版本的的display中,模视矩阵是要自己编写的,因此glLoadIdentity也不复存在了。

在DrawGLScene中,比较多见的还有

glTranslatef(…);

glRotatef(…);

glBegin(…);

glColor3f(…);

glVertex3f(…);

glEnd();

操作大概是,先移动和旋转屏幕,然后在屏幕坐标系绘制图形。

第一步其实修改了视图矩阵,第二步定义了对象在摄像机坐标系下的坐标并绘图。

其实就是创建了一个模视矩阵,顶点、颜色数据,并绘图。在新版的display中,通常是自己编写模视矩阵,然后调用glDrawArrays《图》P41绘图。顶点,颜色数据在init中就已经准备好并发送到GPU了。

在旧的管线编程中,还会用

glMatrixMode(GL_PROJECTION);

gluPespective(…);

进入投影矩阵设置模式并具体设置投影矩阵

glMatrixMode(GL_MODELVIEW)

LookAt(…);

进入模视矩阵设置模式并具体设置模视矩阵

这些函数都是OpenGL旧管线自动提供的。而新版OpenGL管线的投影矩阵和模式矩阵都是自己编写,并调用glUniformMatrix4fv函数发送到着色器的自创矩阵变量中,因为都是纯手动,所以就不用进入具体的矩阵设置模式了。这些操作通常会在display函数中进行。

下面对比一下glut和glfw

我也不知道nehe新版本为什么要用glfw,感觉还是比glut麻烦多了。而且nehe也没有对流程进行函数分块。

然而一个意外的收获是,nehe让我知道了glm这个工具,这个工具可以自动创建模视矩阵和投影矩阵(就像固定管线一样),就方便多了,不用自己写矩阵了。

Glut在main函数中会调用glutInitDisplayMode设置显示模式《图》P56,但glfw没有。

Glut的glutInit对应glfw的glfwInit

Glut的glutInitWindowSize和CreateWindow对应glfw的glfwCreateWindow

Glut的glutInitContextVersion(3,3)对应glfw的

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3);

glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,3);

glut的glutInitContextProfile(GLUT_CORE_PROFILE )对应glfw的

glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);

然后都调用glewInit

然后就是初始化流程,和进行循环绘制了。

Glut的循环绘制调用glutMainLoop就可以了,glfw还要自己手动创建循环。比较费解的是,nehe还要在循环中调用glUseProgram和启用顶点数组对象并发送数据(这个通常在init中进行的),绘制完还要取消顶点数组对象。

最后手动回收缓存、顶点数组对象和程序ID,这个在glut都不用做。

总结

不过总的来说,有nehe这些例子还是难能可贵的,例子的简单易懂是它最重要的价值。有某些功能我都不知道在OpenGL怎么实现,我也不想查红宝书(不知道在哪一页查),那么看nehe怎么实现那就快速得多了,遇到不懂的函数就查红宝书就行了。

下面讲一下纹理

在新版OpenGL管线中,流程是

glGenTexture 创建纹理对象

glBindTexture 绑定纹理对象

glTexImage2D 和纹理图像(颜色矩阵)数据连接

glTexParameterf 设置纹理参数

glActiveTexture(GL_TEXTURE0)  设置纹理对应采样器为0号采样器

glBindTexture 绑定纹理对象

创建顶点坐标数据和顶点对应的纹理坐标数据

在片元着色器中创建采样器

使用glUniform1i把0号采样器赋给片元着色器中的采样器

片元着色器中调用texture2D(texture,texCoord),使采样器获得纹理坐标下纹理的颜色

在nehe中,有自创的loadDDS函数加载DDS图片,该函数把图片转换成unsignedchar* 缓存数组buffer,并调用glCompressedTexImage2D,使纹理对象和压缩纹理图像数据连接

并调用glGenTexture 和glBindTexture 

返回纹理对象

然后创建顶点坐标数据和顶点对应的纹理坐标数据

在片元着色器中创建采样器

glActiveTexture(GL_TEXTURE0)设置纹理对应采样器为0号采样器

glBindTexture 绑定纹理对象

glUniform1i把0号采样器赋给片元着色器中的采样器

片元着色器中调用texture2D(texture,texCoord),使采样器获得纹理坐标下纹理的颜色

texture(myTextureSampler, UV ).rgb使采样器获得纹理坐标下纹理的颜色

在旧版OpenGL管线中,流程是

LoadBMP把图片转换成AUX_RGBImageRec类型的数组

glGenTexture 创建纹理对象

glBindTexture 绑定纹理对象

glTexImage2D 和纹理图像(颜色矩阵)数据连接

glTexParameteri绑定纹理对象

glEnable(GL_TEXTURE_2D)开启纹理映射

在绘制循环中

glBegin(…);

    glTexCoord2f(…);

glVertex3f(…);

    …

glEnd();

创建纹理坐标和对应的顶点坐标

最后推荐一下OpenGL可编程管线的拾取程序,因为我在红宝书找不到例子

http://www.lighthouse3d.com/tutorials/opengl-selection-tutorial/

我作了一下修改(按http://blog.csdn.net/outtt/article/details/51277481的配置可运行)

链接:http://pan.baidu.com/s/1nvE3Xw9密码:s6w2

发布了12 篇原创文章 · 获赞 17 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/outtt/article/details/73251775