begin process at 2012 05 27 14:04:42
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

OpenGL

 > CALCUL DES NORMALES D'UN OBJET 3D

CALCUL DES NORMALES D'UN OBJET 3D


 Information sur la source

Note :
9 / 10 - par 1 personne
9,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10
Catégorie :OpenGL Niveau :Initié Date de création :23/02/2005 Vu :8 426

Auteur : erazor

Ecrire un message privé
Site perso
Commentaire sur cette source (8)
Ajouter un commentaire et/ou une note

 Description

on m'a demandé sur le forum de poster mon algo de tri des sommets mais sorti de son contexte il ne sert pas a grand chose donc je poste ici ma  fonction complete de calcul des normales d'un objet

toutes les critiques, si elles sont constructives, sont les bienvenues ;-)

Source

  • void objet::normales()
  • {
  • float tri[4000][7];
  • int i;
  • int j;
  • int k=0;
  • log("calcul des normales");
  • for (i=0; i<polygons_qty; i++)
  • {
  • normx[polya[i]]=(((verty[polyb[i]])-(verty[polyb[i]]))*((vertz[polyc[i]])-(vertz[polyc[i]])))-(((verty[polyb[i]])-(verty[polyb[i]]))*((vertz[
  • polyc[i]])-(vertz[polyc[i]])));
  • normy[polya[i]]=(((vertz[polyc[i]])-(vertz[polyc[i]]))*((vertx[polya[i]])-(vertx[polya[i]])))-(((vertz[polyc[i]])-(vertz[polyc[i]]))*((vertx[
  • polya[i]])-(vertx[polya[i]])));
  • normz[polya[i]]=(((vertx[polya[i]])-(vertx[polya[i]]))*((verty[polyb[i]])-(verty[polyb[i]])))-(((vertx[polya[i]])-(vertx[polya[i]]))*((verty[
  • polyb[i]])-(verty[polyb[i]])));
  • normx[polya[i]]=normx[polya[i]]/sqrt((normx[polya[i]]*normx[polya[i]])+(normy[polya[i]]*normy[polya[i]])+(normz[polya[i]]*normz[polya[i]]));
  • normy[polya[i]]=normy[polya[i]]/sqrt((normx[polya[i]]*normx[polya[i]])+(normy[polya[i]]*normy[polya[i]])+(normz[polya[i]]*normz[polya[i]]));
  • normz[polya[i]]=normz[polya[i]]/sqrt((normx[polya[i]]*normx[polya[i]])+(normy[polya[i]]*normy[polya[i]])+(normz[polya[i]]*normz[polya[i]]));
  • //2eme point
  • normx[polyb[i]]=normx[polya[i]];
  • normy[polyb[i]]=normy[polya[i]];
  • normz[polyb[i]]=normz[polya[i]];
  • //3eme point
  • normx[polyc[i]]=normx[polya[i]];
  • normy[polyc[i]]=normy[polya[i]];
  • normz[polyc[i]]=normz[polya[i]];
  • }
  • log("mise a 0 du tableau de tri");
  • for (i=0; i<4000; i++)
  • {
  • for (j=0; j<7; j++)
  • {
  • tri[i][j]=0;
  • }
  • }
  • log("tri des sommets");
  • for (i=0; i<vertices_qty; i++)
  • {
  • k=0;
  • for (j=0; j<4000; j++)
  • {
  • if (vertx[i]==tri[j][0] && verty[i]==tri[j][1] && vertz[i]==tri[j][2])
  • {
  • tri[j][3]=tri[j][3]+normx[i];
  • tri[j][4]=tri[j][4]+normy[i];
  • tri[j][5]=tri[j][5]+normz[i];
  • tri[j][6]=tri[j][6]+1;
  • k=1;
  • }
  • }
  • if(k==0)
  • for (j=0; j<4000; j++)
  • {
  • if (tri[j][3]==0 && tri[j][4]==0 && tri[j][5]==0)
  • {
  • tri[j][0]=vertx[i];
  • tri[j][1]=verty[i];
  • tri[j][2]=vertz[i];
  • tri[j][3]=normx[i];
  • tri[j][4]=normy[i];
  • tri[j][5]=normz[i];
  • break;
  • }
  • }
  • }
  • log("calcul de la moyenne");
  • for (j=0; j<4000; j++)
  • {
  • tri[j][3]=tri[j][3]/tri[j][6];
  • tri[j][4]=tri[j][4]/tri[j][6];
  • tri[j][5]=tri[j][5]/tri[j][6];
  • }
  • log("assignation des normales");
  • for (i=0; i<4000; i++)
  • {
  • for (j=0; j<vertices_qty; j++)
  • {
  • if (vertx[j]==tri[i][0] && verty[j]==tri[i][1] && vertz[j]==tri[i][2])
  • {
  • normx[j]=tri[i][3];
  • normy[j]=tri[i][4];
  • normz[j]=tri[i][5];
  • }
  • }
  • }
  • }
void objet::normales()
{
float tri[4000][7];
int i;
int j;
int k=0;

log("calcul des normales");

for (i=0; i<polygons_qty; i++)
    {
    

normx[polya[i]]=(((verty[polyb[i]])-(verty[polyb[i]]))*((vertz[polyc[i]])-(vertz[polyc[i]])))-(((verty[polyb[i]])-(verty[polyb[i]]))*((vertz[

polyc[i]])-(vertz[polyc[i]])));
    

normy[polya[i]]=(((vertz[polyc[i]])-(vertz[polyc[i]]))*((vertx[polya[i]])-(vertx[polya[i]])))-(((vertz[polyc[i]])-(vertz[polyc[i]]))*((vertx[

polya[i]])-(vertx[polya[i]])));
    

normz[polya[i]]=(((vertx[polya[i]])-(vertx[polya[i]]))*((verty[polyb[i]])-(verty[polyb[i]])))-(((vertx[polya[i]])-(vertx[polya[i]]))*((verty[

polyb[i]])-(verty[polyb[i]])));
    

normx[polya[i]]=normx[polya[i]]/sqrt((normx[polya[i]]*normx[polya[i]])+(normy[polya[i]]*normy[polya[i]])+(normz[polya[i]]*normz[polya[i]]));
    

normy[polya[i]]=normy[polya[i]]/sqrt((normx[polya[i]]*normx[polya[i]])+(normy[polya[i]]*normy[polya[i]])+(normz[polya[i]]*normz[polya[i]]));
    

normz[polya[i]]=normz[polya[i]]/sqrt((normx[polya[i]]*normx[polya[i]])+(normy[polya[i]]*normy[polya[i]])+(normz[polya[i]]*normz[polya[i]]));
    //2eme point
    normx[polyb[i]]=normx[polya[i]];
    normy[polyb[i]]=normy[polya[i]];
    normz[polyb[i]]=normz[polya[i]];
    //3eme point
    normx[polyc[i]]=normx[polya[i]];
    normy[polyc[i]]=normy[polya[i]];
    normz[polyc[i]]=normz[polya[i]];
    }

log("mise a 0 du tableau de tri");

for (i=0; i<4000; i++)
    {
    for (j=0; j<7; j++)
        {
        tri[i][j]=0;
        }
    }

log("tri des sommets");

for (i=0; i<vertices_qty; i++)
    {
    k=0;
    for (j=0; j<4000; j++)
        {
        if (vertx[i]==tri[j][0] && verty[i]==tri[j][1] && vertz[i]==tri[j][2])
            {
            tri[j][3]=tri[j][3]+normx[i];
            tri[j][4]=tri[j][4]+normy[i];
            tri[j][5]=tri[j][5]+normz[i];
            tri[j][6]=tri[j][6]+1;
            k=1;
            }
        }
    if(k==0)
    for (j=0; j<4000; j++)
        {
        if (tri[j][3]==0 && tri[j][4]==0 && tri[j][5]==0)
            {
            tri[j][0]=vertx[i];
            tri[j][1]=verty[i];
            tri[j][2]=vertz[i];
            tri[j][3]=normx[i];
            tri[j][4]=normy[i];
            tri[j][5]=normz[i];
            break;
            }
        }    
    }

log("calcul de la moyenne");

for (j=0; j<4000; j++)
    {
    tri[j][3]=tri[j][3]/tri[j][6];
    tri[j][4]=tri[j][4]/tri[j][6];
    tri[j][5]=tri[j][5]/tri[j][6];
    }

log("assignation des normales");

for (i=0; i<4000; i++)
    {
    for (j=0; j<vertices_qty; j++)
        {
        if (vertx[j]==tri[i][0] && verty[j]==tri[i][1] && vertz[j]==tri[i][2])
            {
            normx[j]=tri[i][3];
            normy[j]=tri[i][4];
            normz[j]=tri[i][5];
            }
        }
    }
}

 Conclusion

pour la comprehension de tout le monde, quelques infos:
vous pouvez voir aparaitre ci dessous dans le code source des trucs dans ce genre la: verty[ polyb[i] ]
cela est du au fait que j'utilise comme format de fichiers pour mes objets 3d le 3ds et que donc il stock les donnes des vertices mais aussi

l'ordre des points, et ce afin de pouvoir a coup sur calculer la normal dans le bon sens ;-)

vertx verty et vertz sont les 3 coordonnes des sommets des polygones
ploya ployb et polyc sont les infos d'ordre des sommets
normx normy et normz sont les 3 elements des normals

mon tableau de tri est constitué comme cela: vertx | verty | vertz | normx | normy | normz | diviseur pour faire la moyenne (nbre de fois ou

j'ai fait un ajout dans cette ligne)

a savoir qu'ici je dispose de 4000 polygones au max

en esperant que cela en aide plus d'un ;-)


 Sources du même auteur

Source avec Zip ÉDITEUR DE CARTE

 Sources de la même categorie

Source avec Zip Source avec une capture AFFICHER DES COURBES DE BEZIER par shorzy
Source avec Zip Source avec une capture BASE/MOTEUR 3D EN QT/OPENGL (COMPLET ET FONCTIONNEL!) POUR U... par envi33
Source avec Zip Source avec une capture CLASSE AVEC OPENGL - OBJETS 3D ET ANIMATIONS par rasta63
Source avec Zip Source avec une capture LETTRES 3D AVEC OPENGL ET QT par opossum_farceur
Source avec Zip CUBE 3D GLUT32 VC++ ET DEVC++ par bobby03

Commentaires et avis

Commentaire de shenron666 le 23/02/2005 15:59:59

float tri[4000][7];
pourquoi 7 ?

si tu pouvais expliquer ce que tu met dans ton tableau et pourquoi

je me demande aussi pourquoi trier les sommets d'un objet ? dans quel contexte ?

Commentaire de erazor le 24/02/2005 12:15:19

as tu regardé l'explication finale pour ce qui est du contenu du tableau ;-)

quand a l'utilité de la chose, c'est tout simplement pour faire de l'éclairage gouraud ou phong avec opengl.

tu as alors besoin de trier les sommets, ou plutot de regrouper les somets communs afin de calculer une normale "moyenne".

Commentaire de shenron666 le 24/02/2005 14:05:31

désolé je devais être mal réveillé et j'ai zappé l'explication

si je puis te donner un conseil pour casser la limitation de ta procédure (les 4000 polygones) et aussi obtenir un code plus clair (à mon sens) c'est de créer un objet correspondant à ta seconde dimension et d'utiliser la stl (un vector par exemple) pour stocker lesdis objets
tu pourrais traiter un nombre de vertex limité uniquement par la machine

sinon c'est un bon code qui peut s'avérer utile pour un éditeur d'objet par exemple ;-)

Commentaire de KeniiyK le 02/03/2005 12:49:46

Ta méthode de calcul pour une normale a un sommet c'est quoi exactement ?.
Pour chaque sommet tu fais une moyenne des normales des faces auxquelles il appartient ?. (Si c'est ca il y a mieux...)

Au sinon juste un conseil :
dans ton code tu fais ca :
normx[polya[i]]=normx[polya[i]]/sqrt((normx[polya[i]]*normx[polya[i]])+(normy[polya[i]]*normy[polya[i]])+(normz[polya[i]]*normz[polya[i]]));

normy[polya[i]]=normy[polya[i]]/sqrt((normx[polya[i]]*normx[polya[i]])+(normy[polya[i]]*normy[polya[i]])+(normz[polya[i]]*normz[polya[i]]));

normz[polya[i]]=normz[polya[i]]/sqrt((normx[polya[i]]*normx[polya[i]])+(normy[polya[i]]*normy[polya[i]])+(normz[polya[i]]*normz[polya[i]]));

range plutot dans un float ou un double le diviseur :

float/double length=sqrt((normx[polya[i]]*normx[polya[i]])+(normy[polya[i]]*normy[polya[i]])+(normz[polya[i]]*normz[polya[i]]));

puis faire :
normx[polya[i]]/=length;
normy[polya[i]]/=length;
normz[polya[i]]/=length;

Au moins tu ne calcules qu'une seule fois le length, et il faut aussi verifier qu'il ne soit pas nul.

Commentaire de erazor le 02/03/2005 16:07:45

"Ta méthode de calcul pour une normale a un sommet c'est quoi exactement ?.
Pour chaque sommet tu fais une moyenne des normales des faces auxquelles il appartient ?. (Si c'est ca il y a mieux...)"

je suis preneur ;-)

par contre je ne vois pas l'utilité de verifier due le lenght ne soit pas nul vue que une normale (0,0,0) n'est pas possible??

Commentaire de erazor le 02/03/2005 16:08:26

"Ta méthode de calcul pour une normale a un sommet c'est quoi exactement ?.
Pour chaque sommet tu fais une moyenne des normales des faces auxquelles il appartient ?. (Si c'est ca il y a mieux...)"

je suis preneur ;-)

par contre je ne vois pas l'utilité de verifier due le lenght ne soit pas nul vue que une normale (0,0,0) n'est pas possible??

Commentaire de KeniiyK le 02/03/2005 18:11:34

Pour l'histoire du length==0.0, ca depend d'ou proviennent tes normales, si tu es sur que tes normales au faces ne peuvent pas etre nulles alors ok, pas besoin de verifier.
Mais imaginons que tu calcules tes normales au faces et imaginons une face triangulaire (v0,v1,v2) (avec Vi,
i c [0..2] designant un point 3D), si jamais tu as Vi==Vj avec i!=j, i,j c [0..2]² alors (v1-v0)^(v2-v0)=(0.0,0.0,0.0)
(en Counter Clock Wise au sinon faire (v2-v0)^(v1-v0) mais c'est aussi égal au vecteur nul).
(au fait ^ c'est le cross product)
Voila pour l'explication du length==0.0, a toi de voir, mais je pense qu'on est jamais trop prudent :)

Sinon une méthode qui marche bien (voire super bien...) pour le calcul des normales aux sommets c'est de pondérer la moyenne des normales aux faces par l'angle associé au sommet dans la face.
C'est pas clair ?, JE M'EXPLIQUE  !!!!! :
(t'inquiètes pas c'est pas long et l'exemple est simple, prends une feuille et un crayon au cas mes explications ne soient pas assez claires).

En tenant compte qu'on est dans un repère direct orthonormé oxyz.

Notons 6 sommets Vi, i c [0..5] :
V0=(0.0,0.0,0.0)
V1=(1.0,0.0,0.0)
V2=(1.0,0.0,1.0)
V3=(0.0,1.0,1.0)
V4=(0.0,0.0,1.0)
V5=(0.0,1.0,0.0)

Notons 5 faces triangulaires (en CCW)
Fj(Vi0,Vi1,Vi2), j c [0..4].
Vik, k c [0..2] un des sommets précedents.
et leurs normales NFj(X,Y,Z).
F0(0,1,2)      ->     NF0(0.0,-1.0,0.0)
F1(0,2,4)      ->     NF1(0.0,-1.0,0.0)
F2(0,5,1)      ->     NF2(0.0,0.0,-1.0)
F3(0,3,5)      ->     NF3(-1.0,0.0,0.0)
F4(0,4,3)      ->     NF4(-1.0,0.0,0.0)

Dans le plan oxz on a :

z
|                            
V4......................V2  
|                    .     .                     NF0 et NF1 pointent vers
|               .          .                     toi.
|  F1    .               .          
|     .                    .    
| .            F0        .              
V0------------------V1--x
o

Dans le plan oxy on a :

y
|                            
V5  .
|        .                                       NF2 pointe vers l'ecran
|            .                                  
|    F2         .                  
|                      .        
|                          .              
V0------------------V1--x
o

Dans le plan oyz on a :

z
|                            
V4......................V3  
|                    .     .                     NF3 et NF4 pointent vers
|               .          .                     l'ecran.
|  F4    .               .          
|     .                    .    
| .            F3        .              
V0------------------V5--y
o

Calculons maintenant la normale au sommet V0 (qui participe à toutes les faces), si tu visualises bien l'exemple, tu seras d'accord pour dire que la normale a trouvé est NV0=(-1.0,-1.0,-1.0).

Par la moyenne des faces on trouve donc :
NV0=(NF0+NF1+NF2+NF3+NF4)/5=(-2/5,-2/5,-1/5).
Donc ca ne marche pas....

Par la méthode que j'explique (que je tente d'expliquer...)
Notons les angles du sommet V0 dans chaque face Fi
par AV0i l'angle dans la face i
(par exemple AV00 =angle entre V0V1 et V0V2).
AV00=PI/4
AV01=PI/4
AV02=PI/2
AV03=PI/4
AV04=PI/4
avec une moyenne des normales aux faces pondérées par ces angles on a
NV0=NF0*AV00+NF1*AV01+NF2*AV02+NF3*AV03+NF4*AV04=(-2.0*PI/4 , -1.0*PI/2 , -2.0*PI/4)=
(-1.0,-1.0,-1.0) apres normalisation.

J'espère que j'ai été clair et que cela puisse t'aider.

@+, KeniiyK.




Commentaire de KeniiyK le 02/03/2005 18:35:16

Histoire d'être sur de ne pas laisser des trucs en suspend :
Pour calculer les angles :
pour AV00 par exemple, tu prends les vecteurs V0V1 et V0V2 normalisés puis acos(V0V1.V0V2) . étant le Dot Product. Sachant aussi qu'en C/C++, les fonctions trigos cos, sin, acos etc... bossent en radians.

Et pour finir, saches qu'au niveau mathématique, la moyenne "de base" (non pondérée) à un "coefficient de robustesse" de 0.5 c'est à dire qu'elle peut aussi bien donner le bon résultat qu'un mauvais résultat.

 Ajouter un commentaire




Nos sponsors


Sondage...

Comparez les prix

CalendriCode

Mai 2012
LMMJVSD
 123456
78910111213
14151617181920
21222324252627
28293031   

Consulter la suite du CalendriCode

A découvrir



 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 1,030 sec (4)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales