Lumieres

 

  1. Un peu de MFC de nouveau avant d'illuminer la scene : pour faire bouger le cube, il est preferable de temporiser precisement les deplacements. La classe CCube est deja prevue pour cela (avec Update).
    Lorsque l'application n'a plus rien a faire (la file des messages est vide), la fonction OnIdle de l'application est appelee. Probleme : la classe CWinApp ne peut pas (ou en tout cas je ne sais pas comment faire) connaitre l'instance CView actuellement affichee. Par contre la vue peut connaitre son application. Une solution est donc de rajouter a la classe application un pointeur qui sera initialisee par la vue.

    Dans la classe de vue, rajouter :

    void * pView;

    l'initialiser a NULL dans le constructeur.

    Ajouter la fonction OnIdle (ClassWizard), et pour declencher un message OnPaint utiliser InvalidateRect :

    BOOL CTutorialApp::OnIdle(LONG lCount)
    {
        // TODO: Add your specialized code here and/or call the base class
        if (pView)
            ((CTutorialView *)pView)->InvalidateRect(NULL, FALSE);
        return 1;
    }

    Dans le constructeur de la classe vue, initialiser pView :

    CTutorialView::CTutorialView()
    {
        // TODO: add construction code here
        m_hGLContext = NULL;
        m_GLPixelIndex = 0;
        ((CTutorialApp *)AfxGetApp())->pView = this;
    }

    Changer OnPaint :

    void CTutorialView::OnPaint()
    {
        CPaintDC dc(this); // device context for painting
       
        // TODO: Add your message handler code here
        static DWORD last_t = GetTickCount();
        DWORD t = GetTickCount() - last_t;
        if (t == 0)
            return;
        last_t = GetTickCount();


        glMatrixMode(GL_MODELVIEW);
        glClear(GL_COLOR_BUFFER_BIT);

        static CCube c(1, 0, 0, -8, 30, 35, 0, 0, 0, 0, 0.1, 0.2, -0.3);
        c.Draw(0, 0, 0);
        c.Update(t);

        glFlush();

        SwapBuffers(dc.m_ps.hdc);
        // Do not call CView::OnPaint() for painting messages
    }
  2. Les effets de lumieres sont parametres par deux choses : la source lumineuse et le materiau d'un objet. Chacun dispose de parametres pour la lumiere ambiante, reflechie... C'est la meme chose lorsque l'on eclaire un surface rouge avec un lumiere blanche : on la voit rouge. Si la lumiere est bleue, la surface est noire.
    La composante la plus importante pour la lumiere et la surface celle qui caracterise la lumiere ambiente. Les autres sevrent a donner une impression metallique, plastique ou de pierre, ou bien pour faire des spots.

    Pour parametrer la source lumineuse, utiliser glLight, pour les objets glMaterial (plein d'explications dans les pages man).

    Les effets de spots sont un peu plus difficiles a realiser, il y en a des exemples en multi-texturing.

    Par exemple pour ajouter une lumiere jaune :

    void CTutorialView::OnSize(UINT nType, int cx, int cy)
    {
        CView::OnSize(nType, cx, cy);
       
        // TODO: Add your message handler code here
       
        GLsizei width, height;
        GLdouble aspect;

        width = cx;
        height = cy;

        if (cy==0)
            aspect = (GLdouble)width;
        else
            aspect = (GLdouble)width/(GLdouble)height;

        glViewport(0, 0, width, height);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(45, aspect, 1, 10);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        glDrawBuffer(GL_BACK);

        glEnable(GL_DEPTH_TEST);

        GLfloat ambientProperties[] = {0.8f, 0.8f, 0.08f, 1.0f};
        GLfloat positionProperties[] = {2.0f, 2.0f, -2.0f, 0.0f};
       
        glLightfv( GL_LIGHT0, GL_AMBIENT, ambientProperties);
        glLightfv( GL_LIGHT0, GL_POSITION, positionProperties);

        glEnable(GL_LIGHT0);
        glEnable(GL_LIGHTING);

        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambientProperties);
    }


    Voila ce que cela donne :

    Tutorial4.jpg (9273 bytes)

    Code source : Tutorial4.zip

    Etape precedente     Etape suivante