Bonjour à toutes et à tous
Je poste dans cette section "jeux" car cela me parait le plus adapté au vu de mon problème, qui concerne la 3D.
Je développe un logiciel en python et je souhaite afficher des points 3D (plusieurs dizaines milliers). Pour simplifier et comprendre le fonctionnement je pars de 9 points seulement dont les coordonnées forment un cube en 3D (plus un 9eme point point pile poil au centre du cube). Cela m'aide à visualiser.
J'ai lu pas mal à droite et à gauche (y compris sur ce forum) et j'ai découvert les fameuses matrices qui permettent d'effectuer les transformations requises. Cependant, je ne parviens pas à obtenir le résultat souhaité.
Je vais décrire pas à pas mon problème, pour que vous puissiez me dire les erreurs de raisonnement car je ne suis pas sûre de ce que je fais ...
J'utilise numpy pour les calculs matriciels. La seule chose que j'utilise de la librairie graphique sous jacente à mon programme est l'affichage de points sur l'écran. Je ne peux pas vraiment poster de code car la partie affichage de mon programme est isolée de tous ces calculs, et cela ne pourra pas fonctionner chez vous.
1. Si je veux afficher mon cube je dois le projeter sur l'écran 2D. Si j'affiche bêtement x,y cela me donne un carré (logique, projection sur un plan perpendiculaire à mon axe z).
Les coordonnées de mes points sont définies dans mon repère de référence, qui est censé être fixe.
2. Si je veux faire une rotation de mon cube, cela revient à modifier les coordonnées x,y,z de chaque point du cube dans le repère de référence via les matrices de rotation (celles que l'on trouve partout sur le net).
Ensuite, j affiche bêtement x,y et cela me donne un bon résultat, on voit que le cube a pivoté. Je vois donc mon cube pivoté projeté dans un plan perpendiculaire à mon axe z.
Si je ne fais pas erreur, pour une rotation quelconque je fais la multiplication des 3 matrices (des 3 rotations selon x,y,z) et cela semble encore bien fonctionner.
3. Ensuite, je veux placer ma caméra virtuelle à distance du cube sur l'axe z. Je crée un nouveau cube avec des coordonnées z toutes positives pour simplifier (l'ancien cube était centré sur l'origine). Sur des forums j'ai lu que les gens définissent une nouvelle matrice qui leur sert de caméra. Voici ce que je définis alors:
Pour obtenir la position d'un point dans ce nouveau repère, je multiplie le vecteur point dans le repère de référence avec cette matrice camera.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 matrice_camera = np.array(((1,0,0,0), # correspondance des vecteurs unitaires "espace camera" - "espace monde", modifier ces valeurs cause agrandissement/reduction selon l axe j'ai testé (0,1,0,0), (0,0,1,0), (0,0,0,1))) # position camera dans le repère monde (ici je mets a l'origine)
Ensuite, je veux pouvoir faire pivoter ma camera partout autours du cube. Je dois donc modifier la dernière ligne de ma matrice pour placer la caméra en un point quelconque. Puis je dois appliquer les matrices de rotation a ma matrice de camera. Donc si je ne me trompe pas, c'est une translation plus des rotations. J'ai ceci :
Qu 1 : Est ce que je me trompe si je dis que les points x2,y2,z2 sont bien les points de mon cube dans le repère de la caméra ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 m1, m2, m3 = matRx(self.a1), matRy(self.a2), matRz(self.a3) # les fonctions matRx etc retournent les matrices de rotation, a1 etc sont 3 angles de rotation de ma classe mcampivotee = matrice_camera.dot(m1).dot(m2).dot(m3) # application successive des 3 rotations for x,y,z in liste_points: v = point(x,y,z) x2,y2,z2,_ = v.dot(mcampivotee)
4. Si je modifie ma matrice caméra de sorte que la dernière ligne de la matrice soit la position du centre du cube (chez moi c'est 0,0,400) alors je constate un premier problème qui est que les valeurs z de mes points sont encore plus éloignées de la caméra qu'elles ne l'étaient avant !!!
Qu 2 : Est ce que je dois faire mes coordonnées en négatif pour effectuer la translation correctement ? Avec des coordonnées en négatif cela semble mieux (0,0,-400). Par contre je dois tjrs filtrer selon la valeur de z avant d'afficher pour éviter que des points derrière la caméra ne se trouvent projetés.
5. Si vous m'avez supportée jusque là :-) il me reste à faire de la perspective et à projeter correctement (pas simplement afficher x et y). Là, j'ai trouvé sur le net plein de variantes de cette matrice de perspective. Que me faut il faire ?
Qu 3 : Après application d'une matrice de projection je suis bien censée obtenir systematiquement un z à 0 ? Sinon je ne comprends plus.
J'en ai essayé plusieurs, la dernière étant (mon code ici n'est pas glam ...) Ne vous embêtez pas avec ce bout de code je pense que le problème est dans mon raisonnement, pas dans la matrice :
Avec ça je n'y arrive pas ... J'obtiens n'importe quoi.
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
17
18
19
20
21
22
23
24
25
26
27 def matProjPersp(fov, near, far, asp): #asp=ratio : ratio de la fenetre (la largeur de la fenetre divisee par sa hauteur) #angle : angle de vue de la camera (70° pour un oeil humain) #near : distance la plus proche de la camera qu'il faut afficher #far : distance la plus eloignee de la camera qu'il faut afficher n = near f = far t = n * radians(fov/2) b = -t r = t * asp l = -r m11 = (2*n)/(r-l) m13 = (r+l)/(r-l) m22 = (2*n)/(t-b) m23 = (t+b)/(t-b) m33 = -((f+n)/(f-n)) m34 = -((2*f*n)/(f-n)) m43 = -1 return np.array(((m11,0,m13,0), (0,m22,m23,0), (0,0,m33,m34), (0,0,m43,0)))
Pour moi la valeur de far doit être placée plus ou moins loin (axe z) derrière les derniers points à afficher. La valeur near à l'inverse, devant le plus proche des points à afficher.
Pour la valeur de ratio j'ai mis 1 (pour le moment), et un angle j'ai joué avec, genre 90 voire 180 degrés.
J'ai testé une autre matrice plus naïve (elle ne gère pas les paramètres near, far, angle, ratio) que j'ai trouvé sur Internet :
Le résultat après application est assez nul, c'est la même chose qu'avant, je n'arrive pas à obtenir des arêtes de cube de taille différente entre l'avant (proche) et l'arrière (loin). Pire ... quand j'appuie sur mes touches pour modifier doucement les angles de rotation de ma caméra j'ai des points qui reculent vers l'arrière qui disparaissent ... il doit y avoir des inversions de signe ...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 # matrice projection perspective (elle est appelée ainsi ...) return np.array(((1,0,0,0), (0,1,0,0), (0,0,0,1/f), #cette valeur f est une sorte de distance focale (0,0,0,1)))
Est ce que le raisonnement est correct :
1. définition matrice de caméra
2. translation PUIS rotation de cette matrice de caméra
3. projection perspective (avec quelle matrice ?)
4. affichage des coordonnées x,y (z=0) retournées suite au calcul - et comment filtrer les valeurs négatives ?
Je galère depuis quelques jours, je suis capable de créer et multiplier des matrices mais je ne comprends pas toutes les maths derrière ...
Merci d'avance !
EDIT: Il y avait un souci dans l'affichage de l'axe Y (en raison du système de coordonnées de l'écran). Cependant j'ai tjrs mes problèmes de perspectives.
J'ai fais quelques essais ce soir, en ajoutant un second cube et voilà ce que ça me donne ... les deux cubes (seuls les points sont affichés) font la même taille, et l'un d'entre eux est en avant par rapport à la caméra. Il y a un problème.
Partager