下面我们来具体讲解,代码如下: 首先来看第一句,glMatrixModel()函数。这个函数其实就是对接下来要做什么进行一下声明,也就是在要做下一步之前告诉计算机我要对“什么”进行操作了,这个“什么”在glMatrixMode的“()”里的选项(参数)有3种模式: GL_PROJECTION 投影, GL_MODELVIEW 模型视图, GL_TEXTURE 纹理. 这里我们要做的是对模型视图的改变,所以参数是GL_MODELVIEW。待会儿我们再讲剩下的两个。

看下glTranslatef(), glRotatef()和glScalef()这三个函数。三个函数都末尾带有f,所以参数都是GLfloat型,也有末尾改成d的,参数就是GLdouble型。

首先glTranslatef()函数,三个参数的意思是沿着x,y,z轴平移的分量。

glRotatef()函数,第一个参数为旋转角度,后面三个参数表示沿着从(0,0,0)到(x,y,z)的向量方向旋转。再明确一点其实就是,x,y,z表达的意思并不是坐标点,而是要围绕哪个坐标轴旋转。还记得刚刚的右手法则吗?从坐标(0,0,0)即原点,引出一条线到(x,y,z),用右手握住这条线。假设xyz为(1,0,0),右手大拇指指向(0,0,0)至(1,0,0)的方向才握。另外四个手指的弯曲指向即是物体旋转方向。为什么是右手握住,而不是左手呢?因为OpenGL遵循的是右手法则。到这儿你就理解我为什么先给各位说坐标系和右手法则的事情了,如果刚刚你没认真看,现在看一下,再理解这一段。

最后一个glScalef(),三个参数就是x,y,z轴放大缩小的倍数。

重点是执行顺序问题,顺序是按照由下至上的顺序来的,也就是代码图中123的顺序来的。顺序看似是没有区别的,事实上区别很大。

看这个例子就知道为什么顺序会影响最终绘制结果了: 现在为止讲完第一个glMatrixModel(GL_MODELVIEW)。下一个就是glMatrixModel(GL_PROJECTION)。如果参数是GL_PROJECTION,这个是投影的意思,就是要对投影相关进行操作,进行投影变换,也就是把物体投影到一个平面上,就像我们照相一样,把3维物体投到2维的平面上。这样,接下来的语句可以是跟透视相关的函数。

我们这里介绍两个函数:

glOrtho( xl, xr, yb, yt, zn, zf );

gluPerspective( fovy, aspect, zn, zf );

第一个函数glOrtho是正交投影或平行投影,第二个gluPerspective是透视投影。

先说第一个glOrtho。创建一个平行视景体(就是一个长方体空间区域)。实际上这个函数的操作是创建一个正射投影矩阵,并且用这个矩阵乘以当前矩阵。只有在视景体里的物体才能显示出来,最后两个参数改成0,0后,视景体深度没有了,整个视景体都被压成个平面了,当然就显示不正确了。

第二个函数gluPerspective。创建一个表示对称透视视图平截头体的矩阵,并把它与当前矩阵相乘。fovy是YZ平面上视野的角度,范围0-180°。好的取值范围一般是50-100°。aspect是这个平截头体的纵横比,也就是宽度除于高度。near和far值分别是观察点与近侧裁剪平面以及远侧裁剪平面的距离(沿Z轴负方向)这两个值都是正的。 到此讲完第二个glMatrixModel(GL_PROJECTION)。第三个GL_TEXTURE暂时各位先记着,等讲到纹理时再详细阐述。

代码现在可以扩充成以下代码了: 现在也就是已经做过模型变换,投影变换了,还缺视变换和视口变换。下面我们就来做这两组变换。

介绍一个函数:

gluLookAt( ex, ey, ez, lx, ly, lz, ux, uy, uz );

这个函数第一组eyex, eyey,eyez 相机在世界坐标的位置,第二组centerx,centery,centerz 相机镜头对准的物体在世界坐标的位置,第三组upx,upy,upz 相机向上的方向在世界坐标中的方向。你把相机想象成为你自己的脑袋:第一组数据就是脑袋的位置,第二组数据就是眼睛看的物体的位置,第三组就是头顶朝向的方向(因为你可以歪着头看同一个物体)。这个就是进行视变换的。

再介绍一个函数:

glViewport( ixl, iyb, idx, idy );

调用glViewPort函数来决定视见区域,告诉OpenGL应把渲染之后的图形绘制在窗体的哪个部位。当视见区域是整个窗体时,OpenGL将把渲染结果绘制到整个窗口。这个函数进行视口变换。

这个函数前两个函数是指定视口的左下角位置的,一般为0,0。WindowsGDI中的窗口坐标(0,0)是左上角,而OpenGL所定义的(0,0)是左下角。所以这个函数在这个图中是定义左上角的。后两个参数就是宽度和高度。

这一节结束前再介绍一组有用的函数:

glPushMatrix()和glPopmatirx()

假设我们想要绘制太阳系,中间是太阳,静止不动,地球围绕太阳旋转,月亮围绕地球旋转。

我们首先将坐标系移动到太阳的位置,绘制太阳,再将坐标系移动到地球的位置,绘制地球,然后将坐标系移动到月亮的位置,绘制月亮;如果还有金星、木星、火星呢,他们也都是以太阳为中心旋转,这样子,我们可以绘制完月亮之后再将坐标系回退到绘制地球的时候的坐标系,移动相应的位置,绘制金星,然后再回退或者移动新位置绘制木星。这样的操作不但麻烦,而且容易出错。

那怎么办最好呢,其实就是绘制地球、金星、木星、火星等的时候以太阳为坐标原点,在绘制地球之前先把当前的模型视图矩阵压入堆栈中保存下来(glPushMatirx),这样你在进行变换就不会影响到堆栈中的矩阵,这个时候将坐标系移动到地球的位置绘制地球,绘制完成之后将模型视图矩阵堆栈中的栈顶矩阵(就是我们刚才保存的矩阵)弹出(glPopMatrix),恢复原来的坐标系,再压入堆栈,绘制金星,再弹出。

基本上这一讲已经结束了。各位对OpenGL该有个了大致的思路,并且也想尝试些一些代码了吧。那就动手吧,下期我会将我的github放出来,供大家看一些示例代码。

最后放出一些和本讲有关的,但不影响大家学习OpenGL的小知识,有兴趣的了解下,没兴趣的略过吧。

你只知道有红绿蓝三个颜色叠加出别的颜色,所以glcolor参数是rgb。不知道还可以由白光通过减法减出各种颜色吧。

在管线技术流程图里,提到个名词叫光栅化,可能很多人不明白。光栅化就是把顶点数据转换为片元的过程。片元中的每一个元素对应于帧缓冲区中的一个像素。那么顶点怎么转换为片元的呢?如下图,英语好的自己看吧:

对于fragment processing,在学习了shader之后,你会更加了解通过shader你做了很多你自己的fragment processing。