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

 

现在更新一下网上流传的OpenGL中文教程网站,看起来比红宝书和蓝宝书好

opengl-tutorial中文教程,也就是nehe的新教程,用的glfw+glew

http://www.opengl-tutorial.org/cn/beginners-tutorials/ 

learnopengl中文教程,用的glfw+glad

https://learnopengl-cn.github.io/

 

不过这两个教程其实我都不喜欢,还是喜欢

《交互式计算机图形学 基于OpenGL着色器的自顶向下方法 (第六版)》

用的最传统的glut+glew,深得我心。

不过初学者的话,如果追求最新最酷炫的学习体验的话,还是看网上的教程算了,如果是学术型的,想再理论性地学习一下计算机图形学的话,那么这本书也是非常好的学术性基础书。

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值