Aller au menu - Aller au contenu

Icône Enfin de la 3D (Partie 2/2)

Par Kayl
Mise à jour : 12/05/2009
6 426 visites depuis 7 jours, dont 371 sur ce chapitre, classé 29/795
Dans le dernier chapitre nous nous sommes préparés à passer à la 3D, il est donc temps de s'y mettre et d'entamer notre premier dessin : un cube ! En dessinant notre cube et en l'animant, nous rencontrerons des problèmes, prévus d'avance rassurez-vous ^^ , et nous verrons comment les résoudre.
Sommaire du chapitre :
Icône du chapitre
Chapitre précédent Sommaire Chapitre suivant

Un cube

L'exemple du cube est assez simple et nous continuerons avec lors de la création de notre première scène texturée.

Voyons tout d'abord comment est constitué un cube :

Image utilisateur
Coordonnées des sommets du cube


Un cube est composé de 8 sommets et 6 faces, chaque face faisant intervenir 4 sommets.
Nous n'allons pas nous contenter de dessiner chacun des 8 sommets, nous n'aurions pas de faces pleines. Il nous faut donc décrire les faces une par une, en indiquant les sommets qu'elles font intervenir.

Décrire des sommets en 3D



Ici nous devons définir 3 coordonnées pour chaque sommet : X, Y et Z. Nous ne pouvons donc plus utiliser le basique glVertex2d que nous utilisions auparavant. Il va falloir donc utiliser la version avec 3 arguments soit glVertex3d.

Exemple :
Code : C++
1
glVertex3d(1,1,1);


Le 3d de glVertex3d ne veut pas dire « ouais je fais de la 3D ! ». Rappelez-vous le chapitre Notions de base, 3 spécifie le nombre d'arguments et d le fait que les arguments donnés soient des double (réels).


Décrire le cube



Les faces étant des carrés, nous allons utiliser le mode GL_QUADS pour décrire les vertices.
Pour différencier les faces nous leur attribuerons une couleur différente ; nous ferons la première (celle avec les flèches) en rouge. En ce qui concerne la caméra, j'ai choisi de la placer en (3,4,2) pour regarder le cube centré en (0,0,0), car cela donnera un bon angle de vue (c'est la position utilisée pour le schéma plus haut).

Ce qui donne donc :

Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
void Dessiner()
{
    glClear( GL_COLOR_BUFFER_BIT );

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity( );

    gluLookAt(3,4,2,0,0,0,0,0,1);

    glBegin(GL_QUADS);

    glColor3ub(255,0,0); //face rouge
    glVertex3d(1,1,1);
    glVertex3d(1,1,-1);
    glVertex3d(-1,1,-1);
    glVertex3d(-1,1,1);
    glEnd();

    glFlush();
    SDL_GL_SwapBuffers();
}


Facile ! Il suffit de choisir un point de départ et de suivre le contour de la face pour décrire les sommets un par un.
Je vous conseille, pour les décrire, de vous imaginer faisant face à la face (hum... Image utilisateur ) et de les énumérer un à un dans le sens inverse des aiguilles d'une montre. En effet nous verrons plus tard que cela nous sera utile quand nous voudrons éviter de dessiner les faces cachées. Encore une fois quelque soit le sens que vous décidez d'utiliser, le tout est d'être cohérents et de garder le même sens.


Continuons donc avec la 2e face, disons celle à gauche de la première (quand on regarde le schéma) et faisons-la en vert.

Code : C++
1
2
3
4
5
glColor3ub(0,255,0); //face verte
    glVertex3d(1,-1,1);
    glVertex3d(1,-1,-1);
    glVertex3d(1,1,-1);
    glVertex3d(1,1,1);


Ce qui me donne le résultat suivant :
Image utilisateur


Bon maintenant parce que je veux vous montrer un problème important, attaquons-nous à la face de derrière que nous ferons... devinez... en bleu ! ;)

Rien de compliqué, il suffit de suivre le schéma de tout à l'heure pour avoir rapidement les coordonnées et écrire le code approprié.

Code : C++
1
2
3
4
5
glColor3ub(0,0,255); //face bleue
    glVertex3d(-1,-1,1);
    glVertex3d(-1,-1,-1);
    glVertex3d(1,-1,-1);
    glVertex3d(1,-1,1);


Et voilà le résultat :
Image utilisateur

o_O o_O o_O


En effet vous ne rêvez pas, la face bleue qui était censée être derrière, donc en majeure partie cachée par la rouge et la verte vient se dessiner par-dessus ces dernières.
Et c'est tout à fait logique, OpenGL dessine les carrés dans l'ordre dans lequel on les définit. Il ne se soucie pour l'instant pas de savoir s'il y a déjà quelque chose là où il dessine et vient donc écraser les faces précédentes.

La solution ? Le Z-Buffer !

Le Z-Buffer

Le Z-Buffer ou Depth-Buffer (pour tampon de profondeur) sert à éviter le problème que nous venons de rencontrer.

Principe du Z-Buffer



Le Z-Buffer est un tampon (buffer) qui stocke la profondeur (d'où le Z, X et Y sur l'écran étant la position en pixel) de chaque pixel affiché à l'écran.
Ensuite quand OpenGL demande à dessiner un pixel à un endroit, il compare la profondeur du point à afficher et celle présente dans le buffer. Si le nouveau pixel est situé devant l'ancien, alors il est dessiné et la valeur de la profondeur dans le buffer est mise à jour. Sinon, le pixel était alors situé derrière et n'a donc pas lieu d'être affiché.

Pour bien comprendre, suivons le cheminement qui est fait.
  • Au départ le buffer (ici de taille 3x3 pour l'exemple) est initialisé à des distances infinies (le plus loin possible vers le fond de votre écran).

    Image utilisateur

  • OpenGL demande à dessiner un pixel en (2,2,5).
    Valeur demandée : 5.
    Valeur présente : infini.
    5 < infini => OK pour dessin
    Dessin du pixel + Mise à jour du Z-buffer avec la valeur 5.

    Image utilisateur

  • Demande de dessin d'un pixel en (2,2,10).
    Valeur demandée : 10.
    Valeur présente : 5.
    10 > 5 => Dessin refusé


Application dans OpenGL



Heureusement pour nous OpenGL gère très bien cette technique, il nous faut juste modifier notre programme pour l'activer et bien l'utiliser !

Pour cela il nous faut :
  • activer son utilisation : après la création de la fenêtre OpenGL il faut simplement appeler :
    Code : C++
    1
    glEnable(GL_DEPTH_TEST);
    
  • le réinitialiser à chaque nouvelle image, en même temps que le buffer des pixels :
    Code : C++
    1
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ;
    


Ce qui nous donne un code complet (avec le début de notre cube) :

Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <cstdlib>

void Dessiner();

int main(int argc, char *argv[])
{
    SDL_Event event;

    SDL_Init(SDL_INIT_VIDEO);
    atexit(SDL_Quit);
    SDL_WM_SetCaption("SDL GL Application", NULL);
    SDL_SetVideoMode(640, 480, 32, SDL_OPENGL);

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    gluPerspective(70,(double)640/480,1,1000);
    glEnable(GL_DEPTH_TEST);

    Dessiner();

    for (;;)
    {
        SDL_WaitEvent(&event);

        switch(event.type)
        {
            case SDL_QUIT:
            exit(0);
            break;
        }
        Dessiner();

    }

    return 0;
}

void Dessiner()
{
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity( );

    gluLookAt(3,4,2,0,0,0,0,0,1);

    glBegin(GL_QUADS);

    glColor3ub(255,0,0); //face rouge
    glVertex3d(1,1,1);
    glVertex3d(1,1,-1);
    glVertex3d(-1,1,-1);
    glVertex3d(-1,1,1);

    glColor3ub(0,255,0); //face verte
    glVertex3d(1,-1,1);
    glVertex3d(1,-1,-1);
    glVertex3d(1,1,-1);
    glVertex3d(1,1,1);

    glColor3ub(0,0,255); //face bleue
    glVertex3d(-1,-1,1);
    glVertex3d(-1,-1,-1);
    glVertex3d(1,-1,-1);
    glVertex3d(1,-1,1);

    glEnd();

    glFlush();
    SDL_GL_SwapBuffers();
}


Et en effet en exécutant notre nouveau code nous obtenons ceci :

Image utilisateur


Ouf ! Nous avons enfin ce que nous désirions. Bien pratique ce z-buffer !

Finir le cube



À ce stade il ne vous reste plus qu'à compléter le code avec les 3 faces restantes et leur choisir de belles couleurs.
N'oubliez pas que vous pouvez utiliser le schéma du début pour facilement trouver les coordonnées des sommets de la face en cours.

Voici mon code pour ceux qui ne veulent pas essayer eux-mêmes, ou simplement pour comparer :

Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
glBegin(GL_QUADS);

    glColor3ub(255,0,0); //face rouge
    glVertex3d(1,1,1);
    glVertex3d(1,1,-1);
    glVertex3d(-1,1,-1);
    glVertex3d(-1,1,1);

    glColor3ub(0,255,0); //face verte
    glVertex3d(1,-1,1);
    glVertex3d(1,-1,-1);
    glVertex3d(1,1,-1);
    glVertex3d(1,1,1);

    glColor3ub(0,0,255); //face bleue
    glVertex3d(-1,-1,1);
    glVertex3d(-1,-1,-1);
    glVertex3d(1,-1,-1);
    glVertex3d(1,-1,1);

    glColor3ub(255,255,0); //face jaune
    glVertex3d(-1,1,1);
    glVertex3d(-1,1,-1);
    glVertex3d(-1,-1,-1);
    glVertex3d(-1,-1,1);

    glColor3ub(0,255,255); //face cyan
    glVertex3d(1,1,-1);
    glVertex3d(1,-1,-1);
    glVertex3d(-1,-1,-1);
    glVertex3d(-1,1,-1);

    glColor3ub(255,0,255); //face magenta
    glVertex3d(1,-1,1);
    glVertex3d(1,1,1);
    glVertex3d(-1,1,1);
    glVertex3d(-1,-1,1);

    glEnd();


Et le résultat graphique correspondant :
Image utilisateur


Image utilisateur

Comme vous avez le code sous les yeux vous savez que vous n'avez pas triché et que le code fait bien un cube 3D. Mais personnellement je vois 3 quadrilatères de couleur, je peux faire pareil sous Paint en 30 secondes, la preuve :
Ok c'est moche et mal fait mais avec un peu de soin j'aurais pu avoir pareil ! :honte:

Il est donc temps de profiter de la puissance de la 3D temps réel et d'animer notre cube pour le voir sous toutes les coutures !

Animation

Pour animer notre cube nous allons simplement le faire tourner en utilisant ce que vous connaissez déjà par coeur : la rotation !

Au niveau du dessin nous n'avons vraiment pas grand chose à changer, juste à faire tourner le repère avant de dessiner le cube. Nous allons le faire tourner à la fois sur Z (la verticale) et X donc nous avons besoin de 2 variables globales* pour chacun des angles à contrôler.

Image utilisateur


* En général en programmation on essaye d'éviter les variables globales mais ici nous faisons en quelque sorte du prototypage pour apprendre et tester les concepts OpenGL, ce n'est donc vraiment pas bien grave.

Le code, simplifié, du programme devient alors :

Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <cstdlib>

void Dessiner();

double angleZ = 0;
double angleX = 0;

int main(int argc, char *argv[])
{
   //le code du main
}

void Dessiner()
{
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity( );

    gluLookAt(3,4,2,0,0,0,0,0,1);

    glRotated(angleZ,0,0,1);
    glRotated(angleX,1,0,0);

    //dessin du cube

    glFlush();
    SDL_GL_SwapBuffers();
}


En terme de code SDL nous voulons que ces angles soient modifiés automatiquement avec le temps. On ne peut donc plus se permettre d'attendre les événements avec SDL_WaitEvent et nous allons en conséquence utiliser SDL_PollEvent pour récupérer les événements s'il y en a puis animer notre cube.

Nous modifions donc le code de notre boucle d'affichage pour incrémenter nos angles à chaque image :

Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
for (;;)
    {
        while (SDL_PollEvent(&event))
        {

            switch(event.type)
            {
                case SDL_QUIT:
                exit(0);
                break;
            }
        }

        angleZ += 1;
        angleX += 1;

        Dessiner();

    }


Gérer la vitesse d'animation


En testant le code actuel vous voyez que le cube tourne beaucoup trop vite, nous n'avons franchement rien le temps de voir.
Il faut donc introduire des vitesses de rotation. Ces vitesses ne doivent pas dépendre de l'ordinateur sur lequel le programme est lancé et donc doivent prendre en compte le temps réel.
Pour ce faire, à chaque image (chaque passage dans la boucle donne lieu à une image), il faut déterminer combien de temps il s'est passé depuis la dernière image et faire bouger le cube en conséquence.

Nous avons donc besoin de 3 variables :
  • une pour garder en mémoire le temps qu'il était lors de la dernière image : last_time ;
  • une pour avoir le temps de l'image actuelle : current_time ;
  • une (par commodité) pour le temps écoulé : ellapsed_time.


Pour connaître le temps écoulé, en millisecondes, depuis le lancement de l'application nous utiliserons l'instruction SDL_GetTicks();


Le principe est alors le suivant.
  1. On initialise une première fois, avant de rentrer dans notre boucle d'affichage last_time avec le temps actuel.
  2. À chaque image on récupère le temps actuel dans current_time.
  3. On utilise la différence entre le temps actuel et le temps qu'il était lors de l'ancien passage pour savoir combien de temps s'est écoulé. On stocke le résultat dans ellapsed_time.
  4. On réalise nos mouvements en fonction du temps écoulé.
  5. On finit par affecter à last_time la valeur de current_time car nous passons à une nouvelle image et donc le présent devient du passé ( :'( c'est beau !)
  6. .


En ce qui concerne l'unité de mesure des vitesses, comme le temps écoulé est donné en millisecondes et que les angles utilisés dans glRotate sont en degrés, il s'agit tout simplement de degrés par milliseconde.

Dans notre cas j'utiliserai 0.05 °/ms.

La traduction en code du principe tout juste évoqué est la suivante :

Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Uint32 last_time = SDL_GetTicks();
    Uint32 current_time,ellapsed_time;

    for (;;)
    {
        while (SDL_PollEvent(&event))
        {

            switch(event.type)
            {
                case SDL_QUIT:
                exit(0);
                break;
            }
        }

        current_time = SDL_GetTicks();
        ellapsed_time = current_time - last_time;
        last_time = current_time;

        angleZ += 0.05 * ellapsed_time;
        angleX += 0.05 * ellapsed_time;

        Dessiner();

    }


Image utilisateur


Ne pas monopoliser le CPU



Ça rame ! Le programme prend 100% du CPU rien que pour faire tourner un simple cube, je ne vais jamais pouvoir faire un jeu !


En effet si on regarde la charge du processeur imposée par notre application on voit qu'il est totalement occupé à gérer notre programme :

Image utilisateur


Cela ne veut pas dire que votre programme est lent c'est juste que nous bouclons en permanence et que nous ne prenons jamais de pause. En réalité nous n'avons pas vraiment besoin de boucler tout le temps. Nous allons utiliser une technique possible (celle que je préfère et donc souhaite vous expliquer) : limiter les FPS (frames per second - images par seconde).
En effet pour avoir une animation très fluide il nous suffit de 50 images par seconde.

En fixant le nombre d'images par secondes désirées par votre application, il est alors possible de la faire s'endormir un certain temps si elle va plus vite que nécessaire, ce qui soulagera (même s'il ne s'en plaint pas) le processeur.
Pour ce faire nous allons calculer à chaque image combien de temps nous avons mis pour la dessiner, si nous avons été plus rapides que le temps moyen nécessaire, nous stopperons l'exécution pour un certain temps.

Par exemple, autoriser 50 images par seconde donne à chaque image 20 millisecondes pour s'afficher. Imaginons qu'une image mette 5 ms à s'afficher réellement, il reste alors 15 ms à tuer. Plutôt que de passer directement à l'image suivante, nous allons endormir l'application pendant ces 15 ms.

En terme de code nous allons utiliser SDL_GetTicks comme auparavant pour déterminer le temps écoulé entre le début et la fin de la création de l'image. Nous utiliserons SDL_Delay pour suspendre temporairement l'application.

Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Uint32 start_time; //nouvelle variable

    for (;;)
    {
        start_time = SDL_GetTicks(); 
        while (SDL_PollEvent(&event))
        {

            switch(event.type)
            {
                case SDL_QUIT:
                exit(0);
                break;
                case SDL_KEYDOWN:
                animation = !animation;
                break;
            }
        }

        current_time = SDL_GetTicks();
        ellapsed_time = current_time - last_time;
        last_time = current_time;

        angleZ += 0.05 * ellapsed_time;
        angleX += 0.05 * ellapsed_time;

        Dessiner();

        ellapsed_time = SDL_GetTicks() - start_time;
        if (ellapsed_time < 10)
        {
            SDL_Delay(10 - ellapsed_time);
        }

    }

    return 0;
}


Notez qu'ici nous ne voulons pas savoir combien de temps il s'est passé depuis la dernière fois mais combien de temps notre image a pris à se dessiner (j'y ai inclus la gestion des événements). Il y a donc un appel à SDL_GetTicks au début de notre boucle et un appel à la toute fin. Je réutilise ellapsed_time par commodité mais pas les autres variables pour ne pas mélanger les 2 concepts : limitation des FPS et gestion du temps dans les animations.

Code final :

Code : C++
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <cstdlib>

void Dessiner();

double angleZ = 0;
double angleX = 0;

int main(int argc, char *argv[])
{
    SDL_Event event;

    SDL_Init(SDL_INIT_VIDEO);
    atexit(SDL_Quit);
    SDL_WM_SetCaption("SDL GL Application", NULL);
    SDL_SetVideoMode(640, 480, 32, SDL_OPENGL);

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    gluPerspective(70,(double)640/480,1,1000);

    glEnable(GL_DEPTH_TEST);

    Dessiner();

    Uint32 last_time = SDL_GetTicks();
    Uint32 current_time,ellapsed_time;
    Uint32 start_time;

    for (;;)
    {
        start_time = SDL_GetTicks();
        while (SDL_PollEvent(&event))
        {

            switch(event.type)
            {
                case SDL_QUIT:
                exit(0);
                break;
            }
        }

        current_time = SDL_GetTicks();
        ellapsed_time = current_time - last_time;
        last_time = current_time;

        angleZ += 0.05 * ellapsed_time;
        angleX += 0.05 * ellapsed_time;

        Dessiner();

        ellapsed_time = SDL_GetTicks() - start_time;
        if (ellapsed_time < 10)
        {
            SDL_Delay(10 - ellapsed_time);
        }

    }

    return 0;
}

void Dessiner()
{
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity( );

    gluLookAt(3,4,2,0,0,0,0,0,1);

    glRotated(angleZ,0,0,1);
    glRotated(angleX,1,0,0);

    glBegin(GL_QUADS);

    glColor3ub(255,0,0); //face rouge
    glVertex3d(1,1,1);
    glVertex3d(1,1,-1);
    glVertex3d(-1,1,-1);
    glVertex3d(-1,1,1);

    glColor3ub(0,255,0); //face verte
    glVertex3d(1,-1,1);
    glVertex3d(1,-1,-1);
    glVertex3d(1,1,-1);
    glVertex3d(1,1,1);

    glColor3ub(0,0,255); //face bleue
    glVertex3d(-1,-1,1);
    glVertex3d(-1,-1,-1);
    glVertex3d(1,-1,-1);
    glVertex3d(1,-1,1);

    glColor3ub(255,255,0); //face jaune
    glVertex3d(-1,1,1);
    glVertex3d(-1,1,-1);
    glVertex3d(-1,-1,-1);
    glVertex3d(-1,-1,1);

    glColor3ub(0,255,255); //face cyan
    glVertex3d(1,1,-1);
    glVertex3d(1,-1,-1);
    glVertex3d(-1,-1,-1);
    glVertex3d(-1,1,-1);

    glColor3ub(255,0,255); //face magenta
    glVertex3d(1,-1,1);
    glVertex3d(1,1,1);
    glVertex3d(-1,1,1);
    glVertex3d(-1,-1,1);

    glEnd();

    glFlush();
    SDL_GL_SwapBuffers();
}


En comparaison, pour une animation de la même fluidité, la charge moyenne du processeur est négligeable :

Image utilisateur


Notes diverses :
  • il est aussi possible d'utiliser des timers pour limiter les FPS (voir la doc de SDL_AddTimer ainsi que son exemple). Ce n'est pas la solution retenue ici ;
  • les adeptes de la doc ne manqueront pas de signaler le problème de la granularité du temps de pause (cf. SDL_Delay). Dans les tests effectués pour rédiger ce tutoriel, le temps de pause réel n'excédait jamais le temps demandé de plus de 1 milliseconde. Le nombre réel d'images par seconde est donc égal (ou très proche) au nombre fixé ;
  • en terme d'ergonomie cela peut faire peur à certains de faire s'endormir le programme un certain temps. Qu'ils soient rassurés, même dans une application 3D bien plus complexe, la gestion des événements n'est en rien altérée.




Voilà le mystère de la 3D en OpenGL est enfin tombé !
Vous savez maintenant créer de toutes pièces un objet 3D et réaliser une animation.
En attendant le prochain chapitre sur les textures vous pouvez, si vous le souhaitez, améliorer votre programme pour créer de multiples objets, en animer certains grâce au clavier, et par exemple faire tourner la caméra autour de votre scène.
Bonne création !
Chapitre précédent Sommaire Chapitre suivant

Partager

5 commentaires pour "Enfin de la 3D (Partie 2/2)"
Note moyenne : 3.48 / 4 (132 votes)
Pseudo Commentaire
Hors ligne kami-sama # Posté le 20/04/2009 à 03:04:40
真実はたった一つ
Avatar

très bon tuto.

Hotensai.fr recrute un rédacteur, plus d'info ici

Hotensai.fr actualité Manga/Anime/Jmusic/Drama/Jeux-vidéo/Otaku.
 
Hors ligne toto62860 # Posté le 31/10/2009 à 17:12:12

bon tuto , j'avais regarder il y a longtemps j'avais rien compris mais la ca va impeck :)
par contre j'ai un "probléme" , en faite je trouve que juste en faisant angleX++, mon cube bouge lentement :s
alors que j'ai un PC il a 3 semaine ....
est-ce normal? c'est possible , que cela soit a cause de accélération graphique sachant , que je suis sous windows 7?
Hors ligne Lud@ # Posté le 24/06/2010 à 15:34:43
UNIX en C
Avatar

Avis : Bon

Ville : Sonceboz
Pays : Suisse

Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
for (;;)
    {
        SDL_WaitEvent(&amp;event);

        switch(event.type)
        {
            case SDL_QUIT:
            exit(0);
            break;
        }
        Dessiner();

    }


Le for(;;) ne marche pas. ce n'est pas plûtot while(1) ?
Et c'est quoi ce &amp; devant l'event?

Chez moi aucun des deux bout de code que j'ai cité ne marche.

Sinon le tuto en soit est bien =)

EDIT:
Je viens de trouver a quoi sert le &amp; , en fait il représente un & en html... Source Ici

Image utilisateur
Image utilisateur
Image utilisateur

On dit souvent à tort que mac n'est pas compatible avec un programme, alors que c'est le programme qui ne l'est pas.
 
Hors ligne daminator # Posté le 24/11/2010 à 16:09:49
Le créateur de skynet !
Avatar

Avis : Très bon

Bien jouer très bon tuto.

PS: Mon processeur tourne quand même a 20% il est pas tout neuf mais bon.

google est mon ami, le site du zero est... heu...?
le créateur de skynet te félicite !!! ...ou pas !
 
Hors ligne neo_xnitro # Posté le 21/10/2011 à 23:46:11

bhaaa je ne comprend pas, j'ai ma caméra en

3,4,2 et je look en 0,0,0 avec projection 0,0,1

je modifie le 4 en 5 par exemple se qui à pour but de regardé plus haut, mai à la place il regarde vers la droite, comme si z avait été affecté :s

comme si les données devrais être xcam,zcam,ycam,xview,zview,yview,...

?? une explication ??

Edit: Apres analyse approfondie de l’environnement, il sévère que c'est bien xcam,ycam,zcam,xview,yview,zview
Néanmoins, il faut évité de jouer avec la caméra avant de lire le chapitre suivant !!!

Voir tous les commentaires
Ce tutoriel a été corrigé par les zCorrecteurs.