Rotation d'un carré sur un ecran lcd graphique

Bonjour, je suis en train d'essayer de coder un cube 3d qui tournerais sur mon ecran lcd graphique.

Pour le moment je galére un peu, j'essai pour le moment d'afficher un carré a l'ecran et de le faire tourner par son centre.

J'utilise une arduino uno et un afficheur ST7565.

Je souhaiterais avoir un avis sur les methodes pour arriver au résultat.

J'ai essayé de coder en m'inspirant de cette page:

Voici mon code pour le moment, Non fonctionnel:

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <ST7565_LCD.h>
 
// ST7565 LCD connection with Arduino board using software SPI
#define LCD_DIN    9
#define LCD_SCLK   8
#define LCD_A0     7
#define LCD_RESET  6
#define LCD_CS     5
ST7565_LCD display = ST7565_LCD(LCD_DIN, LCD_SCLK, LCD_A0, LCD_RESET, LCD_CS);
 
/*/ Comment out above, uncomment this block to use hardware SPI
// connect LCD 'DIN' & 'SCLK' to board's hardware SPI pins
#define LCD_A0     7
#define LCD_RESET  6
#define LCD_CS     5
ST7565 display = ST7565(LCD_A0, LCD_RESET, LCD_CS);
*/

 
 
void setup()   {                
  Serial.begin(9600);
 
  // initialize the ST7565 LCD display with contrast = 13 (0 <= coontrast <= 63)
  display.begin(13);
 


}
 //coordonnées du carré
  double tab_coor_xy[4][2]={
    {-20,20},
    {20,20},
    {20,-20},
    {-20,-20}
  };


//coordonées du carré apres decalage
  double tab2_coor_xy[4][2]={
    {0,0},
    {0,0},
    {0,0},
    {0,0}
  };



void loop() {



  draw();
  delay(1000);

  int i=0;
  for (int i=0; i<360; i++){
     rotation(i);
      draw();
     delay(100);
  }


}








void rotation(int degres){

  double sinTheta = sin(degres);
  double cosTheta = cos(degres);


  tab_coor_xy[0][0] = (tab_coor_xy[0][0] * cosTheta) - (tab_coor_xy[0][1] * sinTheta) ; Serial.print(" x:");Serial.println( tab_coor_xy[0][0]);
  tab_coor_xy[0][1] = (tab_coor_xy[0][1] * cosTheta) + (tab_coor_xy[0][0] * sinTheta) ; Serial.print(" y:");Serial.println( tab_coor_xy[0][1]);

  tab_coor_xy[1][0] = (tab_coor_xy[1][0] * cosTheta) - (tab_coor_xy[1][1] * sinTheta) ; 
  tab_coor_xy[1][1] = (tab_coor_xy[1][1] * cosTheta) + (tab_coor_xy[1][0] * sinTheta) ; 

  tab_coor_xy[2][0] = (tab_coor_xy[2][0] * cosTheta) - (tab_coor_xy[2][1] * sinTheta) ; 
  tab_coor_xy[2][1] = (tab_coor_xy[2][1] * cosTheta) + (tab_coor_xy[2][0] * sinTheta) ;

  tab_coor_xy[3][0] = (tab_coor_xy[3][0] * cosTheta) - (tab_coor_xy[3][1] * sinTheta) ; 
  tab_coor_xy[3][1] = (tab_coor_xy[3][1] * cosTheta) + (tab_coor_xy[3][0] * sinTheta) ; 


}







void draw(){
 
  //decalage des abscises et ordonées au centre de l'ecran

  tab2_coor_xy[0][0] = tab_coor_xy[0][0] + 64; 
  tab2_coor_xy[0][1] = tab_coor_xy[0][1] + 32; //Serial.println( tab_coor_xy[0][1]);

  tab2_coor_xy[1][0] = tab_coor_xy[1][0] + 64;
  tab2_coor_xy[1][1] = tab_coor_xy[1][1] + 32;

  tab2_coor_xy[2][0] = tab_coor_xy[2][0] + 64;
  tab2_coor_xy[2][1] = tab_coor_xy[2][1] + 32;

  tab2_coor_xy[3][0] = tab_coor_xy[3][0] + 64;
  tab2_coor_xy[3][1] = tab_coor_xy[3][1] + 32;




  display.clearDisplay();
  display.drawLine(0, 0,0 ,0 , ST7565_ON); //affiche un point

  display.drawLine(tab2_coor_xy[0][0], tab2_coor_xy[0][1],tab2_coor_xy[1][0] ,tab2_coor_xy[1][1] , ST7565_ON);
  display.display(); // Update screen with each newly-drawn line
  
  display.drawLine(tab2_coor_xy[1][0], tab2_coor_xy[1][1],tab2_coor_xy[2][0] ,tab2_coor_xy[2][1] , ST7565_ON);
  display.display(); // Update screen with each newly-drawn line
  
  display.drawLine(tab2_coor_xy[2][0], tab2_coor_xy[2][1],tab2_coor_xy[3][0] ,tab2_coor_xy[3][1] , ST7565_ON);
  display.display(); // Update screen with each newly-drawn line
  
  display.drawLine(tab2_coor_xy[3][0], tab2_coor_xy[3][1],tab2_coor_xy[0][0] ,tab2_coor_xy[0][1] , ST7565_ON);
  display.display(); // Update screen with each newly-drawn line
  

}
 

Que voyez vous sur votre écran ?

Pour faire tourner votre cube vous donnez des coordonnées en 3D aux sommets (8 points donc) puis appliquez une matrice de rotation à ces points. Ensuite vous faites une projection sur un plan orthogonal à la caméra (votre point de vue), plan étant plus ou moins loin en fonction de votre choix.
Il ne reste plus qu’à relier les points

Tout cela c’est du calcul matriciel - est-ce que vous maîtrisez cela ?

Ce que je vois sur mon afficheur c'est un carré qui est au centre mais la rotation n'a pas l'air de fonctionner, je n'utilise pas de matrice, juste un tableau a 2 dimensions qui contients les coordonées x,y de chaque angles du carré. (soit 4 pour un carré en 2 dimensions)

J'ai deja utilisé des matrices de convolution en php mais je pense que s'est pas exactement pareil.

Pour le moment je vois petit car je me contente d'essayer de faire une rotation d'un carré.

L'idéal serais que j'ai un exemple.

J'ai fait une petite vidéo de ce que sa donne:

https://www.youtube.com/shorts/088zc2cTWdk?feature=share

Je viens de trouver sa :slight_smile:

Je vais essayer d'adapter le code

Donc vous avez un carré sur un plan (l’ecran), de coté D, centré en (x,y) que vous voulez faire tourner d’un angle A (en radian ou degrés?) par rapport à son centre.

C’est ça ?

Quelle formule utilisez vous pour calculer la position des sommets ?

Je parts de ceci:

 //coordonnées du carré
  double tab_coor_xy[4][2]={
    {-20,20}, 
    {20,20},
    {20,-20},
    {-20,-20}
  };

Une des difficultées est que l'afficheur a son centre x,y en haut a gauche, comme sur la pluparts des afficheurs. Mon afficheur est un 64 x 128 pixels.

Un changement de repère (translation) une rotation et une translation inverse.

De mon temps on faisait ça en seconde

pour afficher une ligne c'est facile:

 display.drawLine(x, y, x1 ,y1 , ST7565_ON);
  display.display(); 

Il faut écrire les équations

Pour une rotation dans un espace 3D, les matrices ne vont pas suffire. Il faut utiliser des quaternions.
Le bagage mathématique nécessaire peut s'avérer un vrai obstacle...

Je ne comprends pas bien pourquoi une matrice ou des projections ne vont pas suffire ?
Ca fait longtemps que je n'ai pas fait de rendu 3D puisque ça devait être sur un 80286, mais cela fonctionnait très bien avec du rendu fil de fer ou plein, enfin tout est relatif :slight_smile:

non pas pour une rotation / projection simple

Bon voila j'ai reussi a faire la rotation du carré, j'avais fait une erreur dans mon code.

Voila le resultat:

Je vais essayer de poursuivre pour faire un cube, si quelqu'un a des idées:

Voici le code:

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <ST7565_LCD.h>
 
// ST7565 LCD connection with Arduino board using software SPI
#define LCD_DIN    9
#define LCD_SCLK   8
#define LCD_A0     7
#define LCD_RESET  6
#define LCD_CS     5
ST7565_LCD display = ST7565_LCD(LCD_DIN, LCD_SCLK, LCD_A0, LCD_RESET, LCD_CS);
 
/*/ Comment out above, uncomment this block to use hardware SPI
// connect LCD 'DIN' & 'SCLK' to board's hardware SPI pins
#define LCD_A0     7
#define LCD_RESET  6
#define LCD_CS     5
ST7565 display = ST7565(LCD_A0, LCD_RESET, LCD_CS);
*/

 
 
void setup()   {                
  Serial.begin(9600);
 
  // initialize the ST7565 LCD display with contrast = 13 (0 <= coontrast <= 63)
  display.begin(13);
 


}
 //coordonnées du carré
  double tab_coor_xy[4][2]={
    {-20,20},
    {20,20},
    {20,-20},
    {-20,-20}
  };

//coordonées du carré apres rotation
  double tab_coor_xy_bis[4][2]={
    {0,0},
    {0,0},
    {0,0},
    {0,0}
  };



//coordonées du carré apres decalage
  double tab2_coor_xy[4][2]={
    {0,0},
    {0,0},
    {0,0},
    {0,0}
  };



void loop() {



  

  
  for (double i=0; i<3600; i++){
     rotation(i/10);
      draw();
     delay(10);
  }


}








void rotation(double degres){

  double sinTheta = sin(degres);
  double cosTheta = cos(degres);


  tab_coor_xy_bis[0][0] = (tab_coor_xy[0][0] * cosTheta) - (tab_coor_xy[0][1] * sinTheta) ; Serial.print(" x:");Serial.println( tab_coor_xy[0][0]);
  tab_coor_xy_bis[0][1] = (tab_coor_xy[0][1] * cosTheta) + (tab_coor_xy[0][0] * sinTheta) ; Serial.print(" y:");Serial.println( tab_coor_xy[0][1]);

  tab_coor_xy_bis[1][0] = (tab_coor_xy[1][0] * cosTheta) - (tab_coor_xy[1][1] * sinTheta) ; 
  tab_coor_xy_bis[1][1] = (tab_coor_xy[1][1] * cosTheta) + (tab_coor_xy[1][0] * sinTheta) ; 

  tab_coor_xy_bis[2][0] = (tab_coor_xy[2][0] * cosTheta) - (tab_coor_xy[2][1] * sinTheta) ; 
  tab_coor_xy_bis[2][1] = (tab_coor_xy[2][1] * cosTheta) + (tab_coor_xy[2][0] * sinTheta) ;

  tab_coor_xy_bis[3][0] = (tab_coor_xy[3][0] * cosTheta) - (tab_coor_xy[3][1] * sinTheta) ; 
  tab_coor_xy_bis[3][1] = (tab_coor_xy[3][1] * cosTheta) + (tab_coor_xy[3][0] * sinTheta) ; 


}







void draw(){
 
  //decalage des abscises et ordonées au centre de l'ecran

  tab2_coor_xy[0][0] = tab_coor_xy_bis[0][0] + 64; 
  tab2_coor_xy[0][1] = tab_coor_xy_bis[0][1] + 32; //Serial.println( tab_coor_xy[0][1]);

  tab2_coor_xy[1][0] = tab_coor_xy_bis[1][0] + 64;
  tab2_coor_xy[1][1] = tab_coor_xy_bis[1][1] + 32;

  tab2_coor_xy[2][0] = tab_coor_xy_bis[2][0] + 64;
  tab2_coor_xy[2][1] = tab_coor_xy_bis[2][1] + 32;

  tab2_coor_xy[3][0] = tab_coor_xy_bis[3][0] + 64;
  tab2_coor_xy[3][1] = tab_coor_xy_bis[3][1] + 32;




  display.clearDisplay();
  display.drawLine(0, 0,0 ,0 , ST7565_ON); //affiche un point

  display.drawLine(tab2_coor_xy[0][0], tab2_coor_xy[0][1],tab2_coor_xy[1][0] ,tab2_coor_xy[1][1] , ST7565_ON);
  display.display(); // Update screen with each newly-drawn line
  
  display.drawLine(tab2_coor_xy[1][0], tab2_coor_xy[1][1],tab2_coor_xy[2][0] ,tab2_coor_xy[2][1] , ST7565_ON);
  display.display(); // Update screen with each newly-drawn line
  
  display.drawLine(tab2_coor_xy[2][0], tab2_coor_xy[2][1],tab2_coor_xy[3][0] ,tab2_coor_xy[3][1] , ST7565_ON);
  display.display(); // Update screen with each newly-drawn line
  
  display.drawLine(tab2_coor_xy[3][0], tab2_coor_xy[3][1],tab2_coor_xy[0][0] ,tab2_coor_xy[0][1] , ST7565_ON);
  display.display(); // Update screen with each newly-drawn line
  

}
 

bravo - reste plus qu'à le faire en 3D
(peut être faire qu'un seul display.display(); une fois que toutes les lignes sont tracées)

Je viens de trouver un bug etrange, car je sortais pas de ma boucle principale (while ) 0 a 360 degres

Apparement il me manque des calculs intermediaires.

Pour obtenir le resultat voulu j'avais utilisé une variable qui alait de 0 a 3600 puis je divisé par 10...

J'obtiens une rotation complète en 12 degres seulement.

Y a un bug, je cherche

Bon apparement la fonction sinu et cosinus attendent des radians, la sa marche:

  for (int i=0; i<360; i++){
     rotation(i * 3.14 /180);
      draw();
      Serial.print("angle:");
      Serial.println(i);
     delay(100);
  }

Pour la 3D, il faut combiner plusieurs rotations autour de plusieurs axes. Un lien intéressant

bin faut lire l'article en lien, au moins son début.
Cet article fournit toutes les explications et les formules nécessaires.

C’est le cas général et le problème de la composition.

Dans le cas présent vous n’avez qu’un cube fixe avec une rotation sur un seul axe simple du repère de base (translaté). Il n’y a pas de composition.

On a les coordonnées du cube qui ne changent jamais
On a un angle qui permet de calculer la matrice de rotation
On calcule la nouvelle position pour chaque sommet temporaire
On dessine les arêtes temporaires
Puis on change l’angle et on recommence

Et bin, y'a plus qu'à !