首页 > 其他 > 详细

第07课 OpenGL 光照和键盘(2)

时间:2014-10-05 15:38:08      阅读:425      评论:0      收藏:0      [点我收藏+]

下一段代码绘制贴图立方体。我只对新增的代码进行注解。如果您对没有注解的代码有疑问,回头看看第六课。

int DrawGLScene(GLvoid)                                // 从这里开始进行所有的绘制
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);            // 清除屏幕和深度缓存

    glLoadIdentity();                            // 重置当前的模型观察矩阵

下三行代码放置并旋转贴图立方体。glTranslatef(0.0f,0.0f,z)将立方体沿着Z轴移动Z单位。glRotatef(xrot,1.0f,0.0f,0.0f)将立方体绕X轴旋转xrot。glRotatef(yrot,0.0f,1.0f,0.0f)将立方体绕Y轴旋转yrot。

    glTranslatef(0.0f,0.0f,z);                        // 移入/移出屏幕 z 个单位

    glRotatef(xrot,1.0f,0.0f,0.0f);                        // 绕X轴旋转

    glRotatef(yrot,0.0f,1.0f,0.0f);                        // 绕Y轴旋转

下一行与我们在第六课中的类似。有所不同的是,这次我们绑定的纹理是texture[filter],而不是上一课中的texture[0]。任何时候,我们按下F键,filter 的值就会增加。如果这个数值大于2,变量filter 将被重置为0。程序初始时,变量filter 的值也将设为0。使用变量filter 我们就可以选择三种纹理中的任意一种。

    glBindTexture(GL_TEXTURE_2D, texture[filter]);                // 选择由filter决定的纹理

    glBegin(GL_QUADS);                            // 开始绘制四边形

glNormal3f是这一课的新东西。Normal就是法线的意思,所谓法线是指经过面(多边形)上的一点且垂直于这个面(多边形)的直线。使用光源的时候必须指定一条法线。法线告诉OpenGL这个多边形的朝向,并指明多边形的正面和背面。如果没有指定法线,什么怪事情都可能发生:不该照亮的面被照亮了,多边形的背面也被照亮....。对了,法线应该指向多边形的外侧。

看着木箱的前面您会注意到法线与Z轴正向同向。这意味着法线正指向观察者-您自己。这正是我们所希望的。对于木箱的背面,也正如我们所要的,法线背对着观察者。如果立方体沿着X或Y轴转个180度的话,前侧面的法线仍然朝着观察者,背面的法线也还是背对着观察者。换句话说,不管是哪个面,只要它朝着观察者这个面的法线就指向观察者。由于光源紧邻观察者,任何时候法线对着观察者时,这个面就会被照亮。并且法线越朝着光源,就显得越亮一些。如果您把观察点放到立方体内部,你就会法线里面一片漆黑。因为法线是向外指的。如果立方体内部没有光源的话,当然是一片漆黑。

        // 前侧面
        glNormal3f( 0.0f, 0.0f, 1.0f);                    // 法线指向观察者

        glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);    

        glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);    

        glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);    

        glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);    

        // 后侧面
        glNormal3f( 0.0f, 0.0f,-1.0f);                    // 法线背向观察者

        glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);    

        glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);    

        glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);    

        glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);    

        // 顶面
        glNormal3f( 0.0f, 1.0f, 0.0f);                    // 法线向上

        glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);    

        glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,  1.0f,  1.0f);    

        glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,  1.0f,  1.0f);    

        glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);    

        // 底面
        glNormal3f( 0.0f,-1.0f, 0.0f);                    // 法线朝下

        glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);    

        glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);    

        glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);    

        glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);    

        // 右侧面
        glNormal3f( 1.0f, 0.0f, 0.0f);                    // 法线朝右

        glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);    

        glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);    

        glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);    

        glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);    

        // 左侧面
        glNormal3f(-1.0f, 0.0f, 0.0f);                    // 法线朝左

        glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);    

        glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);    

        glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);    

        glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);    
    glEnd();                                // 四边形绘制结束

下两行代码将xot和yrot的旋转值分别增加xspeed和yspeed个单位。xspeed和yspeed的值越大,立方体转得就越快。

    xrot+=xspeed;                                // xrot 增加 xspeed 单位

    yrot+=yspeed;                                // yrot 增加 yspeed 单位

    return TRUE;    
}

现在转入WinMain()主函数。我们将在这里增加开关光源、旋转木箱、切换过滤方式以及将木箱移近移远的控制代码。在接近WinMain()函数结束的地方你会看到SwapBuffers(hDC)这行代码。然后就在这一行后面添加如下的代码。
代码将检查L键是否按下过。如果L键已按下,但lp的值不是false的话,意味着L键还没有松开,这时什么都不会发生。

                SwapBuffers(hDC);                // 交换缓存

                if (keys[L] && !lp)                // L 键已按下并且松开了?
                {

如果lp的值是false的话,意味着L键还没按下,或者已经松开了,接着lp将被设为TRUE。同时检查这两个条件的原因是为了防止L键被按住后,这段代码被反复执行,并导致窗体不停闪烁。
lp设为true之后,计算机就知道L键按过了,我们则据此可以切换光源的开/关:布尔变量light控制光源的开关。

                    lp=TRUE;                // lp 设为 TRUE

                    light=!light;                // 切换光源的 TRUE/FALSE

Now we check to see what light ended up being. The first line translated to english means: If light equals false. So if you put it all together, the lines do the following: If light equals false, disable lighting. This turns all lighting off. The command ‘else‘ translates to: if it wasn‘t false. So if light wasn‘t false, it must have been true, so we turn lighting on.

                    if (!light)                // 如果没有光源
                    {
                        glDisable(GL_LIGHTING);        // 禁用光源
                    }
                    else                    // 否则
                    {
                        glEnable(GL_LIGHTING);        // 启用光源
                    }
                }

下面的代码查看是否松开了"L"键。如果松开,变量lp将设为false。这意味着"L"键没有按下。如果不作此检查,光源第一次打开之后,就无法再关掉了。计算机会以为"L"键一直按着呢。

                if (!keys[L])                    // L键松开了么?
                {
                    lp=FALSE;                // 若是,则将lp设为FALSE
                }

然后对"F"键作相似的检查。如果有按下"F"键并且"F"键没有处于按着的状态或者它就从没有按下过,将变量fp设为true。这意味着这个键正被按着呢。接着将filter变量加一。如果filter变量大于2(因为这里我们的使用的数组是texture[3],大于2的纹理不存在),我们重置filter变量为0。

                if (keys[F] && !fp)                // F键按下了么?
                {
                    fp=TRUE;                // fp 设为 TRUE

                    filter+=1;                // filter的值加一

                    if (filter>2)                // 大于2了么?
                    {
                        filter=0;            // 若是重置为0
                    }
                }

                if (!keys[F])                    // F键放开了么?
                {
                    fp=FALSE;                // 若是fp设为FALSE
                }

这四行检查是否按下了PageUp键。若是的话,减少z变量的值。这样DrawGLScene函数中包含的glTranslatef(0.0f,0.0f,z)调用将使木箱离观察者更远一点。

                if (keys[VK_PRIOR])                // PageUp按下了?
                {
                    z-=0.02f;                // 若按下,将木箱移向屏幕内部
                }

接着四行检查PageDown键是否按下,若是的话,增加z变量的值。这样DrawGLScene函数中包含的glTranslatef(0.0f,0.0f,z)调用将使木箱向着观察者移近一点。

                if (keys[VK_NEXT])                // PageDown按下了么
                {
                    z+=0.02f;                // 若按下的话,将木箱移向观察者
                }

现在检查方向键。按下左右方向键xspeed相应减少或增加。按下上下方向键yspeed相应减少或增加。记住在以后的教程中如果xspeed、yspeed的值增加的话,立方体就转的更快。如果一直按着某个方向键,立方体会在那个方向上转的越快。

                if (keys[VK_UP])                // Up方向键按下了么?
                {
                    xspeed-=0.01f;                // 若是,减少xspeed
                }
                if (keys[VK_DOWN])                // Down方向键按下了么?
                {
                    xspeed+=0.01f;                // 若是,增加xspeed
                }
                if (keys[VK_RIGHT])                // Right方向键按下了么?
                {
                    yspeed+=0.01f;                // 若是,增加yspeed
                }
                if (keys[VK_LEFT])                // Left方向键按下了么?
                {
                    yspeed-=0.01f;                // 若是, 减少yspeed
                }

像前几课一样,我们最后还需要更正窗体的标题。

                if (keys[VK_F1])                // F1按下了么?
                {
                    keys[VK_F1]=FALSE;            // 若是将其设为FALSE

                    KillGLWindow();                // 销毁当前窗口

                    fullscreen=!fullscreen;            // 切换全屏/窗口模式

                    // 重建GL窗口
                    if (!CreateGLWindow("NeHe‘s Textures, Lighting & Keyboard tutorial",640,480,16,fullscreen))
                    {
                        return 0;            // 若无法创建窗口,程序退出
                    }
                }
            }
        }
    }

    // 关闭
    KillGLWindow();                                // 销毁窗口

    return (msg.wParam);                            // 退出程序
}

 

这一课完了之后,您应该学会创建和使用这三种不同的纹理映射过滤方式。并使用键盘和场景中的对象交互。最后,您应该学会在场景中应用简单的光源,使得场景看起来更逼真。

 

第07课 OpenGL 光照和键盘(2)

原文:http://www.cnblogs.com/fish7/p/4007015.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!