Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • Alexandre.Meyer/m1if37-animation
  • Alexandre.Meyer/m2-apprentissage-profond-image
  • Alexandre.Meyer/m2-animation
  • Alexandre.Meyer/hugo-web-minimal
  • Alexandre.Meyer/lifami
  • Alexandre.Meyer/lifapcd
  • Alexandre.Meyer/www
  • Alexandre.Meyer/lifstage
8 results
Show changes
Showing
with 584 additions and 360 deletions
File added
// Ce corrigé n'utilise pas d'héritage car pas vu en LFIAPCD. Il serait peut-être pratique d'avoir une Class Piece et
// des classes dérivées spécifique pour chaque type de pièce : pion, roi, reine, fou, tour, cavalier avec
// simplement une surcharge de la fonction "coupValide" pour chaque type. Cela éviterait un switch dans le code de "coupValide" de Piece.
// Dans ce corrigé, il y a 3 types IdPiece = TypePiece + Couleur. On pourrait en avoir qu'un en mettant 32 valeurs possibles dans le TypePiece.
Barème approximatif :
### Noyau
- la base : struct Vec2, enum Couleur, enum TypePiece / 2 points
- class Piece : /4 points
- class ConfigurationJeu : /4 points
- class Partie : /2 points
- class DictionnaireParties : /2 points
### IHM
- class JeuTXT : /2 points
- class JeuSDL : /2 points
- class GestionnairePartiesSDL : /2 points
//========================================== NOYAU ==============================================================
struct Vec2 // un struct suffit ici (mais une classe irait aussi)
{
int x,y;
Vec2(int _x, int _y);
static void testRegression() const;
}
Vec2 operator+(Vec2, vec2);
Vec2 operator-(Vec2, vec2);
bool operator==(Vec2 , Vec2 );
enum Couleur { BLANC, NOIR };
// => typedef int IdPiece; // est le minimum à avoir : le numéro de pièce dans le tableau de pièce, -1 si la pièce n'existe pas
// Il est sûrement plus efficace d'avoir un enum (+ un struct IdPiece défini juste avant ConfigurationJeu)
enum TypePiece
{
VIDE=-1,
PION1=0, PION2=1, PION3=2, PION4=3, PION5=4, PION6=5, PION7=6, PION8=7,
ROI=8, REINE=9,
FOU1=10, FOU2=11,
CAVALIER1=12, CAVALIER=13,
TOUR1=14, TOUR2=15
};
// --> Vec, TypePiece, Couleur, IdPiece
class Piece
{
public:
Piece( TypePiece typ, Couleur coul, const Vec2& pos); // Normalement ici, il n'y aura jamis VIDE dans le type
void deplacement(Vec2 dep); // déplace la pièce du vecteur 'dep' : ne fait aucun comtrôle du damier
void prise(); // change la pièce à prise
bool coupValide(const ConfigrationJeu&, Vec2 depl); // un switch qui appelle une des fonctions coupValideXXX où XXX dépend du type de pièce, voir en private
void ecriture(ofstream& f);
void lecture(ofstream& f);
static void testRegression() const;
private:
TypePiece m_type; // type de la pièce(un enum=un int, qui sert également pour accèder à la case du tableau de pièces blanche ou noir de ConfigurationJeu
Couleur m_couleur; // BLANC ou NOIR (normalement ici la valeur PERSONNE n'arrivera jamais). PERSONNE sert pour avoir qui a gagné.
Vec2 m_pos; // Position sur le damier, valide uniquement si le bool m_enJeu est vrai
bool m_enJeu; // Prise ou en jeu
float m_importance; // une estimation empirique de la valeur d'une pièce, indépendament de sa position dans une partie
bool coupValidePion(const ConfigrationJeu&, Vec2 depl);
bool coupValideRoi(const ConfigrationJeu&, Vec2 depl);
bool coupValideReine(const ConfigrationJeu&, Vec2 depl);
bool coupValideFou(const ConfigrationJeu&, Vec2 depl);
bool coupValideCavalier(const ConfigrationJeu&, Vec2 depl);
bool coupValideTour(const ConfigrationJeu&, Vec2 depl);
};
// Avec ce type ou peut représenter toutes les pièces du jeu. Un struct suffit ici (mais une classe irait aussi)
// On aurait aussi pu avoir dans l'enum TypePiece, 32 valeurs avec toutes les pièces possibles 16 blanches+16 noires
struct IdPiece
{
TypePiece type;
Couleur coul;
};
// --> Vec, TypePiece, Couleur, IdPiece, Piece
class ConfigurationJeu
{
ConfigurationJeu(); // Appel init :
void init(); // Place toutes les pièces et range toutes les infos dont identifiant. Appeler au début ou à chaque nouvelle partie
bool coupValide(Vec2 pos, Vec2 depl) const; // indique si un déplacement 'depl' d'une pièce (repéré avec sa position 'pos') est possible
std::vector<Vec2> calculTousLesCoupsPossibles(const Vec2& pos) const; // construit un tableau de tous les déplacement possible pour une pièce
bool jouerCoup(Vec2 pos, Vec2 depl); // joue un coup=déplace la pièce de la case 'pos" vers 'pos+depl' si le coup est possible. Renvoie faux si le coup n'est pas valide
const Piece& getPiece(const Vec2& pos) const; // trouve la pièce à partir de sa position.
bool partieTerminee() const // renvoie vrai si un joueur a gagné
Couleur vainqueur() const; // renvoie NOIR, BLANC. ATTENTION : valide seulement si la partie est terminée, sinon renvoie la couleur qui a le score le plus élevé (voir f ci-dessus et ci-dessous)
float score(Couleur col) const; // renvoie une estimation d'un score d'un joueur, calculé en fonction des pièces prises
float distance(ConfigrationJeu cj); // renvoie un réel indiquant si les deux configurations sont proches : 0 indique indentique, un grand nombre=très différentes
void ecriture(ofstream& f);
void lecture(ofstream& f);
static void testRegression() const;
private:
// Avec juste ces 2 tableaux, on peut tout faire mais pour trouver une pièces à partir d'une position
// il faut parcourir les 2 tableaux de pièces. Pas optimal mais ca marche.
Piece m_piecesB[16]; // toutes les pièces blanches
Piece m_piecesN[16]; // toutes les pièces noires
// On pourrait ajouter un tableau comme ceci
IdPiece m_damier[8][8]; // le damier, chaque case sera soit un TypePiece associé à une couleur
Couleur m_joueurSuivant; // La couleur du joueur qui doit jouer
const Piece& getPiece(IdPiece idp, Couleur col) const; // trouve la pièce à partir de son "nom", par exemple getPiece(FOU1, BLANC);
};
// ================ NOYAU : gestion du dictionnaire de parties ==================
// --> Vec, TypePiece, Couleur, IdPiece, Piece, ConfigrationJeu
// Une unique partie avec toutes les étapes(=ConfigurationJeu)
class Partie
{
public:
Partie();
int nbEtape() const;
const ConfigurationJeu& getIemeEtape(int ) const;
void ajouterEtape(const ConfigrationJeu& cj);
void crop(int debut, int fin); // coupe tous les coups avant debut et après fin
void ecriture(ofstream& f);
void lecture(ofstream& f);
static void testRegression() const;
private:
std::vector<ConfigrationJeu> m_etapes;
};
// --> Vec, TypePiece, Couleur, IdPiece, Piece, ConfigrationJeu, Partie
class DictionnaireParties
{
public:
DictionnaireParties();
int nbPartie() const;
void ajouterPartie(const Partie& part);
void ajouterPartie(const string& fichier);
const Partie& getIemePartie(int ) const;
std::vector<ConfigrationJeu> trouveLesConfigurationsEquivalentes(const ConfigrationJeu& cj);
std::vector<ConfigrationJeu> trouveLesConfigurationsEquivalentesMeilleursScores(const ConfigrationJeu& cj, float scoreMin);
std::vector<Vec2> suggererDesBonsCoups(const ConfigrationJeu& cj);
Vec2 suggererMeilleurCoup(const ConfigrationJeu& cj);
void ecriture(ofstream& f);
void lecture(ofstream& f);
static void testRegression() const;
private:
std::vector<Partie> m_dict;
};
//========================================== AFFICHAGE ==============================================================
// --> Vec, TypePiece, Couleur, IdPiece, Piece, ConfigrationJeu
class JeuTxt
{
public:
JeuTxt();
void boucle();
private:
ConfigurationJeu m_cj;
void affichage() const;
};
// --> Vec, TypePiece, Couleur, IdPiece, Piece, ConfigrationJeu
class JeuSDL
{
public:
JeuSDL();
void boucle();
private:
ConfigurationJeu m_cj;
Image m_damier;
Image m_pieces_blanc[TYPEPIECE_MAX];
Image m_pieces_noir[TYPEPIECE_MAX];
void affichage() const;
Vec2 clicSourie(int mouseX, int mouseY);
};
// --> Vec, TypePiece, Couleur, IdPiece, Piece, ConfigrationJeu, Partie, DictionnaireParties
class GestionDictionnairePartiesSDL
{
public:
GestionDictionnaireSDL();
void boucle();
private:
JeuSDL m_jeu;
DictionnaireParties m_dictParties;
Widget m_ihm;
void affichage() const;
};
File added
web/content/cours/doc/supports_de_cours.jpg

2.79 KiB

---
title: ""
description: "Partie Animation de personnage"
---
# Partie Animation de personnage
* Alexandre Meyer
* 4h30 CM, 6h30 TP
* [L'ancienne page de cette partie](https://perso.liris.cnrs.fr/alexandre.meyer/public_html/www/doku.php?id=charanim_m1#master_1_informatique_-_ue_m1if37_animation_en_synthese_d_image)
![](../doc_charanim/charanim_tpose.jpg)
## Cours
* [Systèmes articulés : cinématique directe](https://perso.liris.cnrs.fr/alexandre.meyer/teaching/master_charanim/aPDF_COURS_M1/M1_1_SkeletonBasedAnimation.pdf)
* [Edition d'animations, Graphe d'animations](https://perso.liris.cnrs.fr/alexandre.meyer/teaching/master_charanim/aPDF_COURS_M1/M1_2_MotionControlAndEditing.pdf)
* [Capture de mouvements](https://perso.liris.cnrs.fr/alexandre.meyer/teaching/master_charanim/aPDF_COURS_M1/M1_3_MotionCapture.pdf)
## Les vidéos des 3 CM (2020)
[Les vidéos](video)
## Le TP
* [TP animation de personnage virtuel](tp)
* [[master_charanim_code|Le code initial]]
#### Rendu
Les archives sont à rendre sur TOMUSS
* TP Animation de personnage virtuel
* vous devez rendre une archive avec un readme.txt ou readme.md expliquant ce que vous avez fait et comment lancer le programme
* une VIDEO de DEMO ou une démo en LIVE
* Barème "Personnage"
* (5 points) TP 1ère partie : affichage d'une animation BVH
* (3 points) Contrôleur d'animation : la base (pilotage au clavier d'un déplacement)
* Machine à état (4 points maximum)
* basique : pour une machine à état de base avec 4 animations : iddle, marcher, courir, sauter ou kick
* avancé : une machine à état plus complète avec de nombreuses animations (une dizaine) : voir celles du répertoire motionGraph_second_life, etc.
* Motion Graphe (6 points max)
* basique : transition vers un autre animation en cherchant à la volée une transition compatible
* avancé : un motion graph construit automatiquement en pré-calcul (voir la fin de l'énoncé qui pointe vers un complément de sujet).
* (3 points) Interpolation entre 2 frames, à utilise pour les transitions ou pour une bonne gestion du temps
* (1 points) Collision entre personnage et sphères (voir le code PhysicalWorld)
* (1 points) bonus de qualité/cohérence de la scène
* Le total fait plus que 20 car les points FSM/graphe d'animation sont à comprendre avec un OU : la machine à état rapporte moins de points, car bien moins difficile.
# TP d'Animation de personnage (M1)
## TP partie 1 : affichage
![](/charanim_interpolation.png)
Vous allez créer un module Skeleton.h/.cpp (ce code n'est qu'indicatif, vous êtes libre de vos structures de données). Cette classe va stocker un tableau de toutes les articulations (SkeletonJoint) du squelette et pour chaque articulation stocke l'identifiant de l'articulation parent et la matrice de passage de l'articulation vers le monde.
Le fichier est déjà présent dans le code départ avec des TODO à compléter :
```
class Skeleton
{
public:
struct SkeletonJoint
{
int m_parentId; // Le numéro du père dans le tableau de CAJoint de CASkeleton
Transform m_l2w; // La matrice passant du repère de l'articulation vers le monde
};
Skeleton() {}
//! Créer un squelette ayant la même structure que définit dans le BVH c'est à dire
//! creer le tableau de SkeletonJoint à la bonne taille, avec les parentId initialsé pour chaque case
void init(const BVH& bvh);
//! Renvoie la position de l'articulation i en multipliant le m_l2w par le Point(0,0,0)
Point getJointPosition(int i) const;
//! Renvoie l'identifiant de l'articulation père de l'articulation numéro i
int getParentId(const int i) const;
//! Renvoie le nombre d'articulation
int numberOfJoint() const;
//! Positionne ce squelette dans la position n du BVH.
//! Assez proche de la fonction récursive (question 1), mais range la matrice (Transform)
//! dans la case du tableau. Pour obtenir la matrice allant de l'articulation local vers le monde,
//! il faut multiplier la matrice allant de l'articulation vers son père à la matrice du père allant de
//! l'articulation du père vers le monde.
void setPose(const BVH& bvh, int frameNumber);
protected:
//! L'ensemble des articulations.
//! Remarque : la notion de hiérarchie (arbre) n'est plus nécessaire ici,
//! pour tracer les os on utilise l'information "parentID" de la class CAJoint
std::vector<SkeletonJoint> m_joint;
};
```
Dans le Viewer vous devez :
* Déclarer un Skeleton en variable de la classe
* écrire une fonction qui fait l'affichage
```
void CharAnimViewer::skeletonDraw(const Skeleton& ske);
```
* initaliser l'instance de Skeleton dans la fonction init
* Appeler setPose dans la fonction update
Remarques :
* On sépare bien l'affichage de la gestion du squelette pour pouvoir réutiliser le code Skeleton avec une autre librairie d'affichage.
* On ne s'occupe pas du temps pour l'instant mais uniquement du numéro de la posture.\\
* Vous pouvez trouvez des BVH dans le répertoire data du code de départ. Notamment le fichier robot.bvh pour debuguer.
## TP partie 2 : Contrôleur d'animation
##### Déplacer une sphère au clavier
Ecrivez une class CharacterControler qui à partir des touches claviers contrôlera le déplacement d'un personnage. Dans une 1er temps faites juste déplacer une boule : accélérer, freiner, tourner à droite, tourner à gauche, sauter. Ce contrôleur comportera une position et une vitesse. La vitesse sera modifiée par les flèches (ou un pad) et la position sera mise à jour dans la fonction update du Viewer en utilisant le paramètre "delta" recu par la fonction update.
Une classe de Controller peut ressembler à ceci.
```
class CharacterController
{
public:
CharacterController() : ... {}
void update(const float dt);
void turnXZ(const float& rot_angle_v);
void accelerate(const float& speed_inc);
void setVelocityMax(const float vmax);
const Point position() const;
const Vector direction() const;
float velocity() const;
const Transform& controller2world() const { return m_ch2w; }
protected:
Transform m_ch2w; // matrice du character vers le monde
// le personnage se déplace vers X
// il tourne autour de Y
// Z est sa direction droite
float m_v; // le vecteur vitesse est m_v * m_ch2w * Vector(1,0,0)
float m_vMax; // ne peut pas accélérer plus que m_vMax
};
```
##### Déplacer un personnage au clavier
Dans un 2e temps, votre contrôleur comportera également une série
d'animation bvh : attendre, marcher, courir, et donner un coup de pied.
En fonction de l'action que veut faire le joueur appuyant sur des
touches vous changerez d'animation. Vous coderez la machine à états
finis (FiniteStateMachine) de l'image ci-dessous. Les cercles sont les
états (l'animation en train d'être jouée), les rectangles rouges sont
les éventements et les carrés bleus sont les actions à effectuer
(fonction de la classe). Ce changement se fera brutalement. Ne vous
occupez pas non plus des pieds qui glissent sur le sol. Un meilleur
contrôle peut-être fait la construction d'un graphe d'animation.
![](/fsm.png)
## TP partie 3 : Transition et plus
a) Pour améliorer le réalisme, il serait bon de faire les transitions
entre deux animations en choisissant deux poses des animations qui sont
proches. Pour cela il faut calculer la distance entre deux poses
d'animations (Voir les infos dans le sujet Graphe d'animation).
b) Pour aller encore plus loin, on peut construire un automate de
manière complètement automatique, on appelle alors ceci un graphe
d'animation. [Voir le sujets de TP
suivants.](https://perso.liris.cnrs.fr/alexandre.meyer/public_html/www/doku.php?id=master_charanim_tp_m2_cpp&s[]=graphe#tp_3e_partiegraphe_d_animation)
a.bis) Indépendamment de la machine à état ou du graphe, si vous voulez
gérer le temps de manière plus juste, il faudrait récupérer le temps
réellement écoulé depuis l'affichage précédent. Ceci vous fera ne vous
fera pas tomber précisément sur une frame stocké dans le clip (BVH). Il
faudra donc interpoler entre les 2 frames. Le résultat sera de l'ordre
du détail lors de l'affichage mais si vous voulez que votre moteur
d'animation tourne sur toutes les machines indépendamment du CPU, il
faut le faire. Cette interpolation peut également servir pour passer
d'un clip à un autre.
## TP partie 3.PLUS : graphe d'animation
* -* [Motion Graph de l'article original](http://www.cs.wisc.edu/graphics/Gallery/kovar.vol/MoGraphs/);
* Des BVH avec squelette compatible pour le graphe sont donné dans le git, répertoire Second\_Life.
Nous avons remarqué dans la partie 1 que la transition d'animation ne fonctionne bien que lorsque les deux poses du squelette sont assez proches (il faut bien sûr également que les deux squelettes aient la même topologie). L'idée d'un graphe d'animation est de construire un graphe où chaque noeud correspond à une pose d'une animation et où chaque arrête définit qu'une transition est possible entre les deux poses.
#### Comparaison de deux poses d'animation
Pour construire un graphe d'animation à partir d'une ou plusieurs animations, on doit être capable de comparer deux poses d'animation. Une distance de 0 indique que les deux poses sont identiques. Une distance grande indique que les 2 poses sont très différentes.
A partir de la classe Skeleton, écrivez la fonction de calcul de distance entre deux poses de squelette. Cette fonction est déjà présente dans la classe Skeleton plus haut mais en commentaire. Cette fonction calcule itérativement sur toutes les articulations la somme des distances euclidienne entre chaque articulation de deux squelettes aillant la même topologie mais dans des poses différentes.
```
friend float Skeleton::Distance(const Skeleton& a, const Skeleton& b);
```
Remarque : il est important de ne pas tenir compte de la translation et de la rotation de l'articulation racine. Une même pose a deux endroits du monde doit donner une distance de 0. Dans un 1er temps, votre personnage aura son noeud root centré en (0,0,0), puis dans la dernière partie de cette question, vous traiterez le centre de gravité.
#### Construction du graphe
Ecrivez un module MotionGraph qui contiendra un ensemble de BVH et le graphe d'animation définissant des transitions dans cette ensemble d'animation.
* Un noeud du graphe=(Identifiant d'une animation + un numéro de pose);
* un arc du graphe entre deux poses indique la transition possible entre ces deux poses. Deux poses sont compatibles à la transition quand la distance entre les deux squelettes sont inférieurs à un certain seuil fixé empiriquement.
Vous pouvez créer un module CACore/CAMotionGraph.h/.cpp
```
class MotionGraph
{
...
protected:
//! L'ensemble des BVH du graphe d'animation
std::vector<BVH> m_BVH;
//! Un noeud du graphe d'animation est repéré par un entier=un identifiant
typedef int GrapheNodeID;
//! Une animation BVH est repérée par un identifiant=un entier
typedef int BVH_ID;
//! Un noeud du graphe contient l'identifiant de l'animation, le numéro
//! de la frame et les identifiants des noeuds successeurs
//! Remarque : du code plus "joli" aurait créer une classe CAGrapheNode
struct GrapheNode
{
BVH_ID id_bvh;
int frame;
std::vector<GrapheNodeID> ids_next; //! Liste des nœuds successeurs
};
//! Tous les noeuds du graphe d'animation
std::vector<GrapheNode> m_GrapheNode;
};
```
#### Navigation dans le graphe
Une fois ce graphe construit, on peut définir différente manière de naviguer dedans :
* Un parcours aléatoire dans le graphe (juste pour vérifier que le graphe est ok);
* L'utilisateur donne des directions au clavier => le parcours dans le graphe est conditionné par ces contraintes.
#### Gestion correcte du centre de gravité
Pour chaque arc du graphe, vous devez stocker la transformation (soit une matrice 4x4, soit un quaternion et une translation) du noeud root (souvent le centre de gravité) entre la pose i et la pose i+1. Cette transformation sera appliqué au noeud root de votre personnage quand il empruntera l'arc.
## NON DEMANDE CETTE ANNEE : Animation physique (voir la partie de F. Zara à la place)
#### Particules
![](/charanim_ball.png)
Dans la fonction init de la class CharAnimViewer indiquez un nombre de particules non nul :
```
m_world.setParticlesCount( 10 );
```
Dans la fonction render, il faut afficher les particules en dé-commentant cette ligne :
```
m_world.draw();
```
Vous verrez alors les particules s'afficher, mais elles ne seront pas animées. Pour calculer la physique sur les particules, il y a deux
classes **PhysicalWorld** et **Particle**. Regardez le fichier Particles.h. Il faudra compléter les fonctions update, collision et groundCollision :
```
void update(const float dt = 0.1f)
void groundCollision()
void collision(const Point& p, const float radius)
```
Le code de update doit mettre à jour la vitesse avec l'équation F=m.a où a = dv/dt
Et mettre à jour la position avec l'équation habituelle p = p + v.t
[Regardez les explications dans la vidéo de cours ou ici](https://perso.liris.cnrs.fr/alexandre.meyer/teaching/master_charanim/aPDF_COURS_M1/M1_TP_PhysicsAnimation_ParticulesMassesRessorts.pdf).
#### Interaction personnage/particules
Pour ajouter l'interaction entre votre personnage et des boules/sphères se trouvant dans l'environnement, il faut appeler PhysicalWorld::collision depuis CharAnimViewer::update en parcourant toutes les articulations du personnage. Dans un 1er temps, vous pouvez juste faire disparaitre les particules touchées en faisant passer le rayon de la particule à -1 et faire en sorte que les particules de rayon négatif ne soient pas affichées. Puis ajoutez dans Particle::collision du code pour déplacer les particules en collisions (résoudre les collisions) et changer leur vecteur vitesse.
#### Tissus
Un tissu est composé d'un maillage de Masses/Ressorts. Ajoutez une classe Spring qui va comporter :
* la raideur du ressort
* la longueur au repos du ressort
* idA et idB : l'identifiant des 2 particules aux extrémités du ressort. Ces 2 identifiants sont l'indices de deux particules dans le tableau de particules stocké dans la classe PhysicalWorld.
Munissez cette classe d'une fonction *addForce* qui calcule les forces qu'applique le ressort sur les 2 particules.
```
void Spring::addForce(vector<Particles>& part, const float dt)
```
Dans la classe PhysicalWorld, ajoutez un tableau de ressort :
```
std::vector<Spring> m_springs;
```
Le constructeur de PhysicalWorld créera un tissu avec des masses ressorts sous la forme de l'image ci-dessous. La génération se fera procéduralement.
![](/mass-spring.jpg)
#### Interaction avec le personnage
Normalement, le personnage va pouvoir interagir avec le tissu en passant dessous ...
---
title: "Planning"
description: "Planning"
---
## Printemps 2024
<img src="doc/2024_edt.png" width="800" class="center">
<a href="http://adelb.univ-lyon1.fr/direct/index.jsp?projectId=3&ShowPianoWeeks=true&showTree=false&resources=95569&displayConfName=_DirectPlanning_DOUA_CHBIO&days=1&weeks=22,23,24,25,26,27,29,30,31,32,33,34,35" target = "_blank" >Ouvrir sur ADE</a><br/>
Les TD
* Quai 43 s.102 (1er étage) : Nicolas Pronost
* Quai 43 s.109 (1er étage) : Franck Favetta
* Quai 43 s.106 (1er étage) : Erwan Guillou
* Quai 43 s.112 (1er étage) : Francois Pitois
* TD1 Thémis 58 (1er étage), TD2 Themis 7 puis Berthollet 203 (2ème étage),Berthollet 204 (2ème étage) : Alexandre Meyer
## Les dates importantes
* jeudi 15 février 18h : module Image à rendre dans TOMUSS
* mardi 20 février 8h-9h30 : examen en amphi
* jeudi 29 février à 18h : cahier des charges à rendre dans TOMUSS
* mardi 12 mars : démo mi-parcours
* mardi 16 avril : soutenance de projet
web/content/planning/doc/2024_edt.png

53.2 KiB

---
title: "Projet réalisé en TP"
description: "Projet"
---
<img src="doc/projet.jpg" width="300" class="center">
### Sujet et critères de notation
Vous êtes libre du sujet de votre projet, mais discutez-en avec les intervenants de TD et TP afin d'obtenir leur accord. [Si vous êtes en panne d'inspiration, voici quelques idées de sujets](./doc/ideas).
* **Le projet est à réaliser en groupe de 2 ou 3 maximum** (4 n'est pas possible)
* [N'oubliez pas de lire les règles à respecter lors de la conception et la réalisation d'un projet](https://forge.univ-lyon1.fr/Alexandre.Meyer/L2_ConceptionDevApp/-/blob/master/doc/coding_rules.md)
* Regardez également les critères de notations (notes "Technique", "Conception" et "Organisation") [dont le détail est ici](https://docs.google.com/spreadsheets/d/1OcpRm6gQtmRNWSXeG7QwnFJ6Eqzl7_DKCjUM4V9P4A0/edit?usp=sharing). (IMPORTANT A LIRE)
* Vous devez **être autonome ET nous montrer régulièrement l'état d'avancement de votre projet**. Un groupe dont les membres arrivent à 10h voir plus tard, voir pas du tout et qui, tout d'un coup, une semaine avant la soutenance ont un projet bien abouti, sera considéré comme très très suspect.
* Travail en équipe : vous disposez de 100 points par projet. A la fin du projet, vous affectez ces points à chacun des membres du groupe en fonction du degré d'implication. Par exemple, un groupe équilibré avec une personne un peu plus leader donnera 30, 30 et 40 points. Cette information servira à moduler les notes de chacuns (voir les critères de notation dans la grille). La modulation peut aller plus loin que juste les points sur l'organisation du travail. Un étudiant non impliqué peut avoir une note très faible sur les 3 parties, loin du reste du groupe.
<img src="doc/cahier2.jpg" width="200" class="center">
### Cahier des charges
Après quelques séances de conception et développement, vous devez rédiger et soumettre un cahier des charges (case 'DepotCahierDesCharges' sur Tomuss au format pdf, un seul dépôt par groupe). Ce cahier des charges reprend l'organisation vue en cours et en TD. Il doit comporter au moins une présentation du projet, une description détaillée de l'application (ex. règles du jeu ou fonctionnalités du logiciel), une liste exhaustive et détaillée des tâches à réaliser, un diagramme des classes (UML) et un diagramme de Gantt (tous les deux prévisionels). Ce document fait typiquement entre 4 et 10 pages.
#### Réaliser votre diagramme des classes (UML)
* [Les bases d'un diagramme de classes sur wikipedia.](https://fr.wikipedia.org/wiki/Diagramme_de_classes) Nous n'utilisons que la notion d'association (et un peu héritage) en LIFAP4 pour les relations entre classes
* Des outils
* [Umbrello UML modeller](http://uml.sourceforge.net/) (Linux) est un programme permettant de modéliser les différents diagrammes UML (Unified Language Diagram)
* [Dia](http://en.wikipedia.org/wiki/Dia_(software)) est un programme
pour dessiner des diagrammes
* [StarUML](http://staruml.io/)
* [www.diagrams.net](https://www.diagrams.net/index.html) : app en ligne ou app à installer (simple, léger et efficace)
* [Outils online Viual-paradigm](https://online.visual-paradigm.com). Choisissez "Class diagram".
* [Ce lien](http://en.wikipedia.org/wiki/List_of_Unified_Modeling_Language_tools) répertorie différents outils pouvant être utilisés pou définir des diagrammes de modules
Remarque : normalement sur les machines du Nautibus, Umbrello et Dia sont installés, sinon utilisez un outil en ligne.
<img src="doc/demo.png" width="200" class="center">
### Démo mi-parcours
A la moitié de votre projet, vous donnerez une démonstration aux intervenants de 10 minutes, qui sera suivie de quelques questions. Le
but de cette démonstration est de faire un point sur ce qui marche et ce qui reste à faire, ainsi que de présenter l'organisation et la gestion de votre projet en général. Vous devez donc à la fois montrer ce que votre application est déjà capable de faire, mais aussi que vous avez les capacités à finaliser le projet à temps.
<img src="doc/soutenance.jpg" width="200" class="center">
### Soutenance
**La soutenance dure 20 min = 15 min de présentation démo, suivi de 5 min de questions**.
La présentation devra être réalisée sous Powerpoint ou équivalent. Le mieux est de générer un PDF pour des raisons de compatibilité. Voici quelques conseils pour la présentation (entre 8 et 10 minutes).
* Il s'agit d'une présentation technique. Passez donc rapidement sur l'interface graphique et les fonctionnalités, sur lesquelles vous pourrez plus vous attarder durant la démo. La majeure partie devra être consacrée à expliquer comment vous avez conçu et programmé votre application, en décrivant les classes et les structures correspondantes.
* Le fruit d'un travail de plus de 40h doit être décrit en quelques minutes, ce qui est très court. Allez rapidement à l'essentiel ! Le planning étant très serré, vous serez interrompu si vous dépassez le temps imparti.
* Pour les projets réalisés en groupe, le temps de parole devra être équitablement réparti entre les étudiants.
* Le meilleur aperçu de la conception de votre projet reste le diagramme des classes (UML). Soignez sa présentation !
Voici un plan possible.
* Slide 1: Titre du projet, auteurs, principe de l'application (très rapide, avec une capture d'écran)
* Slide 2: **Vue d'ensemble du diagramme des classes (UML)** (donc le diagramme doit être à jour)
* Slide 3 à n-1: Explications détaillées des 3 ou 4 classes les plus importants et/ou les plus intéressants (ex. ceux dont vous êtes les plus fiers, sur lesquels vous avez passé le plus de temps)
* Slide n: Conclusion. Attention à éviter les banalités du style "Le projet a été intéressant..." (ou l'inverse !). Les intervenants vous ont suivis pendant un semestre et ont déjà leur idée là-dessus! Décrivez par exemple ce qui marche et ce qui ne marche pas (les objectifs initiaux du cahier des charges ont-ils été atteints ?), les éventuelles difficultés rencontrées, et ce que vous (re)feriez avec un peu (ou beaucoup) plus de temps.
Quelques conseils pour la démo (entre 5 et 7 minutes).
* Le code doit être compilé, et la démo doit être lancée via l'exécutable
* Préparez la démo pour être lancée tout de suite après la présentation (ex. sur votre ordinateur portable)
* Répétez les actions que vous voulez illustrer, concentrez vous sur ce qui fonctionne (soyez vendeur!)
* Utilisez le plein écran si approprié, prévoyez de quoi entendre sons et musiques si besoin
* Si nécessaire, testez votre démo avant sur écran externe (ie. apprenez comment afficher en double écran sur votre machine)
* **Faîtes au moins une répétition complète pour éviter les surprises (timing, démo qui fonctionne pas, etc.).**
<img src="doc/livrable.png" width="200" class="center">
#### Travail à rendre (case 'DepotProjetFinal' dans Tomuss)
Préparer et soumettre une archive suivant les mêmes conventions que le module Image nommée `NOM_PROJET_NUMEROETU1_NUMEROETU2_NUMEROETU3.tar.gz` et contenant au minimum les points suivants.
* Un `readme.md` à la racine de l'archive contenant au moins
* les informations factuelles du projet : noms, prénoms, numéros étudiant et identifiant du projet sur la forge
* un manuel : commandes de compilation et d'exécution, règles du jeu ou utilisation de l'application, la liste des fonctionnalités du programme
* une description de l'organisation de votre archive
* Tout le code (dans le répertoire src)
* Un makefile (dans le répertoire racine) ou un fichier CMakeLists.txt
* Attention, toute autre librairie que la SDL devra être incluse dans l'archive ou pouvoir s'installer avec les packages
* Les assets de votre application (dans le répertoire data, ex. images, sons, modèles 3D, fonts, fichiers de configuration)
* Les exécutables sont compilés dans le répertoire bin
* La documentation de votre projet (dans le répertoire doc) contenant au minimum
* La présentation orale (fichier PowerPoint ou pdf)
* Le diagramme des classes UML à jour (fichier image ou pdf)
* Le diagramme de Gantt à jour (fichier image ou pdf) avec une description de qui a fait quoi dans le projet (associations entre les tâches du diagramme et les étudiants)
* La documentation du code (dans le répertoire doc/html, générée par doxygen)
Veillez à bien nettoyer votre archive avant soumission, i.e. supprimer les fichiers inutiles (fichiers objets, dossiers/fichiers git etc.).
web/content/projet/doc/cahier.png

29.3 KiB

web/content/projet/doc/cahier2.jpg

164 KiB

web/content/projet/doc/demo.png

19.5 KiB

# Voici une liste non exhaustive d'idées de sujet
## Jeux
Le plus rigolo c'est les jeux ... inspirez vous des mini-jeux de vos mobiles ou des consoles.
#### Plateaux
- Dames
- Les dames chinoises
- Othello
- Reversi
- Sudoku et variantes
- Démineur
- Risk, ou autre jeu de stratégie basé sur l'occupation du plateau
- Monopoly
- Scrabble
- etc.
#### Jeux de cartes
- Poker
- Munchkin
- Tarot
- etc.
#### Jeux d'arcade
- Pacman
- Tetris
- Nibble
- Sokoban
- Space invaders
- Azerty warrior
- Mini-course de voitures caméra au-dessus [type SuperSprint](http://en.wikipedia.org/wiki/Super_Sprint)
- Galaga
- Donkey Kong
- Star Wars
- Dig Dug
- Asteroids
- Defender
- Tron
- Tempest (tie)
- Centipede (tie)
- Snake
- etc.
## Simulation et vie artificielle
- génération de plantes à partir d'une grammaire (plutôt pour ceux qui ont déjà suivi "Infographie")
- génération automatique de terrain (plutôt pour ceux qui ont déjà suivi "Infographie") :
cf. "Real Time Procedural Terrain Generation"\]\]
- vie artificielle (jeux de la vie, colonie de fourmies ? les sims ?)
## Applications
- Logiciel de traitement d'images : Application affichant une image et proposant différents algorithmes de traitement d'images : éclaircissement, niveau de gris, flou, etc.
- Gestion de rendez-vous / agenda
- Gestion de bibliothèques / dvd, etc.
- Musique : Gestion de playlist et autres
- Geographie : affichage du monde avec des infos sur les pays et villes
- Math : calcul formel, résolution de système, calcul matriciel, vecteur, etc.
- Logiciel de dessin vectoriel : On désire réaliser un logiciel de dessin vectoriel. Par vectoriel on entend qu'un dessin est constitué d'une liste de primitives géométriques simples : points, droites, cercles, carrés, ... auxquelles on peut par exemple associer des caractéristiques comme la couleur ou l'épaisseur du trait, etc. Pour être utilisable ce logiciel devra être muni d'une interface : par exemple une fenêtre constituée d'une barre d'outils, d'une zone de dessin et d'un menu. Vous êtes entièrement libre des outils que vous proposez à l'utilisateur ainsi que de la manière dont vous pensez votre interface. Prévoir un fichier d'aide pour l'utilisateur peut être une bonne idée si vous avez le temps.
web/content/projet/doc/livrable.png

87.7 KiB

web/content/projet/doc/projet.jpg

28.9 KiB

web/content/projet/doc/soutenance.jpg

59.2 KiB

web/content/projet/doc/soutenance2.jpg

170 KiB

---
title: "Travaux Dirigés"
description: "TD"
---
<br>
Il y a des TD au tableau/stylo et des TD sur machine. Pour la partie marchine, le module Image est à rendre.
<br>
### TD-C Conception et diagramme des classes
<img src="doc/conception.jpg" width="100" class="center">
Etude de la conception de différentes applications simples, diagramme des classes.
* [TD-C1 : Parc de voitures, Pacman](doc/LIFAPCD_TD-C1_ParcvoiturePacman.pdf)
* [Elements de correction du TD Conception 1](doc/LIFAPCD_TD-C1_ParcvoiturePacman_corriges.pdf)
* [TD-C2 : application d'assemblage de Duplo et introduction aux TD outils](doc/LIFAPCD_TD-C2_Duplo.pdf)
* [Elements de correction du TD Conception 2](doc/LIFAPCD_TD-C2_Duplo_corrige.pdf)
<br>
<br>
### TD-O Outils
<img src="doc/tools.png" width="200" class="center">
#### TD-O0 Installation et choix d'un éditeur de code
Choisisser un éditeur de code. Nous vous conseillons de choisir parmi VSCode, Visual Studio(Windows), XCode(MacOS), CLion ou Codeblocks (Windows/Linux). [Regarder les consignes d'installation ici](https://forge.univ-lyon1.fr/Alexandre.Meyer/L2_ConceptionDevApp/-/blob/master/doc/install.md)
<br>
#### TD-O1 Classe Image
Voir l'énoncé de la [Partie 1](doc/LIFAPCD_TD-O1_ClasseImage.pdf)
* Ecriture de la structure Pixel et de la classe Image
* Organisation des fichiers
* Début des tests de la mémoire avec Valgrind
<br>
#### TD-O2 Gestionnaire de version et documentation
* Passage du code dans un projet git
* Se connecter sur la [forge Lyon 1](https://forge.univ-lyon1.fr)
* Dupliquez [le projet suivant](https://forge.univ-lyon1.fr/Alexandre.Meyer/l2_cda_moduleimage). Il comporte l'éxécution du script de notation dans sa version tout automatique. Attention : puor la notation votre archive sera testée avec un humain qui regarde votre code.
* Ajoutez-y les membres de votre groupe
* [Réalisez le tutorial "Premier pas" se trouvant ici](https://forge.univ-lyon1.fr/Alexandre.Meyer/L2_ConceptionDevApp/-/blob/master/doc/git.md)
* Documentez la classe Image et la structure Pixel avec les balises doxygen et générez une documentation HTML. [Voir les explications générales sur doxygen ici](https://forge.univ-lyon1.fr/Alexandre.Meyer/L2_ConceptionDevApp/-/blob/master/doc/doxygen.md).
* Pour votre module Image
```
~/LIFAPCD/modIm $ mkdir doc
~/LIFAPCD/modIm $ doxygen -g doc/doxyfile
~/LIFAPCD/modIm $ code doc/doxyfile
// éditer les balises du fichier doxyfile
~/LIFAPCD/modIm $ code ../Makefile
```
Ajouter une règle dans votre Makefile
```
doc: doc/doxyfile
doxygen doc/doxyfile
```
<br>
#### TD-O3 Débogage
Voir l'énoncé de la [Partie 3](doc/LIFAPCD_TD-O3_Debogage.pdf)
* Gestion de mémoire et optimisation de code sur un exemple "jouet"
* Débogage des fonctions de sauvegarde et de chargement d'une image
* Gdb
* Valgrind
<br>
#### TD-O4 Bibliothèques (lib)
Voir l'énoncé de la [Partie 4](doc/LIFAPCD_TD-O4_SDL.pdf)
* Installer les librairies SDL2
* Écrire la classe ImageViewer
* Faire le diagramme des classes du module Image
<br>
<br>
## Module Image à rendre
<img src="../projet/doc/livrable.png" width="150" class="center">
### À rendre
Votre archive sera testée avec un script particulier (cf. plus bas). Vous devez donc **respecter exactement le format attendu par ce script sinon vous aurez la note zéro**.
**Déposez votre archive sur TOMUSS**, dans la case `DepotModuleImage` du cours. Vous devez **respecter l'heure limite,** car le dépôt sera désactivé après l'heure limite. Une soumission en retard (par email ou autre) entraînera la note zéro pour tout le groupe. Un seul dépôt par groupe d'étudiants (sur n'importe lequel des comptes).
Votre module Image doit respecter les conventions suivantes.
* À faire en groupe de 2 ou 3 étudiants
* Votre archive s'appelle `NUMEROETU1_NUMEROETU2_NUMEROETU3.tgz` ou `NUMEROETU1_NUMEROETU2_NUMEROETU3.tar.gz` (pas de zip) où `NUMEROETU1` est le numéro étudiant du premier membre du groupe, etc.
* Pour faire le tgz, il faut vous placer dans le répertoire parent du projet, puis entrer `tar cfvz NUMEROETU1_NUMEROETU2_NUMEROETU3.tgz NUMEROETU1_NUMEROETU2_NUMEROETU3`
* Tous les fichiers se décompressent dans un répertoire ayant pour nom `NUMEROETU1_NUMEROETU2_NUMEROETU3` (même nom que l'archive)
* Ce répertoire doit contenir les sous-répertoires `bin`, `src`, `obj`, `data` et `doc`
* Un fichier `Makefile` (donné explicitement ou bien générable par le fichier `CMakeLists.txt` de CMake) compile les trois programmes :
* `bin/exemple` exécute le code générant les images en sortie (i.e. exécute mainExemple.cpp)
* `bin/test` appelle `testRegression` de la classe Image (test de non-régression qui vérifie tout) et affiche les tests effectués à l'écran (i.e. exécute mainTest.cpp)
* `bin/affichage` fait l'affichage de l'image dans une fenêtre SDL avec zoom/dézoom (i.e. exécute mainAffichage.cpp)
* `readme.md` est un fichier texte expliquant la librairie. Au minimum comment compiler et exécuter, ce que fait le module et chacun des exécutables, l'organisation de l'archive, etc., et il doit indiquer les noms/prénoms/numéros des étudiants et l'id du projet sur la forge
* Vos fichiers sources (.h et .cpp) sont placés dans le dossier `src`
* Les images sauvées et lues seront toujours placées dans le dossier `data`
* Les .o sont générés dans obj (mais non présent dans l'archive)
* Dans le dossier `doc`, vous aurez
* `doc/doxyfile` est le fichier de configuration de doxygen
* `doc/html/index.html` est la page d'entrée de la documentation (générée avec doxygen mais non présente dans l'archive)
Ces conventions sont très répandues, et il serait de bonne habitude de les appliquer pour tous vos rendus de TP (info ou autres), ou vos projets futurs publiés sur internet. Vous utiliserez notamment ces conventions pour votre projet.
**Vous n'avez pas le droit de modifier le code fourni.** Les programmes principaux, les noms des fichiers, des classes et structures, des fonctions, des données, etc., doivent être exactement les mêmes que ceux donnés. Ceci conditionne fortement le succès du script.
### Script de test du module Image
Votre archive du module Image sera testée avec le script présent dans le répertoire `TD_moduleImage` [fourni durant le TD ici](https://forge.univ-lyon1.fr/Alexandre.Meyer/L2_ConceptionDevApp), s'appelant evalModuleImage.py (script Python). Avant de soumettre votre archive, vérifiez que l'exécution du script se déroule sans erreur. Pour vous, il y a 3 manières de lancer le script :
* sous linux avec le code du script en tapant la commande `python3 evalModuleImage.py NUMEROETU1_NUMEROETU2_NUMNUMEROETU3.tgz`;
* sur la machine de l'université en [suivant les explications ici](https://forge.univ-lyon1.fr/Alexandre.Meyer/L2_ConceptionDevApp);
* en clonant le projet donné en TD-O2, à chaque commit le script est lancé.
#### Script et notation
* Si le script échoue à une étape, le correcteur n'ira pas plus loin (même si la suite est juste).
* Si le script rapporte des erreurs, corrigez les avant de soumettre votre archive.
* Le script vous donne également une note **INDICATIVE** à la fin. **Pour la note finale, des vérifications supplémentaires (non automatiques) seront effectuées par les enseignants.** La note indicative est donc une **note maximale possible**.
#### Précision technique sur ce script
* Ce script doit tourner avec Python 3 (attention à pas utiliser Python 2) et uniquement sous Linux à cause de valgrind. Si vous l'exécutez sur votre machine personnelle, il faut installer python, doxygen, valgrind, SDL2, etc. Voir les installations à faire sur [la page projet](projet).
* Si votre code nécessite l'utilisation du standard CPP11 ou plus, n'oubliez pas d'ajouter l'option `-std=c++11` (ou plus) dans les lignes de commande g++ de votre Makefile.
* Sous MacOS, [regardez les consignes ici](doc/tools_MacOS.pdf) (merci Erwan)
* Sous Windows, installer WSL, puis tout se passe comme sous Linux
File added
File added