Philosophie de SOFA

Graphe de scène

Il faut savoir que la boucle d'animation de SOFA est basée sur l'utilisation d'un graphe de scène, chaque objet de la scène étant alors un noeud de ce graphe :

A chaque noeud du graphe, on peut y attacher :

Les objets attachés permettent de définir :


Tutoriaux de SOFA

Sur le site de SOFA vous pouvez trouver les explications de deux codes simples :


Degrés de libertés (DOF) des objets de la scène

Un des composants les plus importants est le MechanicalObject. Ce composant permet de définir les degrès de liberté d'un objet (i. e. les coordonnées de positions, vitesses, accélérations, forces, etc.). A noter que toutes les coordonnées mises dans ce composant doivent avoir le même type (par exemple vecteur 3D). Les particules de cet élément sont dessinés en blanc dans l'application SOFA (visibles en cochant la case “Behavior Model”). Ci-dessous l'extrait du code (issu du tutoriel OneParticule) permettant de définir une particule :

Déclaration du composant MechanicalObject nommé particle
    typedef sofa::defaulttype::Vec3Types MyTypes;

    sofa::component::MechanicalObject<MyTypes>* particle = new 
    sofa::component::MechanicalObject<MyTypes>;
setName permet de définir le nom qui apparaîtra dans le graphe de scène
    particle->setName("particle");
Ce composant est rattaché au noeud "particule_node" du graphe de scène (cf. tutoriel)
    particule_node->addObject(particle);
Redéfinition de la taille de particle : 1 seul élément 
    particle->resize(1);
Initialisation des coordonnées de position et de vitesse de particle
    // The point
    (*particle->getX())[0] = Vec3(0,0,0);

    // The velocity
    (*particle->getV())[0] = Vec3(0,0,0);

Masse des éléments de la scène

La masse de l'objet est déclarée à l'aide d'un autre composant. En effet, la masse ne rentre pas dans le cadre de MechanicalObjet puisque tous les composants de cet élément doivent être de la même forme, donc souvent des vecteurs 3D. Voici quelques exemples de composants permettant de définir la masse de l'objet à simuler :


Solveurs utilisés dans la boucle d'animation

Pour animer les objets de la scène, nous devons, à chaque pas de temps, calculer les nouvelles positions des particules constituants les objets. Pour cela, à chaque pas de temps, les calculs suivants doivent être effectuer :

Les accélérations des particules sont calculées à partir des forces, en utilisant la loi fondamentale de la dynamique.

Les vitesses et les positions sont ensuite calculées par intégration successives des accélérations. Plusieurs méthodes d'intégrations existent, divisées en deux catégories : les méthodes explicites et les méthodes implicites (nécessitant la résolution d'un système linéaire). Vous pourrez trouver dans SOFA des solveurs déjà implantés permettant d'effectuer cette phase d'intégration :


Calcul des forces des objets de la scène

Dans la boucle d'animation d'un objet, le calcul des forces est très important, puisque ce sont les forces appliquées aux différents éléments constituants l'objet qui vont déterminer son comportement au cours du temps. Par exemple dans un système masses-ressorts, l'objet est discrétisé en un ensemble de particules qui interragissent ensemble grâce à leurs connections par des ressorts. Ainsi, ce sont les forces engendrées par les ressorts qui vont déterminer le mouvement des différentes particules de l'objet.

Un certain nombre de classes ont été implantées dans le namespace sofa::component::forcefield. Vous y trouverez notamment les composants suivants :

Selon le modèle de forces choisi, vous pourrez définir plus précisément les propriétés de votre modèle (raideur et amortissement des ressorts, propriétés élastiques (module de Young, de Poisson, etc.), …).


Topologie des maillages des objets de la scène

Le composant MeshToplogy permet de définir le maillage d'un objet de la scène. Ce maillage peut être composé de lignes, triangles, carrés, tétraédres, ou de cubes. Des méthodes permettent notamment de récupérer un élément particulier du maillage (par ex. getLine(index_type i)). Il est également possible de récupérer le nombre de chacun de ces éléments (par ex. getNbCubes ()), ou de modifier la topologie du maillage en y insérant de nouveaux éléments (par ex. addTriangle (int a, int b, int c)). Voici un exemple de code permettant de créer un simple tétraédre (issu du tutoriel OneTetrahedron) :

    sofa::component::topology::MeshTopology* topology 
     = new sofa::component::topology::MeshTopology;

    topology->addTetrahedron(0,1,2,3);

A noter que la méthode load() permet de récupérer les données mises dans un fichier .obj pour créer facilement le maillage d'un objet plus complexe.


Contraintes imposées

Le composant FixedConstraint permet d'ajouter des contraintes à un objet, contraintes qui seront fixes au cours du temps. Par exemple, voici le code permettant de fixer le point 0 d'un objet :

    sofa::component::constraint::FixedConstraint<MyTypes>* constraints = new  
      sofa::component::constraint::FixedConstraint<MyTypes>;

    node->addObject(constraints);
    constraints->addConstraint(0);

Visualisation des objets simulés

Le composant OglModel permet de créer la partie visuelle de l'objet. La méthode load() permet notamment de charger des données issues d'un fichier.obj par exemple.


Mapping

Il est parfois intéressant de décomposer un objet en deux : une partie servant au rendu de l'objet, et une autre servant aux calculs de l'animation. Il faut ensuite effectuer un “mapping” entre ces deux parties afin que le rendu suive le mouvement de la partie simulation. Plusieurs types de mapping sont disponibles dans SOFA :

Dans le tutoriel OneTetrahedron, le mapping permet de faire coincïder le mouvement du foie avec le mouvement simulé du tétraédre : le foie devient le tétraèdre.


Traitement des collisions entre les objets de la scène

Le traitement des collisions (détection et traitement) passe par plusieures étapes, chacune correspondant à un élément à ajouter à la scène (relié directement à la racine du graphe si identique pour tous les objets). Ces éléments font partie du namespace sofa::component::collision :

Plusieurs modèles sont disponibles pour les collisions :