OpenGL学习笔记(八)

龙云尧个人博客,转载请注明出处。

CSDN地址:http://blog.csdn.net/michael753951/article/details/71702311

个人blog地址:http://yaoyl.cn/nehexue-xi-bi-ji-ba/


前言

本部分单独讲Lesson10的内容,本次讲述重点将不再是作者在代码中各种方法如何如何调用,比如如何实现旋转,如何绘制图像,如何实现透明,如何实现步进等等,这个在我前面7篇笔记中已经有详细的说明了,本篇笔记将不再重复,如果有什么疑问可以翻我之前的笔记或者上网查询。

本次实验参变量不少,作者通过代码带我们真正的实现了一个3D世界,我们可以在这个3D世界里面自由的走动和观察。(也是我们玩的譬如《我的世界》这样的第一视角游戏的世界构建的基本)

文中给出了几个数据结构——tagVERTEX,tagTRIANGLE,tagSECTOR。vertex用来存放每一个坐标点的空间直角坐标系中的位置(x, y, z)和需要展示的图像的位置(u, v),trandgle表示三角形中存在的3个点,包含3个tagVERTEX(事实上,现今大多数人都是用无数这样的三角形来近似/逼近一个曲面),然后sector表示一个由许多三角形构成的体的结构。文中,所有的与体相关的三角形都放在一个文件中,通过读写文件来对体进行操作。

代码分析

好了,大致的介绍已经完成,我们接着看看作者是如何一步一步完成这个3D世界的建设的。(晚上课程中已经解释的地方我这里不再重复,而还未解释清楚的地方我将重点解释)

作者首先定义了一个readstr方法,用来读取文件f中的内容,将其读进string指向的内存空间。接着定义了一个SetupWorld方法,将”data/world.txt”中的内容调用readstr方法读取内容,并将其写进 tagSECTOR 类的变量 sector1 中,关于txt中数据格式需要在这里说明一下——每一行代表一个坐标点的信息,包含5个变量,分别为该点的x轴坐标、y轴坐标、z轴坐标、该点对应的渲染图片的点的x坐标,该点对应的渲染图片的点的y坐标。每3行(即3个点)构成一个3角形。前3个变量各位可能还有印象,后两个点可以回去看看《nehe学习笔记(五)》,找找glTexCoord2f方法的说明。

然后是和以前一样的LoadBMP以及LoadGLTextures方法。InitGL方法中,打开纹理映射和深度测试,同时调用之前定义好的SetupWorld方法读入所有三角形的信息。

接下来就是第一个重头戏DrawGLScene了,所有的动作都是在这里展示出来的,理解这一块的知识对我们将来自己构建3D世界有莫大的帮助。

该部分首先定义了5个浮点数x_m, y_m, z_m, u_m, v_m,分别用来对应tagVERTEX中的5个5种元素。使用xtrans & ytrans & ztrans 分别表示画笔起笔处的x坐标 & y坐标 & z坐标(也就是说在glTranslatef中将被用到。),接着定义了xtrans & ztrans & ytrans,这三个值决定了画笔起点沿X轴、Y轴、Z轴移动的长度,也即决定了画笔的起点位置(也即整张地图的位置),sceneroty则据定了角色的视觉角度。

变量中我们需要注意,本次实验中,沿着某轴移动的长度通常以 pos 结尾作为变量,而旋转的角度通常以 ros 结尾作为变量,谨记这一点对我们后期按键控制的理解会有帮助。

接着作者调用两次glRotatef,先将图像沿着x轴旋转一定角度(lookupdown),完成抬头动作,再将图像沿着y轴旋转一定角度(sceneroty),完成正面朝向的转换。

现在我们已经确定了抬头角度和视角,接下来就要设定你现在所处的位置了——其实就是反方向移动整个3D模型即可,这也就是为什么在trans赋值的时候,会取负数的原因。

在上一步骤调用glTranslatef已经绘点结束之后,我们将开始进行图像绘制,这个部分就不细说了。我对文本中前3行(第一个三角形)标稍作图解,剩下的你可以自己尝试继续绘制。

坐标系

到这一步,绘制完成,接下来的KillGLWindow以及CreateGLWindow以及WndProc和之前一致,不解释。

第二个重头戏来了,WinMain。这个部分我们将实现通过按键控制你在整个3D世界中的游荡(其实是在控制整个3D世界移动)。下面我将仔细解释。

B键设置透明,这个之前笔记解释过,记得disable深度测试,然后enable透明。F键设置画质,不解释了。

接下来是按up键,这个时候首先会更改xpos和zpos,为什么会如此修改,期初我也很疑惑,不过在画了一张图解之后,便豁然开朗了。我们根据代码可以知道heading这个变量代表了你当前正脸朝向与Z轴正向的角度(因为heading赋值给了yrot,而yrot是绕着y轴旋转的角度,所以heading就是你转身的角度啦)。

通过下图我们便可以知道为什么使用UP键向前走的时候,作者使用如下两行代码实现移动了。

up&down

1
2
xpos -= (float)sin(heading*piover180) * 0.05f;
zpos -= (float)cos(heading*piover180) * 0.05f;

接着作者在pos变换完成以后,稍稍微修改walkbias变量,它将影响到ypos,从而模仿人行走的时候的高低起伏,让人更加自然。

接下来的 left, right, page_up & page_down 按键的反馈设置就基本不用解释啦,你按照右手定则稍稍为跟着做一下就能够理解啦。需要注意的是,在WinMain中,所有的pos和trans都是从观察者的角度进行变换的,真正的变换是在DrawGLScene,在DrawGLScene方法中我们已经对数据做了特殊处理以保证显示正常自然。

好了,到这里本章节的代码也就解释完毕了,粗读代码会觉得很容易,因为都是我们之前已经掌握的内容,但是细想作者是如何一步一步具体实现的时候,情况就会复杂很多。通过不断画图和翻以前的代码,我才不断的深入理解整个OpenGL的原理,以及3D模型的构建原理和过程。至此,OpenGL应该算是正式入门了吧。

稍稍留一个小问题,你知道为什么作者在DrawGLScene方法中,xtrans直接赋值为xpos的负值,ztrans同样直接赋值为zpos的负值,sceneroty也是直接取了yrot的负值(不过为了严谨,又添了一个360作为进位),偏偏ytrans要在赋值为walkbias的负值之后,还要减去一个0.25呢?(提示,walkbias乘上sin之后有正有负,如果不添加一个常数,你的“眼睛”就会在地板所在的y=0面上不断上下抖动,而添加0.25之后,则是将你的“眼睛”提高到了一定的高度,让你有了身高的感觉,从而更加自然)

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

请我喝杯咖啡吧~

支付宝
微信