Bonjour à toutes et à tous.
J'avance dans ma prise en main de Processing.
J'ai commencé un projet pour mettre mes connaissances à l'épreuve. J'avais déja posté une question ici : http://codelab.fr/4018#p21462
J'avance donc et j'arrive à une deuxième étape : me déplacer autour de l'objet. La c'est plus un problème de mathématiques (trigonométrie) que de programmation auquel je me confronte.
J'ai simplifié le code du post cité ci dessus pour n'avoir qu'un cube au centre de ma fenêtre, ça me permet de me concentrer sur la problématique de la caméra. J'affiche donc un cube. La sphère au milieu du cube matérialise le centre de la scène. C'est ici que je place le cube et le point fixé par ma caméra.
Je souhaite pouvoir bouger la caméra dans l'espace avec la souris :
- avec un gauche droit et déplacement horizontal : je tourne autour du cube de droite à gauche.
- avec un gauche droit et déplacement vertical : je tourne autour du cube de haut en bas.
- avec un clic droit et déplacement vertical : je zoome et dézoome.
voila ce que j'obtiens :
int cubeSize = 150; int winSizeX = 640; int winSizeY = 480; //center int cx = winSizeX/2; int cy = winSizeY/2; int cz = -cubeSize/2; //camera positions float camEyeX = 0; float camEyeY = 0; float camEyeZ = 0; float viewX = cx; float viewY = cy; float viewZ = cz; float camUpX = 0; float camUpY = 1; float camUpZ = 0; //Polar coordinates float theta = 90; float phi = 0; float rho = 200; //distance from cam to point of view void setup(){ size(winSizeX,winSizeY, P3D); lights(); } void draw(){ background(0); stroke(255); noFill(); updateCamPosition(); camera(camEyeX,camEyeY,camEyeZ,viewX,viewY,viewZ,camUpX,camUpY,camUpZ); translate(cx,cy,cz); sphere(2); box(cubeSize); } void updateCamPosition(){ camEyeX = rho * sin(radians(theta)) * sin(radians(phi)); camEyeY = rho * cos(radians(theta)); camEyeZ = rho * sin(radians(theta)) * cos(radians(phi)); } void mouseDragged(){ if (mouseButton == LEFT){ theta = theta + (pmouseY - mouseY); phi = phi - (pmouseX - mouseX); } if (mouseButton == RIGHT){ rho = rho - (pmouseY - mouseY); } }
Mais au final les déplacement sont très chaotiques !
Je dois avoir un pb dans la gestion des coordonnées mais je ne trouve pas la faille.
Si quelqu'un peut me venir en aide ?
PS : au cours de mes "révisions" de trigo, je m'apperçois que la norme concernant les coordonnées polaires à un axe Z vers le haut. Est-ce le cas dans Processing ?
Dernière modification par Marty (2013-02-22 18:09:03)
Hors ligne
Moi quand je veux me déplacer en caméra 3d, j'ai recours a ça : http://gdsstudios.com/processing/libraries/ocd/
C'est une librairie qui gère le déplacement de la caméra 3d, très utile
Dernière modification par cgiles (2013-02-23 08:38:19)
Hors ligne
Merci pour l'info,
J'ai déja scruté des solutions via des librairies. Il existe aussi PEasyCam qui fait le boulot.
Mais la comme je débute j'aimerais essayer de construire quelque chose en passant le moins possible par les librairies externes histoire de savoir ce que je fais. Une fois que je "maitriserai" quelques règles je pourais me passer de réinventer la roue...
Dans l'exemple donné je pense avoir bon mais ca marche pas comme escompté...
Hors ligne
Bon j'ai repéré le problème, il s'agit d'un problème de repère d'origine.
Dans mon premier post je décale l'origine par un translate() pour me positionner au milieu de la fenêtre et c'est cela qui semble coincer. Si je dessine tout au point de coordonnées (0,0,0) cela fonctionne.
PS : au passage j'ai corrigé les calculs des coordonnées de rotation de la caméra pour les faire correspondre à un axe XY dans le plan de l'écran et Z en profondeur. Les calculs que j'ai trouvé sont habituellement faits pour un repère YZX.
Le code est donc maintenant comme suit. Si quelqu'un peut m'expliquer l'erreur commise sur le translate() ?
int cubeSize = 150; int winSizeX = 640; int winSizeY = 480; //center int cx = winSizeX/2; int cy = winSizeY/2; int cz = -cubeSize/2; //camera positions float camEyeX = 0; float camEyeY = 0; float camEyeZ = 0; float viewX = 0; float viewY = 0; float viewZ = 0; float camUpX = 0; float camUpY = 1; float camUpZ = 0; //Polar coordinates float theta = 90; float phi = 0; float rho = 350; //distance from cam to point of view void setup(){ size(winSizeX,winSizeY, P3D); } void draw(){ background(0); stroke(255); noFill(); updateCamPosition(); camera(camEyeX,camEyeY,camEyeZ,viewX,viewY,viewZ,camUpX,camUpY,camUpZ); //translate(cx,cy,cz); sphere(2); box(cubeSize); } void updateCamPosition(){ camEyeX = rho * cos(radians(theta)) * cos(radians(phi)); camEyeY = rho * sin(radians(theta)); camEyeZ = rho * cos(radians(theta)) * sin(radians(phi)); } void mouseDragged(){ if (mouseButton == LEFT){ theta = theta + (pmouseY - mouseY); phi = phi - (pmouseX - mouseX); } if (mouseButton == RIGHT){ rho = rho - (pmouseY - mouseY); } }
Hors ligne
Voici une tentative d'explication :
int cubeSize = 150; int winSizeX = 640; int winSizeY = 480; //center int cx = winSizeX/2; int cy = winSizeY/2; int cz = 0; //camera positions float camEyeX = 0; float camEyeY = 0; float camEyeZ = 0; float viewX = cx; float viewY = cy; float viewZ = cz; float camUpX = 0; float camUpY = 1; float camUpZ = 0; //Polar coordinates float theta = 90; float phi = 0; float rho = 350; //distance from cam to point of view void setup() { size(winSizeX, winSizeY, P3D); } void draw() { background(0); stroke(255); noFill(); updateCamPosition(); camera(camEyeX, camEyeY, camEyeZ, viewX, viewY, viewZ, camUpX, camUpY, camUpZ); translate(cx, cy, cz); sphere(2); box(cubeSize); } void updateCamPosition() { camEyeX = rho * cos(radians(theta)) * cos(radians(phi)) + cx; camEyeY = rho * sin(radians(theta)) + cy; camEyeZ = rho * cos(radians(theta)) * sin(radians(phi)); } void mouseDragged() { if (mouseButton == LEFT) { theta = theta + (pmouseY - mouseY); phi = phi - (pmouseX - mouseX); } if (mouseButton == RIGHT) { rho = rho - (pmouseY - mouseY); } }
Mettre la coordonnée cz du centre à 0
Pointer la caméra sur le centre
Remettre le translate de l'objet
Translater la caméra dans le calcul des nouvelles coordonnées de celle-ci. En fait, le calcul des cooordonnées s'effectuaient autour du point zéro
Dis moi si cela fonctionne car un bug pour la version Mac m'empêche de tourner et de zoomer.
Dernière modification par Mushussu (2013-02-24 11:02:57)
Hors ligne
Merci Mushussu,
ça fonctionne effecivement, mais je ne comprend pas pourquoi dans mon exemple les coordonnées s'effectuent autour du point zéro ?
Le point de vue de la caméra est bien fixée à cx, cy, cz du coup la rotation de la caméra devrait se faire autour de ce point non ?
Dernière modification par Marty (2013-02-24 16:00:12)
Hors ligne
En fait tu entres dans la fonction caméra ses coordonnées en premier par rapport au point zéro. Donc comme les objet 3D ont comme origine le point zéro tout se passait bien.
Imagine une caméra réelle dans une pièce avec un rail de travelling circulaire. Si l'objet est au centre du cercle et que la caméra vise l'objet. Alors la caméra tournera autour de l'objet comme souhaité. Mais si l'objet est en dehors du cercle, bien que la caméra vise l'objet tu ne pourras pas tourner autour de l'objet. Il faut réaliser un changement d'origine.
Hors ligne
ok je vois mieux maintenant.
Du coup moi je faisais une translation pour mettre mon objet au centre de l'écran... mais avec une caméra cela devient inutile non ?
Ok donc pour cette problématique j'ai saisi. Maintenant ce n'était qu'un prototype simple pour "pratiquer" un peu la caméra. L'étape suivante c'est de remplacer le cube qui ne sera non pas un cube simple, mais composite : un cube formé par un ensemble de spheres (64 au total) qui me fera dont un cube de 4x4x4 sphères (cf mon premier post dans ce fil qui renvoie vers un autre post qui explique cela).
Par choix (la position des sphères doit correspondre à un modèle physique représenté aujourd'hui par un cube de leds mais qui sera à terme une structure plus importante), je construit le cube en commençant par la sphère en bas à gauche sur le plan le plus proche de la caméra, le comptage commence sur la profondeur (axe Z), puis en X et enfin en Y. (j'espère que tout cela est relativement clair !)
Le tout est construit à partir de l'origine (0,0,0).
Si je suis tes indications il faut donc décaler l'origine du point de vue de la caméra vers le centre de la structure et déplacer aussi la caméra en conséquence ?
petite illustration de ce que ça commence à donner ci-dessous".
A noter :
- pour des questions de performances de ma carte graphique j'ai remplacé les sphères par des cubes
- les cubes colorés représentent la face avant du cube avec le cube blanc = premier cube en bas à gauche quand on regarde le cube de face.
- pour m'aider visuellement j'ai représenté les axes : X (vert), Y (bleu), Z (rouge)
PS : déja je note un pb de placement de la caméra...
Led[] ledCube = new Led[64]; int cubeSize = 150; int wWidth = 640; int wHeight = 480; //center //int cx = wWidth/2; //int cy = wHeight/2; //int cz = -cubeSize/2; //camera positions float camEyeX = 0; float camEyeY = 0; float camEyeZ = 0; float viewX = 0; float viewY = 0; float viewZ = 0; float camUpX = 0; float camUpY = 1; float camUpZ = 0; //Polar coordinates float theta = 90; float phi = 0; float rho = 300; //distance from cam to point of view void setup(){ int c = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { for (int k = 0; k < 4; k++) { ledCube[c] = new Led(j, -i, -k, false, 120); c++; } } } size(wWidth,wHeight, P3D); } void draw(){ background(0); pointLight(150,255,255,200,200,200); noLights(); noStroke(); noSmooth(); fill(160); drawAxis(); updateCamPosition(); camera(camEyeX,camEyeY,camEyeZ,viewX,viewY,viewZ,camUpX,camUpY,camUpZ); drawCube(); } class Led { int x; int y; int z; boolean isOn; color bColor; Led (int xPos, int yPos, int zPos, boolean state, color col) { x = xPos; y = yPos; z = zPos; isOn = state; bColor = col; } void display() { pushMatrix(); translate(x * (cubeSize / 3), y * (cubeSize / 3), z * (cubeSize / 3)); fill(bColor); box(3); popMatrix(); } } void drawAxis(){ stroke(0,255,0); line(0,0,0,100,0,0); stroke(0,0,255); line(0,0,0,0,100,0); stroke(255,0,0); line(0,0,0,0,0,-100); noStroke(); } void drawCube() { for (int i = 0; i < 64; i++) { switch (i) { case 0 : ledCube[i].bColor = color(255,255,255); break; case 12 : ledCube[i].bColor = color(255,0,0); break; case 48 : ledCube[i].bColor = color(0,255,0); break; case 60 : ledCube[i].bColor = color(0,0,255); break; } ledCube[i].display(); } } void updateCamPosition(){ camEyeX = rho * cos(radians(theta)) * cos(radians(phi)); camEyeY = rho * sin(radians(theta)); camEyeZ = rho * cos(radians(theta)) * sin(radians(phi)); //Prevent flipping if camera moves past top or bottom of cube if ((theta > 90.0 && theta < 270.0) || (theta < -90.0 && theta > -270.0)) { camUpY = -1.0; } else { camUpY = 1.0; } } void mouseDragged(){ if (mouseButton == LEFT){ theta = theta + (pmouseY - mouseY); phi = phi - (pmouseX - mouseX); } if (mouseButton == RIGHT){ rho = rho - (pmouseY - mouseY); } }
Dernière modification par Marty (2013-02-24 19:41:52)
Hors ligne
Oui, ou bien centrer la structure autour du point zéro :
void display() { pushMatrix(); translate(x * (cubeSize / 3) - cubeSize / 2, y * (cubeSize / 3) + cubeSize / 2, z * (cubeSize / 3) + cubeSize / 2); fill(bColor); box(3); popMatrix(); }
Hors ligne
Je vois.
Pour une solution de changement d'axe plutôt que centrer la structure ça te semble juste ?
void draw() { background(0); pointLight(150, 255, 255, 200, 200, 200); noLights(); noStroke(); noSmooth(); fill(160); drawAxis(); updateCamPosition(); camera(camEyeX, camEyeY, camEyeZ, viewX, viewY, viewZ, camUpX, camUpY, camUpZ); translate(-(cubeSize / 2), (cubeSize / 2), (cubeSize / 2)); drawCube(); }
Par contre dans mon idée j'étais censé avoir comme point de vue de départ la face avec les angles matérialisés en couleur (plan XY). J'ai décidément un problème de repère dans l'espace !!
Et aussi pourquoi l'écran reste noir tant qu'il n'y a aucun mouvement de caméra ? Je n'arrive pas à corriger ça
Merci encore pour tes conseils...
Hors ligne
Il n'y a pas de bonne méthode pour centrer autour du point zéro, il y a celle que tu trouves la plus adéquate à ton projet.
Pour le départ, il faut changer l'initialisation des angles :
//Polar coordinates float theta = 0; float phi = 90; float rho = 300; //distance from cam to point of view
En plus cela règle le problème d'affichage du départ.
Hors ligne
Oui évidement, c'était trop simple pour le voir
En fait je pensais à un pb d'affichage, mais c'est simplement la caméra qui pointait dans le vide...
Merci encore pour le temps que tu as pris et pour tes conseils.
...étape suivante... !
Hors ligne
Correction de bug, lorsque theta = 90 il y a une absence de rendu :
//Polar coordinates float theta = 0.01; float phi = 90; float rho = 300; //distance from cam to point of view
Hors ligne
Ah oui ! donc en fait c'était bien un bug !
Mais ça doit être un bug dans mon code, je doute que ce soit processing...
Hors ligne
Je regardais votre code et je me suis dit que ça pourrait vous intéresser : http://wiki.processing.org/w/Wheel_mouse
c'est pour utiliser la roulette de la souris dans processing, et ainsi libéré le clic droit, pour une réinitialisation de la cam ou un mouvement de travelling...
Hors ligne