Open Inventor |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Introduction
Open Inventor : couche objet ajoutée à OpenGL pour faciliter la modélisation des scènes à afficher. Open Inventor : librairie d'objets et de méthodes utilisables pour créer des applications graphiques 3D interactives. La boite à outils d'Inventor inclut : (1) des primitives de gestion de base de données de scène composée d'objets (forme, propriétés, groupe et moteur), (2) un ensemble de noeuds qui autorisent la création de groupes de noeuds prédéfinis, (3) des manipulateurs interactifs (boite de manipulation et trackball) qui sont des objets présents dans la scène que l'utilisateur peut manipuler interactivement, (4) la librairie de composants Inventor Xt (visualiseur, éditeur de matériau, éditeur de lumière,...) qui donne accès à des fonctions d'interface de haut niveau. Open Inventor a été utilisé par SGI comme base pour les spécifications de VRML. La base de données Inventor noeud : bloc de construction élémentaire utilisé pour créer une base de données 3D Inventor. Chaque noeud contient de l'information (matériau de surface, description de forme, transformation géométrique, lumière, caméra,...). Graphes de scène : scène constituée d'un assemblage de noeuds constitué en graphe. Base de donnée Inventor : assemblage de plusieurs graphes de scène constituant ainsi une scène globale. Opérations peuvant être réalisées sur un graphe de scène :
Les noeuds peuvent être classés en :
Primitives plus spéciales : les moteurs et les senseurs. Moteur : objet pouvant être connecté à d'autres objets utilisé pour réaliser des animations ou imposer des contraintes inter-objets Senseur : objet destiné à détecter un changement dans la base de données et à appeller alors une fonction Manipulateurs Manipulateur : noeud d'un type spécial destiné à réagir à des événements de l'interface utilisateur et pouvant être édité directement par l'utilisateur. Exemple : la boite de saisie est une boite englobante munie de poignées aux coins et aux faces. La librairie de composants d'Inventor Intégration et support avec le système X-Window:
L'arbre de classes d'Inventor Toutes les classes d'Inventor font partie d'un arbre de classes dérivant de la classe SoBase. Il est possible de dériver soit même de nouvelles classes de toute classe existante. Exemples Création d'une fenêtre où une scène sera rendue. Construction du graphe de scène (un cône) par création de noeuds propriété et forme et leur combinaison en groupes. #include <Inventor/Xt/SoXt.h> #include <Inventor/Xt/SoXtRenderArea.h> #include <Inventor/nodes/SoCone.h> #include <Inventor/nodes/ SoDirectionalLight.h> #include <Inventor/nodes/SoMaterial.h> #include <Inventor/nodes/ SoPerspectiveCamera.h> #include <Inventor/nodes/SoSeparator.h> main(int , char **argv) { Widget myWindow = SoXt::init(argv[0]); if (myWindow == NULL) exit(1); SoSeparator *root = new SoSeparator; SoPerspectiveCamera *myCamera = new SoPerspectiveCamera; SoMaterial *myMaterial = new SoMaterial; root->ref(); root->addChild(myCamera); root->addChild(new SoDirectionalLight); myMaterial->diffuseColor.setValue(1.0, 0.0, 0.0); root->addChild(myMaterial); root->addChild(new SoCone); SoXtRenderArea *RenderArea = new SoXtRenderArea(myWindow); myCamera->viewAll(root, RenderArea->getViewportRegion()); RenderArea->setSceneGraph(root); RenderArea->setTitle("Hello Cone"); RenderArea->show(); SoXt::show(myWindow); SoXt::mainLoop(); } Utilisation d'un moteur pour faire tourner le cône #include <Inventor/Xt/SoXt.h> #include <Inventor/Xt/SoXtRenderArea.h> #include <Inventor/engines/SoElapsedTime.h> #include <Inventor/nodes/SoCone.h> #include <Inventor/nodes/ SoDirectionalLight.h> #include <Inventor/nodes/SoMaterial.h> #include <Inventor/nodes/ SoPerspectiveCamera.h> #include <Inventor/nodes/SoRotationXYZ.h> #include <Inventor/nodes/SoSeparator.h> main(int , char **argv) { Widget myWindow = SoXt::init(argv[0]); if ( myWindow == NULL ) exit(1); SoSeparator *root = new SoSeparator; root->ref(); SoPerspectiveCamera *myCamera = new SoPerspectiveCamera; root->addChild(myCamera); root->addChild(new SoDirectionalLight); SoRotationXYZ *myRotXYZ = new SoRotationXYZ; root->addChild(myRotXYZ); SoMaterial *myMaterial = new SoMaterial; myMaterial->diffuseColor.setValue(1.0, 0.0, 0.0); root->addChild(myMaterial); root->addChild(new SoCone); myRotXYZ->axis = SoRotationXYZ::X; SoElapsedTime *myCounter = new SoElapsedTime; myRotXYZ->angle.connectFrom(&myCounter-> timeOut); SoXtRenderArea *RenderArea = new SoXtRenderArea(myWindow); myCamera->viewAll(root, RenderArea->getViewportRegion()); RenderArea->setSceneGraph(root); RenderArea->setTitle("Moteur de rotation"); RenderArea->show(); SoXt::show(myWindow); SoXt::mainLoop(); } Addition d'un manipulateur trackball #include <Inventor/Xt/SoXt.h> #include <Inventor/Xt/SoXtRenderArea.h> #include <Inventor/manips/SoTrackballManip.h> #include <Inventor/nodes/SoCone.h> #include <Inventor/nodes/ SoDirectionalLight.h> #include <Inventor/nodes/SoMaterial.h> #include <Inventor/nodes/ SoPerspectiveCamera.h> #include <Inventor/nodes/SoSeparator.h> main(int , char **argv) { Widget myWindow = SoXt::init(argv[0]); if (myWindow == NULL) exit(1); SoSeparator *root = new SoSeparator; root->ref(); SoPerspectiveCamera *myCamera = new SoPerspectiveCamera; root->addChild(myCamera); root->addChild(new SoDirectionalLight); root->addChild(new SoTrackballManip); SoMaterial *myMaterial = new SoMaterial; myMaterial->diffuseColor.setValue(1.0, 0.0, 0.0); root->addChild(myMaterial); root->addChild(new SoCone); SoXtRenderArea *RenderArea = new SoXtRenderArea(myWindow); myCamera->viewAll(root, RenderArea->getViewportRegion()); RenderArea->setSceneGraph(root); RenderArea->setTitle("Trackball"); RenderArea->show(); SoXt::show(myWindow); SoXt::mainLoop(); } Utilisation d'une fenêtre de rendu avec zones de contrôle pour des rotations et des agrandissements #include <Inventor/Xt/SoXt.h> #include <Inventor/Xt/viewers/ SoXtExaminerViewer.h> #include <Inventor/nodes/SoCone.h> #include <Inventor/nodes/SoDirectionalLight.h> #include <Inventor/nodes/SoMaterial.h> #include <Inventor/nodes/SoPerspectiveCamera.h> #include <Inventor/nodes/SoSeparator.h> main(int,char **argv) { SoXtExaminerViewer *myViewer ; Widget myWindow = SoXt::init(argv[0]); if (myWindow == NULL) exit(1); SoSeparator *root = new SoSeparator; root->ref(); SoMaterial *myMaterial = new SoMaterial; myMaterial->diffuseColor.setValue(1.0, 0.0, 0.0); root->addChild(myMaterial); root->addChild(new SoCone); myViewer = new SoXtExaminerViewer(myWindow); myViewer->setSceneGraph(root); myViewer->setTitle("Examiner Viewer"); myViewer->show(); SoXt::show(myWindow); SoXt::mainLoop(); } Conventions de syntaxe Les types basiques commencent par Sb.
Toutes les autres classes sont préfixées avec les lettres So (SoCone, SoMaterial, SoTransform,...). Les noms de méthode et de variable commencent par une minuscule. Chaque mot dans un nom commence par une majuscule (getNormal(), setSceneGraph(),...). Les énumérations sont en majuscules (FILLED, PER_PART). Un fichier d'inclusion correspond à chaque classe. Les noeuds et les groupes La base de données de scène La base de données de scène contient les informations concernant une ou plus scènes 3D. Elle est appelée SoDB. La méthode la plus importante associée à SoDB est SoDB::init(). Il s'agit de la première opération à réaliser (SoXt::init() si on utilise la component library pour programmer sous X). Elle réalise l'initialisation de la base de donnée de scène. Les graphes de scène Graphe de scène : composition de un ou plusieurs noeuds représentant individuellement un objet géométrique, une propriété ou un noeud de groupe. Une hiérarchie de noeuds est créée par additions de noeuds en tant que fils de noeud de groupe avec pour résultat la constitution d'un graphe. Les noeuds Création Utilisation de l'opérateur C++ new SoSphere *sphere = new SoSphere; Pas de delete Types de noeuds :
Un noeud est composé d'un ensemble de données appelées champs qui le décrivent. Exemple
Chaque noeud implante ses propres modes d'action. Réalisation d'une action particulière sur une scène -> instanciation de la classe de cette action -> application au noeud racine du graphe de scène Exécution d'une action -> parcours du graphe de scène de la racine aux feuilles et de gauche à la droite (préordre) Exécution d'une action -> gestion d'un état courant (collection de paramètres) :
Durant le parcours du graphe de scène, les noeuds peuvent modifier cet état courant. Création de groupes Utilisation de la classe SoGroup Utilisation de la méthode addchild() Combinaison d'un noeud transform, d'un noeud material et d'un noeud sphere pour constituer un groupe "tête" pour un objet de type robot : SoGroup head = new SoGroup; head->addChild(transform); head->addChild(material); head->addChild(sphere);
Les noeuds d'un groupe sont indexés à partir de 0. Lors du parcours d'un graphe de scène, les noeuds sont évalués dans l'ordre de leurs indexes. Les séparateurs Le noeud SoSeparator (sous-classe de SoGroup) permet d'isoler les effets de certains noeuds d'un groupe par rapport aux autres. Avant de traiter ses fils, le noeud SoSeparator sauvegarde l'état courant et le restaure après traitement. SoTransform *xf1 = new SoTransform; xf1->translation.setValue(0.0, 3.0, 0.0); SoMaterial *bronze = new SoMaterial; bronze->ambientColor.setValue(.33,.22,.27); bronze->diffuseColor.setValue(.78,.57,.11); bronze->specularColor.setValue(.99,.94,.81); bronze->shininess = .28; SoCylinder *myCylinder = new SoCylinder; myCylinder->radius = 2.5; myCylinder->height = 6; SoSeparator *body = new SoSeparator; body->addChild(xf1); body->addChild(bronze); body->addChild(myCylinder); SoTransform *xf2 = new SoTransform; xf2->translation.setValue(0,7.5,0); xf2->scaleFactor.setValue(1.5,1.5,1.5); SoMaterial *silver = new SoMaterial; silver->ambientColor.setValue(.2,.2,.2); silver->diffuseColor.setValue(.6,.6,.6); silver->specularColor.setValue(.5,.5,.5); silver->shininess = .5; SoSphere *mySphere = new SoSphere; SoSeparator *head = new SoSeparator; head->addChild(xf2); head->addChild(silver); head->addChild(mySphere); SoSeparator *robot = new SoSeparator; robot->addChild(body); robot->addChild(head); L'instanciation multiple Un même noeud peut être ajouté à plusieurs groupes -> il possède plusieurs parents. Tout changement du noeud fils sera répercuté sur chacune de ses instances. Exemple : création d'un robot avec deux instanciations d'une jambe SoCube *thigh = new SoCube; thigh->width = 1.2; thigh->height = 2.2; thigh->depth = 1.1; SoTransform *calfTransform = new SoTransform; calfTransform->translation.setValue(0,-2.25,0.0); SoCube *calf = new SoCube; calf->width = 1; calf->height = 2.2; calf->depth = 1; SoTransform *footTransform = new SoTransform; footTransform->translation.setValue(0,-2,.5); SoCube *foot = new SoCube; foot->width = 0.8; foot->height = 0.8; foot->depth = 2; SoGroup *leg = new SoGroup; leg->addChild(thigh); leg->addChild(calfTransform); leg->addChild(calf); leg->addChild(footTransform); leg->addChild(foot); SoTransform *leftTransform = new SoTransform; leftTransform->translation = SbVec3f(1,-4.25,0); SoSeparator *leftLeg = new SoSeparator; leftLeg->addChild(leftTransform); leftLeg->addChild(leg); SoTransform *rightTransform = new SoTransform; rightTransform->translation.setValue(-1,-4.25,0); SoSeparator *rightLeg = new SoSeparator; rightLeg->addChild(rightTransform); rightLeg->addChild(leg); SoTransform *bodyTransform = new SoTransform; bodyTransform->translation.setValue(0.0,3.0,0.0); SoMaterial *bronze = new SoMaterial; bronze->ambientColor.setValue(.33,.22,.27); bronze->diffuseColor.setValue(.78,.57,.11); bronze->specularColor.setValue(.99,.94,.81); bronze->shininess = .28; SoCylinder *bodyCylinder = new SoCylinder; bodyCylinder->radius = 2.5; bodyCylinder->height = 6; SoSeparator *body = new SoSeparator; body->addChild(bodyTransform); body->addChild(bronze); body->addChild(bodyCylinder); body->addChild(leftLeg); body->addChild(rightLeg); SoTransform *headTransform = new SoTransform; headTransform->translation.setValue(0,7.5,0); headTransform->scaleFactor.setValue(1.5,1.5,1.5); SoMaterial *silver = new SoMaterial; silver->ambientColor.setValue(.2,.2,.2); silver->diffuseColor.setValue(.6,.6,.6); silver->specularColor.setValue(.5,.5,.5); silver->shininess = .5; SoSphere *headSphere = new SoSphere; SoSeparator *head = new SoSeparator; head->addChild(headTransform); head->addChild(silver); head->addChild(headSphere); SoSeparator *robot = new SoSeparator; robot->addChild(body); robot->addChild(head); Les champs Les champs d'un noeud créé sont automatiquement initialisés. La syntaxe pour affecter une valeur à un champ dépend :
Exemple SoDrawStyle *d = new SoDrawStyle; d->style.setValue(SoDrawStyle::LINES) ; d->lineWidth.setValue(3) ; d->linePattern.setValue(0xf0f0);
Affectation SoOrthographicCamera *cam = new SoOrthographicCamera; cam->height.setValue(1.); Lecture float result = cam->height.getValue();
Affectation SoTransform *xform = new SoTransform; SbVec3f vector; vector.setValue(2.5, 3.5, 0.0); xform->translation.setValue(vector); SoTransform *xform = new SoTransform; xform->translation.setValue(SbVec3f(2.5,3.5,0.0)); SoTransform *xform = new SoTransform; float x = 2.5, y = 3.5, z = 0.0; xform->translation.setValue(x, y, z); SoTransform *xform = new SoTransform; float floatArray[3]; floatArray[0] = 2.5; floatArray[1] = 3.5; floatArray[2] = 0.0; xform->translation.setValue(floatArray); Lecture SbVec3f t = xform->translation.getValue();
Allocation de la zone mémoire destinée à contenir les valeurs. Affectation et allocation noeud->champ.setValues(starting index, number of values, pointer to array of values); SoMaterial *mtl; float vals[3]; vals[0] = 0.2; vals[1] = 0.5; vals[2] = 0.9; mtl->transparency.setValues(0, 3, vals); Lecture f = mtl->transparency[13]; Insertion float newValues[2]; newValues[0] = 0.1; newValues[1] = 0.2; mtl->transparency.insertSpace(10,2); mtl->transparency.setValues(10,2,newValues); Nombre de valeurs mtl->transparency.getNum() Suppression de valeurs mtl->transparency.deleteValues(8,2); Ignore flag Permet de rendre un champ inactif. SoMaterial *bronze = new SoMaterial; bronze->ambientColor.setValue(.33, .22, .27); bronze->diffuseColor.setValue(.78, .57, .11); bronze->specularColor.setIgnored(TRUE); bronze->shininess = .28; bronze->specularColor.setIgnored(FALSE); if (bronze->specularColor.isIgnored()) { printf("Yes, specular is ignored\n"); } Les caméras et les lumières Les caméras Un noeud caméra génère une image de tout ce qui est défini après lui dans le graphe de scène. Les noeuds caméra sont dérivés de la classe SoCamera.
Actions réalisées lors de la rencontre d'un noeud caméra
SoPerspectiveCamera Sous-classe de SoCamera permettant la visualisation en perspective telle que celle réalisée par l'oeil humain. Un champ supplémentaire : heightAngle (SoSFFloat) : angle vertical du volume de visualisation de la caméra (pyramide tronquée) SoOrthographicCamera Sous-classe de SoCamera permettant la visualisation en projection orthographique (parallèle). Un champ supplémentaire : height (SoSFFloat) : hauteur du volume de visualisation de la caméra (parallélépipède rectangle) Visualisation écran de l'image générée Un viewport est une zone rectangulaire où est affichée une image calculée. Par défaut, le viewport a la même dimension que la fenêtre d'affichage. (SoXtRenderArea). Le champ viewportMapping de SoCamera permet d'indiquer comment mapper la projection de la caméra dans le viewport quand leurs deux aspects ratio différent.
Exemple Trois caméra sont définies :
#include <Inventor/SbLinear.h> #include <Inventor/SoDB.h> #include <Inventor/SoInput.h> #include <Inventor/Xt/SoXt.h> #include <Inventor/Xt/SoXtRenderArea.h> #include <Inventor/nodes/SoBlinker.h> #include <Inventor/nodes/SoDirectionalLight.h> #include <Inventor/nodes/SoMaterial.h> #include <Inventor/nodes/SoOrthographicCamera.h> #include <Inventor/nodes/SoPerspectiveCamera.h> #include <Inventor/nodes/SoSeparator.h> #include <Inventor/nodes/SoTransform.h> main(int, char **argv) { Widget myWindow = SoXt::init(argv[0]); if (myWindow == NULL) exit(1); SoSeparator *root = new SoSeparator; root->ref(); SoBlinker *myBlinker = new SoBlinker; root->addChild(myBlinker); SoOrthographicCamera *c1 = new SoOrthographicCamera; SoPerspectiveCamera *c2 = new SoPerspectiveCamera; SoPerspectiveCamera *c3 = new SoPerspectiveCamera; myBlinker->addChild(c1); myBlinker->addChild(c2); myBlinker->addChild(c3); root->addChild(new SoDirectionalLight); SoInput myInput; if (! myInput.openFile("parkbench.iv")) return 1; SoSeparator *fileContents = SoDB::readAll(&myInput); if (fileContents == NULL) return 1; SoMaterial *myMaterial = new SoMaterial; myMaterial->diffuseColor.setValue(0.8,0.23, 0.03); root->addChild(myMaterial); root->addChild(fileContents); SoXtRenderArea *RenderArea = new SoXtRenderArea(myWindow); SbViewportRegion myRg(RenderArea->getSize()); c1->viewAll(root,myRg); c2->viewAll(root,myRg); c3->viewAll(root,myRg); SbVec3f initialPos; initialPos = c3->position.getValue(); float x,y,z; initialPos.getValue(x,y,z); c3->position.setValue(x+x/2.,y+y/2.,z+z/4.); RenderArea->setSceneGraph(root); RenderArea->setTitle("Cameras"); RenderArea->show(); SoXt::show(myWindow); SoXt::mainLoop(); } Les lumières Toutes les lumières sont dérivées de la classe SoLight.
Trois sous-classes dérivent de SoLight : SoPointLight Définition d'une lumière ponctuelle émettant uniformément dans toutes les directions. Un champ supplémentaire :
SoDirectionalLight Définition d'une lumière émettant uniformément dans une direction particulière. Un champ supplémentaire :
SoSpotLight Définition d'une lumière ponctuelle émettant dans une direction privilégiée définissant un cône d'illumination. Quatre champs supplémentaires :
Exemple #include <Inventor/SoDB.h> #include <Inventor/Xt/SoXt.h> #include <Inventor/Xt/viewers/SoXtExaminerViewer.h> #include <Inventor/nodes/SoCone.h> #include <Inventor/nodes/SoDirectionalLight.h> #include <Inventor/nodes/SoMaterial.h> #include <Inventor/nodes/SoPointLight.h> #include <Inventor/nodes/SoSeparator.h> #include <Inventor/nodes/SoShuttle.h> #include <Inventor/nodes/SoTransformSeparator.h> main(int,char **argv) { Widget myWindow = SoXt::init(argv[0]); if (myWindow == NULL) exit(1); SoSeparator *root = new SoSeparator; root->ref(); SoDirectionalLight *myDirLight = new SoDirectionalLight; myDirLight->direction.setValue(0,-1,-1); myDirLight->color.setValue(1,0,0); root->addChild(myDirLight); SoTransformSeparator *sep = new SoTransformSeparator; root->addChild(sep); SoShuttle *myShuttle = new SoShuttle; sep->addChild(myShuttle); myShuttle->translation0.setValue(-2,-1,3); myShuttle->translation1.setValue( 1, 2,-3); SoPointLight *myPointLight = new SoPointLight; sep->addChild(myPointLight); myPointLight->color.setValue(0,1,0); root->addChild(new SoCone); SoXtExaminerViewer *v = new SoXtExaminerViewer(myWindow); v->setSceneGraph(root); v->setTitle("Lights"); v->setHeadlight(FALSE); v->show(); SoXt::show(myWindow); SoXt::mainLoop(); } |