C'est quoi

Type: Librairie graphique haut niveau.
Plateforme: IRIX, LINUX.
Langage: C, C++.
Accès: version démo de ~140 jours sous Linux, Payant (?) sur IRIX.
Version du moment: 2.4

Principes de base

IRIS Performer est une librairie graphique haut niveau qui permet de créer des applications complexes (simulation temps réel), pouvant supporter de multiples fenêtres, multiples écran, multiples cartes vidéos. Elle peut être utilisée pour réaliser des programmes dans le domaine de la simulation visuelle, réalité virtuelle, navigation dans des espaces architecturaux, loisirs interactifs ..etc.. On peut le définir comme une surcouche d'OpenGL sur lequel il s'appuie pour faire le rendu.

Une simulation visuelle respecte en géneral le schéma suivant :
L'utilisateur met à jour ses données, lit les actions de l'utilisateur, met à jour les éléments graphiques (ainsi que la position de la caméra) puis affiche la scène.

La philosophie de Performer est de séparer les différents aspects d'une simulation dans 3 processus différents :

Le grand intérêt de cette séparation se justifie sur une machine multiprocesseur où on peut alors faire tourner ces processus en parallèle.

Pour permettre le partage de données et la synchronisation Performer définit une zone nommée Shared Arena commune aux processus :

Rendu

Performer utilise un graphe de scène pour représenter les différents éléments visuels. Ce graphe de scène est utilisé par le process CULL pour regrouper les objets dans des volumes englobants hiérarchiques qui lui permet de réaliser efficacement le culling.

Performer supporte les notions de multipipe, multi-window, multi-channel.

Utilisation

Structure de base




Hello World!

Un exemple de programme vide, simple.C: #include <iostream.h> #include <stdlib.h> #include <Performer/pf.h> #include <Performer/pf/pfChannel.h> #include <Performer/pf/pfNode.h> #include <Performer/pf/pfScene.h> #include <Performer/pf/pfDCS.h> #include <Performer/pf/pfGeode.h> #include <Performer/pf/pfLightSource.h> #include <Performer/pfutil.h> #include <Performer/pfdu.h> #include <Performer/pfui.h> #include <Performer/pfui/pfiXformer.h> pfiTDFXformer* xformer = NULL; bool exitNow = false; pfuEventStream events; void handleEvents(void) { pfuGetEvents(&events); // process each of the events; dev is the kind of event, val is // its value, such as a keyboard event with an ASCii value of 27. for (int j=0; j < events.numDevs; ++j) { int dev = events.devQ[j]; if ( events.devCount[dev] > 0) { switch ( dev ) { case PFUDEV_WINQUIT: exitNow = true; events.devCount[dev] = 0; break; case PFUDEV_KEYBD: { // process keyboard input for (int i=0; i < events.numKeys; ++i ) { int key = events.keyQ[i]; if ( events.keyCount[key] ) { switch (key) { case 27: // escape key; exit program exitNow = true; break; case 'r': xformer->stop(); xformer->reset(); break; default: break; } } } } events.devCount[dev] = 0; break; case PFUDEV_REDRAW: events.devCount[dev] = 0; break; default: break; } } // devcount } // numDev events.numKeys = 0; events.numDevs = 0; } int main (int argc, char *argv[]) { if (argc < 2) cout << "Usage: " << argv[0] << " " << endl; pfInitArenas(); // Initialize Performer pfInit(); pfuInitUtil(); pfiInit(); pfMultiprocess( PFMP_APPCULLDRAW ); // Load all loader DSO's before pfConfig() forks pfdInitConverter(argv[1]); pfConfig(); // Append to Performer search path, PFPATH, files in // /usr/share/Performer/data */ pfFilePath(".:/usr/share/Performer/data"); pfNode *root = pfdLoadFile(argv[1]); if (root == NULL) { pfExit(); exit(-1); } // determine extent of scene's geometry pfSphere bsphere; root->getBound(&bsphere); // Attach loaded file to a new pfScene pfScene* scene =new pfScene; //add a light scene->addChild(new pfLightSource); // recenter the model to (0,0,0) pfMatrix transfo; transfo.makeTrans(-bsphere.center[PF_X], -bsphere.center[PF_Y], -bsphere.center[PF_Z]); pfMatrix mscale; float scal = 1./bsphere.radius; mscale.makeScale(scal, scal, scal); transfo = transfo + mscale; pfSCS* recenter = new pfSCS(transfo); recenter->addChild(root); recenter->flatten(0); recenter->getBound(&bsphere); // adding a DCS for Trackball movement pfGroup* group = new pfGroup; group->addChild(recenter); pfDCS* dcs = new pfDCS; dcs->addChild(group); scene->addChild(dcs); // Configure and open window pfPipe *p = pfGetPipe(0); pfPipeWindow *pw = new pfPipeWindow(p); pw->setWinType(PFPWIN_TYPE_X); pfuInitInput(pw, PFUINPUT_X); pw->setName("simpl"); pw->setOriginSize(30,30,500,500); pw->open(); // Create and configure a pfChannel. pfChannel* chan = new pfChannel(p); chan->setScene(scene); chan->setFOV(45.0f, 0.0f); chan->setNearFar(0.1f, 100.0f * bsphere.radius); chan->setLODAttr(PFLOD_SCALE,2.15f); chan->setLODAttr(PFLOD_FADE,1.0f); // Init pos pfCoord view; view.xyz.copy(bsphere.center); view.xyz[PF_Y] -= 2.*bsphere.radius; view.hpr.set(0.0f,0.0f,0.0f); chan->setView(view.xyz, view.hpr); // Trackball pfuMouse mouse; xformer = new pfiTDFXformer; xformer->setAutoInput(chan, &mouse, &events); xformer->setAutoPosition(chan, dcs); xformer->selectModel(PFITDF_TRACKBALL); xformer->setNode(group); xformer->setCoord(&view); xformer->setResetCoord(&view); // Global scene pre/post draw (affichage des stats) // scene->setTravFuncs(PFTRAV_DRAW, preDraw, postDraw); while (!exitNow) { pfuGetMouse(&mouse); xformer->update(); // Go to sleep until next frame time. pfSync(); // Initiate cull/draw for this frame. pfFrame(); handleEvents(); } // Terminate parallel processes and exit pfuExitInput(); pfuExitUtil(); pfExit(); }

... et le joli Makefile qui va avec (qui compile sous Linux et Irix): #!smake PFROOT = / include $(PFROOT)/usr/share/Performer/src/pfmakedefs #-- provide a list of alternate locations for file searches UNIQUE = .. #-- alternate locatins for included files LCXXINCS = \ -I${UNIQUE} \ -I${QTDIR}/include \ -I${PFROOT}/usr/include/CC \ -I${PFROOT}/usr/include #-- base name of program TARGET = simple.${PFABI} #-- files from which the target is built {some are in the common directory} CXXFILES = \ simple.C include $(PFROOT)/usr/share/Performer/src/pfmakerules #-- objects are built from either unique or common files VPATH = ${UNIQUE} .PATH: ${UNIQUE} Plusieurs cibles par défaut dans Performer: REM: static et dynamique .. on peut savoir avec ldd simple pour Linux et elfdump -Dl simple pour Irix.

Fonction avancées

Multipipe

L'autre interet c'est de supporter plusieurs cartes graphique (synchroniser) pour réaliser en paralllèle différents rendu d'une scène. Pour cela on peut définir plusieurs pipeline software de rendu ( constitué par les process CULL/DRAW), qu'on associe à une une carte graphique.

Multi-window Multi-channel

Sur chaque pipeline on peut définir plusieurs fenêtre de rendu (pfPipeWindow), puis plusieurs camera (pfChannel) dans chaque fenetre.

On peut aussi associer les camera à des sorties différentes(pfPipeVideoChannel) sur la carte vidéo (à partir de la même pfPipeWindows) :

Intersections

Performer supporte l'intersection 3D en désignant un processus spécifique qui s'occupe des calculs d'intersections pour un segment ou un ensemble de segments (accès à l'objet, le triangle et le point d'intersection).

Chargement/conversion de modèles

Un autre aspect concerne le chargement de base de données d'objets 3D (ou de scène 3D) provenant de fichiers de formats différents (3DS, IV, PFB, VRML, 40 formats ..). Pour répondre à ce besoin il se base sur des loader specifiques désignés par l'extension du fichier. On peut facilement programmer son propre loader pour son propre format (voir les codes sources de loaders non-commerciaux en exemple dans /usr/share/Performer/src/lib/libpfdb/libpf*) .

Il supporte aussi de nombreuses fonctionnalités :

.. aller jouer avec les exemples dans /usr/share/Performer/data et perfly pour visualiser.

Organisation

Toutes ces fonctionnalités sont regroupés dans 2 librairies principales et 4 librairies secondaires:

Ça a l'air bien, mais y'a pas de doc!!

Faut il utiliser Performer ?

Avantages

Problèmes

Références

©Raphaël, Xadec et Eric