IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

OpenGL Discussion :

Problème de normales avec OpenGL


Sujet :

OpenGL

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2008
    Messages : 15
    Points : 12
    Points
    12
    Par défaut Problème de normales avec OpenGL
    Bonjour à tous,

    Je dispose dans mon programme de deux vecteurs, un contenant une liste de points (leurs coordonnées), et une liste de triangles, contenant les 3 coordonnées des 3 sommets dans la liste de points.

    L'affichage fonctionne, mais l'image a une couleur uniforme, donc l'effet 3D est complètement raté.
    Je dois donc pour arranger ce problème calculer les normales de chaque facettes, ce que je fais avec le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    glBegin(GL_TRIANGLES);
     
        glColor3ub(255,0,0); //du rouge
        for(int i=0; i<(int)facettes.size();i++)
        {
            nx=(points[facettes[i].x-1].x-points[facettes[i].y-1].x)*(points[facettes[i].y-1].x-points[facettes[i].z-1].x);
            ny=(points[facettes[i].x-1].y-points[facettes[i].y-1].y)*(points[facettes[i].y-1].y-points[facettes[i].z-1].y);
            nz=(points[facettes[i].x-1].z-points[facettes[i].y-1].z)*(points[facettes[i].y-1].z-points[facettes[i].z-1].z);
            //qDebug() << "Test "<<nx<<","<<ny<<","<<nz;
            glNormal3f(nx,ny,nz);
            glVertex3d(points[facettes[i].x-1].x,points[facettes[i].x-1].y,points[facettes[i].x-1].z);
            glVertex3d(points[facettes[i].y-1].x,points[facettes[i].y-1].y,points[facettes[i].y-1].z);
            glVertex3d(points[facettes[i].z-1].x,points[facettes[i].z-1].y,points[facettes[i].z-1].z);
        }
     
        glEnd();
    Bon, les tableaux sont un peu confus, j'admets, mais la deuxième partie du code fonctionne bien, et l'affichage des normales par le code de debug donne bien des valeurs différentes pour chaque facette, donc même si le calcul est foireux, on devrait voir quelque chose, or cela ne change rien du tout.

    Est ce qu'il y a quelque chose à activer pour que cela fonctionne ?
    Je n'ai a première vue pas mis de lampe dans mon programme, n'en ayant pas le besoin puisque jusqu'ici tout s'affichait bien, en ais-je besoin ?

    Merci d'avance pour tout aide que vous pouvez m'apporter.

  2. #2
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 883
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 883
    Points : 219 327
    Points
    219 327
    Billets dans le blog
    123
    Par défaut
    Bonjour,

    Effectivement, avoir des normales c'est beau ... mais seul cela ne sert à rien.
    Les normales permettent les calculs de la reflection, et de tout autre effet lumineux. Donc il va falloir avoir une lumière, pour voir l'effet des normales.

    En debug: on affiche les normales avec des vecteurs unités ( pour être sur que cela marche )
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  3. #3
    Membre confirmé
    Inscrit en
    Février 2008
    Messages
    413
    Détails du profil
    Informations personnelles :
    Âge : 44

    Informations forums :
    Inscription : Février 2008
    Messages : 413
    Points : 486
    Points
    486
    Par défaut
    Bonjour,

    comme le dit LittleWhite, il va te falloir une lumière...plus précisément:

    1. Activer l'eclairage OpenGL (glEnable(GL_LIGHTING))
    2. Activer au moins une source lumineuse (glEnable(GL_LIGHT0) par exemple, ainsique les différents parametres pour configurer cette source)
    3. Définir un "matériel" pour tes sommets (comme une couleur, mais avec des parametres en plus pris en compte pour le calcul de l'eclairage): glMaterial(...), ou la combinaison glEnable(GL_COLOR_MATERIAL) et glColor(...)

    Et si tout celà te paraît obscur (sans mauvais jeu de mot, un peu plus d'infos ici: http://www.sjbaker.org/steve/omniv/opengl_lighting.html

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2008
    Messages : 15
    Points : 12
    Points
    12
    Par défaut
    D'accord, un grand merci à vous deux pour cette aide précieuse.

    J'ai fait ce que vous avez préconisé, et le résultat commence à se rapprocher de ce que je souhaite.

    Il me reste deux petits problèmes, intimement liés à mon avis.
    Tout d'abord, je souhaite que ma fenêtre soit redimensionnable, je précise que j'utilise Qt pour tout ce qui est de l'interface.

    Lorsque ma fenêtre n'est pas carrée, mon objet se déforme joyeusement lorsqu'on le fait pivoter. Comment puis-je résoudre ce problème ?
    Ensuite, mon soucis est que certaines facettes visibles mais presque perpendiculaires "à l'axe de la camera", apparaissent totalement noires, alors qu'elles ne le devraient pas.

    J'ai joint une image du problème.

    Je me demande si cela n'est pas lié à une déformation du vecteur normal lié au premier problème. Par contre, cela se produit également avec une fenêtre carrée. Alors que l'objet est immobile, et donc ces normales fixes, lorsque je change d'angle de vision, des facettes noires redeviennent visibles, et vice versa.

    Merci d'avance pour votre aide.
    Images attachées Images attachées  

  5. #5
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 883
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 883
    Points : 219 327
    Points
    219 327
    Billets dans le blog
    123
    Par défaut
    Pour qt et le redimensionnement j'utilise ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    void GLWidget :: resizeGL(int width, int height )
    {
    	glViewport(0,0,width,height);
     
    #ifdef _DEBUG
    	std::cout << "GLWidget resize ("<< width << "x" << height << ")" << std::endl;
    #endif	
    }
    En parant du principe que la classe s'appelle GLWidget, et aussi que elle hérite du QGLWidget
    En fait, nous surchargeons une fonction de QGLWidget, qui est appelée lors du redimensionnement .

    Pour les choses qui apparaissent en noir, même en regardant la capture d'écran ( qui est petite ) j'ai pas compris le bug. Et je ne pense pas que ce soit un problème de redimensionnement ( mais ça vous allez vite le savoir ).
    Peut être que vos normales sont fausses ?
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  6. #6
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2008
    Messages : 15
    Points : 12
    Points
    12
    Par défaut
    Merci pour votre réponse.

    En fait, comme c'est mon premier programme réalisé avec Qt, je me suis inspiré d'un des codes de démonstration pour réaliser le Widget.

    J'avais donc ainsi déja la fonction suivante, à laquelle je n'avais jamais porté une attention particulière, ce qui m'a permis de me rendre compte que quelque chose n'allait pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    void Widget3d::resizeGL(int width, int height)
    {
        glViewport(0, 0, width, height);
        gluPerspective(70,1,0.01,60);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glMatrixMode(GL_MODELVIEW);
    }
    Je l'ai donc remplacée par :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void Widget3d::resizeGL(int width, int height)
    {
        glViewport(0, 0, width, height);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
    }
    qui me semble plus logique. Mes deux problèmes ont effectivement disparu, mais par contre tout mon affichage s'est en quelque sorte décalé et ne fais plus trop ce que j'attends de lui, en conséquence logique de la supression de la ligne gluPerspective, j'imagine.

    Est ce que ma fonction de resize est correcte ainsi ?
    Est ce qu'il y a moyen simplement de rétablir l'affichage que j'avais avant ?
    Je vais travailler sur ce dernier point.

    Encore merci pour votre aide qui me fait bien progresser.

    PS: Je précise que l'effet voulu est le suivant : La caméra est fixe, on peut éloigner l'objet dans une direction ou le faire tourner sur lui même dans les trois directions.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void Widget3d::paintGL()
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();
        glTranslated(0.0, -2.0, -zoom);
        glRotated(xRot / 16.0, 1.0, 0.0, 0.0);
        glRotated(yRot / 16.0, 0.0, 1.0, 0.0);
        glRotated(zRot / 16.0, 0.0, 0.0, 1.0);
        glCallList(object);
    }

  7. #7
    Membre confirmé
    Inscrit en
    Février 2008
    Messages
    413
    Détails du profil
    Informations personnelles :
    Âge : 44

    Informations forums :
    Inscription : Février 2008
    Messages : 413
    Points : 486
    Points
    486
    Par défaut
    Bonjour,

    content que tu avances dans ton affaire! Juste une remarque concernant ton probleme de normales et de "faces noires".

    D'après ton code publié dans le 1er post, tu calcules les normales par triangle. En soit ca n'est pas faux....mais ca dépend du rendu final que tu veux obtenir, je m'explique:
    Dans un mesh, la plupart des sommets sont communs a plusieurs triangles. Disons que le sommet A appartient aux triangles 1, 2, 3, 5 et 6. La tu calcules 6 normales différentes, qui seront appliquées à A au moment du dessin de chaque triangle. Au final, ca te donne un aspect "à facettes", comme on peut le voir sur ta capture d'écran.

    Si tu veux un aspect "lisse", il faut
    - Calculer les 6 normales
    - Interpoler ces normales et obtenir la normale "moyennée" correspondante
    - Appliquer cette normale à A

    Et là normalement tu n'auras plus l'effet que tu décris.

    Hum en me relisant pas sûr que ca soit très très clair....au cas-où je re-détaillerai

  8. #8
    Membre actif Avatar de Robxley
    Homme Profil pro
    Docteur ingénieur traitement d'image
    Inscrit en
    Mai 2009
    Messages
    158
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Docteur ingénieur traitement d'image

    Informations forums :
    Inscription : Mai 2009
    Messages : 158
    Points : 228
    Points
    228
    Par défaut
    Salut,

    Si j'ai bien compris tu as un décalage lorsque tu redimensionnes ta fenêtre. Je pense que tu as un problème de ratio hauteur/largeur quand ton redimensionnement n'est plus une fenêtre carrée.


    je te conseille la fonction de redimensionnement suivante où le ratio largeur / hauteur de la fenêtre est prise en compte pour avoir une projection orthonormée.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    void Widget3d::resizeGL(int width, int height)
    {
        glViewport(0, 0, width, height);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(70,(float)width/(float)height, 0.01, 60);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
    }
    ps : Dans le cas où on a une fenêtre carrée tu retombes bien sur le resizeGL de démonstration que tu as posté.
    Rien ne sert de courir, mieux vaut partir à point. Programmer aussi d'ailleurs.
    Surtout, mais surtout pas d’astuces !
    Pas de bras, pas de chocolat. Les deux mains sur le clavier.

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2008
    Messages : 15
    Points : 12
    Points
    12
    Par défaut
    Merci pour vos réponses.

    En effet, grâce à votre aide je n'ai plus le problème lié au redimensionnement, et je pense que je devrais m'en tirer pour la vue.

    Cependant, mon problème de facettes noires reste entier, et je m'étais mal expliqué je pense. L'aspect "facettes" en lui même ne me dérange pas plus que cela, mais merci quand même ShevchenKik pour l'explication, je m'en servirai au moment ou je souhaiterai lisser mes objets.

    Je vous ai joint une image plus grande de mon problème.
    Comme vous le voyez, certaines facettes sont noires et cela change au fur et a mesure que l'on fait pivoter l'image.

    Ça ne me semble pas être lié au calcul des normales en temps que tel, puisque les normales sont sensées rester fixes. Je penche plutot pour un problème de repère, ou les normales seraient décalées, enfin je ne sais pas trop.

    Voici quand même la manière dont je calcule les normales, j'ai modifié mon premier calcul qui m'avait l'air louche pour réaliser un produit vectoriel classique entre deux arêtes du triangle.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
            abx=points[facettes[i].x-1].x-points[facettes[i].y-1].x;
            aby=points[facettes[i].x-1].y-points[facettes[i].y-1].y;
            abz=points[facettes[i].x-1].z-points[facettes[i].y-1].z;
            acx=points[facettes[i].x-1].x-points[facettes[i].z-1].x;
            acy=points[facettes[i].x-1].y-points[facettes[i].z-1].y;
            acz=points[facettes[i].x-1].z-points[facettes[i].z-1].z;
            nx=(aby*acz)-(acy*abz);
            ny=(abz*acx)-(abx*acz);
            nz=(abx*acy)-(aby*acx);
            norme=sqrt(nx*nx+ny*ny+nz*nz);
            nx/=norme;
            ny/=norme;
            nz/=norme;
            glNormal3f(nx,ny,nz);
    Comme vous pouvez le voir, j'ai tenté de normaliser le vecteur, mais ca ne change rien.

    Merci d'avance pour votre aide.
    Images attachées Images attachées  

  10. #10
    Membre confirmé
    Inscrit en
    Février 2008
    Messages
    413
    Détails du profil
    Informations personnelles :
    Âge : 44

    Informations forums :
    Inscription : Février 2008
    Messages : 413
    Points : 486
    Points
    486
    Par défaut
    Re,

    une idée vite fait: puisque les faces "noires" apparaissent / disparaissent en fonction de la rotation, ca ressemble a un probleme par rapport a la position de la lumière.

    Plus précisément je pense à l'orientation des faces: à moins que tu n'aies explicitement précisé que tu veux un éclairage sur 2 faces, OpenGL va s'occuper de la face avant, et de celle-ci uniquement.

    La face avant est définie par l'ordre dans lequel tu envois tes 3 sommets par triangle. Par défaut, sens anto-horaire = face avant, sens horaire = face arrière (mais tu peux modifier ca aussi).

    Bref, j'ai l'impression que certains de tes triangles sont en face arrière alors que le reste est en face avant....

    si tu peux, essaie d'inverser l'ordre de TOUS tes triangles: si ceux qui étaient noir auparavant sont colorés, et les autres qui étaient bon deviennent noirs, c'est ca!

  11. #11
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2008
    Messages : 15
    Points : 12
    Points
    12
    Par défaut
    Bien vu, c'est exactement ca.

    Comment puis-je régler le soucis alors ?

    J'ai fait un glDisable(GL_CULL_FACE); malheureusement sans succès.

    Merci de votre aide.

  12. #12
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 883
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 883
    Points : 219 327
    Points
    219 327
    Billets dans le blog
    123
    Par défaut
    De mémoire, le glDisable(GL_CULL_FACE); devrait suffire. L'avez vous fait à l'initialisation?
    ( Pardon pour mon code faut du resize ... je n'utilisais pas un environement 3D pour ce code )
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  13. #13
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2008
    Messages : 15
    Points : 12
    Points
    12
    Par défaut
    Oui, je l'ai placé dans la fonction d'initialisation, appelée à la création du widget.

    Une autre piste : J'utilise blender pour exporter mon fichier, pour des raisons pratique je n'exporte que les points et les facettes. Je présume qu'une option doit exister dans blender pour lui dire d'indicer les points des triangles en fonction de la normale, pour que je n'aille plus ce problème.

    Je ne suis pas chez moi actuellement, donc je n'ai pas la possibilité de tester pour le moment, mais si quelqu'un a une indication qui pourrais m'aider, si possible pour simplement afficher les deux faces de mes objets, ce serait très gentil.

    Merci d'avance.

  14. #14
    Membre confirmé
    Inscrit en
    Février 2008
    Messages
    413
    Détails du profil
    Informations personnelles :
    Âge : 44

    Informations forums :
    Inscription : Février 2008
    Messages : 413
    Points : 486
    Points
    486
    Par défaut
    Re,

    pour le culling, les fonctions qui t'intéressent sont:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    glFrontFace(GL_CCW);	   // Culling : Front Face is Counter-Clockwise
    glCullFace(GL_BACK);	   // Cull the back faces
    glEnable(GL_CULL_FACE);     // Turn Culling ON
    si tu désactive le culling avec un glDisable(GL_CULL_FACE), les faces avant et arrières seront affichées. Mais pour avoir uncalcul d'éclairage correct sur les 2 faces, il faut configurer l'éclairage en conséquence, avec un

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);							// Enable dual-side lighting
    Là normalement ca devrait s'afficher. Mais ce n'est pas la solution idéale, car en désactivant le culling la carte graphique a 2 fois plus de polygones a calculer, et les calculs d'eclairage sur 2 faces sont évidemment plus couteux que sur une seule....

    Je pense que le mieux serait d'identifier quels triangles sont rendus "dans le mauvais sens" et de corriger ca, comme ca tu peux garder le culling et l'éclairage sur une seule face.

Discussions similaires

  1. Problème de compilation avec OpenGL
    Par kipgon dans le forum Qt
    Réponses: 15
    Dernier message: 16/05/2013, 10h28
  2. [Graphics View] Problème d'affichage avec OpenGL
    Par elwess dans le forum Qt
    Réponses: 4
    Dernier message: 20/02/2012, 09h48
  3. Problème de transparence avec OpenGL
    Par yann458 dans le forum OpenGL
    Réponses: 15
    Dernier message: 16/12/2011, 08h43
  4. Problème de son avec OpenGL
    Par SQUAL dans le forum Android
    Réponses: 0
    Dernier message: 12/03/2011, 10h51
  5. Problème de profondeur avec OpenGL et GLUT
    Par brotelle dans le forum GLUT
    Réponses: 3
    Dernier message: 12/03/2006, 14h47

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo