CALCUL DES NORMALES D'UN OBJET 3D

shenron666 Messages postés 229 Date d'inscription dimanche 14 septembre 2003 Statut Membre Dernière intervention 20 août 2014 - 23 févr. 2005 à 15:59
KeniiyK Messages postés 326 Date d'inscription vendredi 13 août 2004 Statut Membre Dernière intervention 2 novembre 2007 - 2 mars 2005 à 18:35
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/29723-calcul-des-normales-d-un-objet-3d

KeniiyK Messages postés 326 Date d'inscription vendredi 13 août 2004 Statut Membre Dernière intervention 2 novembre 2007 2
2 mars 2005 à 18:35
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.
KeniiyK Messages postés 326 Date d'inscription vendredi 13 août 2004 Statut Membre Dernière intervention 2 novembre 2007 2
2 mars 2005 à 18:11
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.
cs_erazor Messages postés 85 Date d'inscription jeudi 7 février 2002 Statut Membre Dernière intervention 8 février 2007
2 mars 2005 à 16:08
"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??
cs_erazor Messages postés 85 Date d'inscription jeudi 7 février 2002 Statut Membre Dernière intervention 8 février 2007
2 mars 2005 à 16:07
"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??
KeniiyK Messages postés 326 Date d'inscription vendredi 13 août 2004 Statut Membre Dernière intervention 2 novembre 2007 2
2 mars 2005 à 12:49
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.
shenron666 Messages postés 229 Date d'inscription dimanche 14 septembre 2003 Statut Membre Dernière intervention 20 août 2014
24 févr. 2005 à 14:05
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 ;-)
cs_erazor Messages postés 85 Date d'inscription jeudi 7 février 2002 Statut Membre Dernière intervention 8 février 2007
24 févr. 2005 à 12:15
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".
shenron666 Messages postés 229 Date d'inscription dimanche 14 septembre 2003 Statut Membre Dernière intervention 20 août 2014
23 févr. 2005 à 15: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 ?
Rejoignez-nous