NeHe OpenGL教程 第五课 3D图形

来源:互联网 发布:潭州教育python网盘 编辑:程序博客网 时间:2024/04/30 14:02

扩展上一节课的代码,这一节课我们将在3D空间中创建一个真实的3D对象。我们会在上节课的三角形上添加左,右和背面三个面,在正方形上添加左,右,上,下和背面。这样,三角形会形成一个金字塔,而正方形会形成一个立方体。我们会混合金字塔的颜色,形成一个平滑着色的物体;而对于立方体,我们会在每个面上涂上不同的颜色。

int DrawGLScene(GLvoid)     // 我们绘制图形的地方
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除颜色和深度缓存
    glLoadIdentity();                   // 重置模型视图矩阵
    glTranslatef(-1.5f,0.0f,-6.0f);       // 向左移动1.5个单位,向屏幕里移动6.0个单位
 
    glRotatef(rtri,0.0f,1.0f,0.0f);       // 沿y轴旋转金字塔
 
    glBegin(GL_TRIANGLES);       //绘制金字塔

有些人可能早已在上节课中的代码上尝试自行创建3D对象了。我经常会被问道的一个问题是“我的对象怎么不会绕着其自身的轴旋转?看起来总是在满屏乱转。”为了让你的物体绕着一个轴旋转,你必须控制它让他在那个轴上旋转。(原文:One thing I've been asked quite a bit is "how come my objects are not spinning on their axis? It seems like they are spinning all over the screen". In order for your object to spin around an axis, it has to be designed AROUND that axis. )你必须牢记任何物体的中心点必须在(0.0f,0.0f,0.0f)上。

下面的代码将在中心轴的周围创建一个金字塔。(它是具有前,后,左,右加上底面五个面的立体图形,我们绘制了前,后,左,右四个侧面,想象一下金字塔的样子。)金字塔的最上面高于中心点一个单位,金字塔的最下面低于中心点一个单位。金字塔的顶点正好在y轴上(0.0f,1.0f,0.0f),最下面的顶点要么离中心点左边一个单位,要么离中心点右边一个单位。

注意,所有的三角形都是逆时针绘制的。这很重要,我们将会在后面的教程中做解释,现在,只要知道要么以顺时针顺序绘制,要么以逆时针顺序绘制,但是,不要混用这两种绘制顺序,除非你有必要那么做。

我们首先绘制金字塔的正面。因为所有面都用到了上顶点,我们把所有三角形的这个点设置为红色。三角形底部的两个点的颜色是交替的。(原文:The color on the bottom two points of the triangles will alternate. )在金字塔的正面,左下顶点是绿色的,右下顶点是蓝色的。然后,金字塔右面的三角形,左下顶点是蓝色的,右下顶点是绿色的。通过交替每个面的底部两个顶点的颜色,我们可以保证底部每个面相交的顶点的颜色相同。(原文:By alternating the bottom two colors on each face, we make a common colored point at the bottom of each face.)

glColor3f(1.0f,0.0f,0.0f);          // 红色
glVertex3f( 0.0f, 1.0f, 0.0f);          // 顶点 (正面)
glColor3f(0.0f,1.0f,0.0f);          // 绿色
glVertex3f(-1.0f,-1.0f, 1.0f);          // 左下顶点 (正面)
glColor3f(0.0f,0.0f,1.0f);          // 蓝色
glVertex3f( 1.0f,-1.0f, 1.0f);          // 右下顶点(正面)

然后,我们绘制金字塔的右面。注意其底边上的两个顶点的X坐标位于中心点右侧的一个单位处。顶点则位于y轴(0.0f,1.0f,0.0f)上,右侧面从上顶点开始向外侧倾斜至底边上。

注意,左下顶点这次绘制成蓝色。这样,它就和正面的右下顶点是同一颜色。蓝色将从这个角向金字塔的正面和右侧面扩展并与其他颜色混合。

注意,剩下的三个面和正面的绘制都是在同一个glBegin(GL_TRIANGLES) 和 glEnd() 之间的。因为我们绘制的所有物体都是三角形,所以OpenGL以每三个点为一组来绘制三角形。一旦绘制完三个点,如果还有三个点,就绘制另一个三角形。如果还剩下四个点,OpenGL会先用前三个点绘制一个三角形,会把第四个点认为是一个新的三角形的第一个点。而不会绘制一个正方形。所以,确认你没有意外地添加多余的点。

glColor3f(1.0f,0.0f,0.0f);          // 红色
glVertex3f( 0.0f, 1.0f, 0.0f);          // 顶点 (右侧面)
glColor3f(0.0f,0.0f,1.0f);          // 蓝色
glVertex3f( 1.0f,-1.0f, 1.0f);          //左下顶点(右侧面)
glColor3f(0.0f,1.0f,0.0f);          // 绿色
glVertex3f( 1.0f,-1.0f, -1.0f);         // 右下顶点 (右侧面)

然后绘制背面。再一次交换颜色。左下顶点这次又是绿色,因为它和右侧面共用的那个顶角是绿色的。

glColor3f(1.0f,0.0f,0.0f);          // 红色
glVertex3f( 0.0f, 1.0f, 0.0f);          // 顶点 (背面)
glColor3f(0.0f,1.0f,0.0f);          // 绿色
glVertex3f( 1.0f,-1.0f, -1.0f);         //左下顶点 (背面)
glColor3f(0.0f,0.0f,1.0f);          // 蓝色
glVertex3f(-1.0f,-1.0f, -1.0f);         // 右下顶点 (背面)

最后,我们绘制左侧面。颜色再交换一次。左下顶点是蓝色,和背面的右下顶点混合。右下顶点是绿色,和正面的左下顶点混合。金字塔绘制完成。因为金字塔只是沿y轴旋转,我们看不见底面,所以没有必要绘制底面。如果你想尝试以下,可以试着给金字塔加一个正方形的底面,然后沿x轴旋转,看看是否正确地添加了底面。确保正方形的四个角的颜色和金字塔的底面四个角的颜色匹配上。

    glColor3f(1.0f,0.0f,0.0f);          // 红色
    glVertex3f( 0.0f, 1.0f, 0.0f);        // 顶点 (左侧面)
    glColor3f(0.0f,0.0f,1.0f);          // 蓝色
    glVertex3f(-1.0f,-1.0f,-1.0f);          // 左下顶点 (左侧面)
    glColor3f(0.0f,1.0f,0.0f);          // 绿色
    glVertex3f(-1.0f,-1.0f, 1.0f);          // 右下顶点(左侧面)
glEnd();                        // 金字塔绘制完成

然后我们绘制正方体。它由六个正方形构成。所有的正方形都以逆时针顺序绘制。意味着,我们先绘制右上顶点,第二个绘制左上顶点,第三个绘制左下顶点,最后绘制右下顶点。当我们绘制正方体的背面时,看起来好像是以顺时针的顺序绘制的,但是你必须牢记,如果我们从背面观察正方体,屏幕的左边实际上是正方形的右边,而屏幕的右边实际上是正方形的左边。

注意,在这一课中,我们把正方体移进屏幕更深了一点。之所以这么做,是为了让正方体的尺寸看起来更接近金字塔的尺寸。如果你只是把正方体移进屏幕6个单位,正方体看起来会比金字塔大得多,正方体的一部分可能会被屏幕的边界截断。你可以尝试这种设置,来观察当正方体移进屏幕越深,看起来会越小,移入屏幕越浅,看起来越大。这就是透视的效果。物体的距离越远,看起来越小。

glLoadIdentity();
glTranslatef(1.5f,0.0f,-7.0f);    //右移并且移入屏幕
 
glRotatef(rquad,1.0f,1.0f,1.0f);       // 让正方体沿x,y,z轴旋转
 
glBegin(GL_QUADS);   //开始绘制正方体

我们从正方体的顶面开始绘制。我们相对于正方体的中心向上移动一个单位。注意,在y轴上的位置永远都是1.0。我们将绘制一个与z平面平行的正方形。意思是说,它在z平面里。(原文:We then draw a quad on the Z plane. Meaning into the screen. )我们首先绘制正方体顶面的右上顶点。右上顶点应该是在(1.0f,1.0f,-1.0f)处。第二个点应该在(-1.0f, 1.0f,-1.0f)处。然后我们绘制正方形朝向观察者的底边。为了实现这个效果,我们不是把顶点移入屏幕,相反,我们把顶点移除屏幕一个单位。

glColor3f(0.0f,1.0f,0.0f);          // 绿色
glVertex3f( 1.0f, 1.0f,-1.0f);          // 右上顶点 (顶面)
glVertex3f(-1.0f, 1.0f,-1.0f);          // 左上顶点 (顶面)
glVertex3f(-1.0f, 1.0f, 1.0f);          // 左下顶点 (顶面)
glVertex3f( 1.0f, 1.0f, 1.0f);          // 右下顶点(顶面)

底面的绘制和顶面是类似的,但是由于它是底面,所以我们要相对于正方体的中心向下移动一个单位。注意,在y轴上的位置永远都是-1.0。如果我们在正方体的底部,观察底面的正方形,你会注意到正方形的右上顶点是最接近观察者的,所以,我们不是从远处开始绘制,而是从最接近观察者的右上顶点开始绘制,然后是左上顶点,最后绘制其余的底边的两个顶点。

如果你真的不关心多边形的绘制顺序(顺时针还是逆时针),你可以从顶面的绘制那里把代码拷贝过来,然后把y轴的值改为-1.0,就可以了,但是如果忽略了正方形的绘制顺序,可能会产生意想不到的效果,例如使用纹理映射。

glColor3f(1.0f,0.5f,0.0f);          // 桔黄色
glVertex3f( 1.0f,-1.0f, 1.0f);      // 右上顶点 (底面)
glVertex3f(-1.0f,-1.0f, 1.0f);          // 左上顶点 (底面)
glVertex3f(-1.0f,-1.0f,-1.0f);          // 左下顶点 (底面)
glVertex3f( 1.0f,-1.0f,-1.0f);          // 右下顶点 (底面)

接下来,我们绘制正方体的正面。我们相对于正方体的中心移出一个单位来绘制正面。注意,在z轴上的位置永远是1.0。在金字塔中,z轴上的值不总是1.0。在上顶点,z轴的值等于0.0。如果你在下面的代码中尝试把z的值变成0.0,你会注意到,你改变的那个角将会倾斜入屏幕。这不是我们现在想要的效果。

glColor3f(1.0f,0.0f,0.0f);          // 红色
glVertex3f( 1.0f, 1.0f, 1.0f);          // 右上顶点 (正面)
glVertex3f(-1.0f, 1.0f, 1.0f);          // 左上顶点 (正面)
glVertex3f(-1.0f,-1.0f, 1.0f);          // 左下顶点 (正面)
glVertex3f( 1.0f,-1.0f, 1.0f);          // 右下顶点 (正面)

正方体的背面的绘制类似于正面的绘制,但是它相对于正方体的中心移入屏幕一个单位。注意,所有点的z值都是-1.0。

glColor3f(1.0f,1.0f,0.0f);          // 黄色
glVertex3f( 1.0f,-1.0f,-1.0f);          // 左下顶点 (背面)
glVertex3f(-1.0f,-1.0f,-1.0f);          //右下顶点 (背面)
glVertex3f(-1.0f, 1.0f,-1.0f);          // 右上顶点(背面)
glVertex3f( 1.0f, 1.0f,-1.0f);          // 左上顶点 (背面)

现在,我们还有两个正方形需要绘制,来组成正方体。通常,你会注意到一个面上的点总有一个轴上的值是固定的。在正方体的左侧面上,所有的x轴上的值都是-1.0。这是因为我们总是在正方体中心的左侧来绘制左侧面。

glColor3f(0.0f,0.0f,1.0f);          // 蓝色
glVertex3f(-1.0f, 1.0f, 1.0f);          // 右上顶点 (左侧面)
glVertex3f(-1.0f, 1.0f,-1.0f);          // 左上顶点 (左侧面)
glVertex3f(-1.0f,-1.0f,-1.0f);          // 左下顶点(左侧面)
glVertex3f(-1.0f,-1.0f, 1.0f);          // 右上顶点 (左侧面)

剩下最后一个面,我们就完成正方体的绘制了。x轴上的值永远都是1.0。以逆时针顺序绘制。如果你想尝试以下,可以不绘制这个面,那么绘制成的就是一个箱子。

或者如果你想尝试,你可以给每个顶点设置不同的颜色,让后让它们混合,就像金字塔那样。

        glColor3f(1.0f,0.0f,1.0f);          // 紫色
        glVertex3f( 1.0f, 1.0f,-1.0f);          // 右上顶点(右侧面)
        glVertex3f( 1.0f, 1.0f, 1.0f);          // 左上顶点(右侧面)
        glVertex3f( 1.0f,-1.0f, 1.0f);          // 左下顶点 (右侧面)
        glVertex3f( 1.0f,-1.0f,-1.0f);          // 右上顶点(右侧面)
    glEnd();                        // 完成正方体绘制
 
    rtri+=0.2f;                     // 增加金字塔的旋转角度
    rquad-=0.15f;                       // 减少正方体的旋转角度
    return TRUE;                       
}

这节课的最后,你应该已经很好地理解了在3D空间中如何创建对象。你应该把OpenGL屏幕想象成一张巨大的图纸,在它的后面有很多透明的层。就像一个巨大的正方体是由很多个点组成的一样。一些点在左边,一些点在右边,一些点在上边,一些点在下边,一些点在正方体的远端。如果你能想象到屏幕里的深度,那么你可以绘制任何的3D对象。

如果你还不是很理解3D空间,也不要灰心。刚开始正确理解这些确实很难。正方体是学习这些东西的一个很好的例子。如果你注意到了,正方体背面的绘制和正面的绘制是完全一样的,只是背面是移入屏幕里面绘制的。

原创粉丝点击