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 :
- APP : s'occupe
de la mise à jour des données de l'appli,
lecture des périphériques de contrôle, mise à jour de la base de donnée.
- CULL : fait du culling dans la
base de donnée (View-Frustum Culling),
calcule le niveau de LOD,
et génère une display list Performer
des objets à afficher.
- DRAW : s'occupe de la génération
des commandes graphique (pour le geometry engine) et l'affichage.
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
- La géométrie pfGeoSet: dit quoi dessiner
on précise des sommets, normales, couleurs, des faces (indexé ou pas) et des coordonnées de textures.
Performer 2.4 autorise plusieurs textures (multitextures).
- L'apparence pfGeoState: dit comment le dessiner
Les textures, les environnement de texture (glTexEnv, glTexGen, ...), culling, wireframe, lightmodel, matériaux, ...
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:
- dso par défaut (make tout court)
- ddst version debug linké avec les shared libs (lbpf*.so)
- dbg version debug linké en static
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 :
- Gestion des textures + pagination (clipmaping = dans des grandes textures)
- Level of Detail avec fading.
- Affichage de stats graphiques détaillées.
- Contrôle frame rate ( fixe, libre).
- Animation (par des pfEngine modification position, géometrie apparence),
- Shadow,SpotLight, fog.
- Effet visuels avancées: billboard, light point, Shaders (=rendus exotiques en plusieurs passes, description dans des fichiers textes).
- Pagination asynchrone de base de données.
- Modèle de collision, modèle de déplacement (walk, trackball, fly).
.. 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:
- libpf et libpr constitué les librairies de base de Performer pour la gestion de la scène et le rendu.
- libfdb sert principalement pour importer les fichiers de différents formats.
- libpfdu fournit des fonctions avancées pour le contrôle, l'optimisation de la geometrie et l'apparence des objets.
- libpfui s'occupe de la gestion de l'interaction (trackball, navigation ..etc..)
- libpfutil fournit un ensemble de fonctions supplementaire pour la gestion des textures, configuration multiprocesseur ..etc..
Ça a l'air bien, mais y'a pas de doc!!
- man pages: pb entre les man c et c++. Sous Linux man /usr/man/man3/pfGeoSet.3pf.C++ car sinon on récupère /usr/man/man3/pfGeoSet.3pf.c.
REM: avec tkman (cf. astuce pour config iMAGIS ça se passe mieux car on peut choper les autres man-pages.
- insight: taper iiv ou insight sous irix
- en pdf (sous Linux) très utile pour faire des "search": pour débuter
/usr/share/doc/sgi-performer-2.4/Perf_GetStarted/pdf/Perf_GetStarted.pdf
et le
/usr/share/doc/sgi-performer-2.4/Perf_PG/pdf/Perf_PG.pdf
Programming guide
- en html:
/usr/share/doc/sgi-performer-2.4/Perf_GetStarted/html/index.html
et le /usr/share/doc/sgi-performer-2.4/Perf_PG/html/index.html
- si on trouve rien, il reste le grep récursif dans les sources d'exemple qui sont en /usr/share/Performer/src/:
- dernier recours, la mailing list Performer qui est assez active (réponses dans des délais raisonnables) dont les archives sont à consulter avant de poster une question.
Faut il utiliser Performer ?
Avantages
- Portabilité Linux-Irix facile
- Offre plein d'outils déja débuggés:
- les loaders
- le scene-graph
- le culling
- la gestion des affichages complexes.
- Multi-proc: parallélisation des processus de Cull-draw-app automatique
et transparente (flag PFMP_APP_CULL_DRAW).
Problèmes
- Multi-proc: complique tout quand on veut juste afficher un cube.
- gros merdier entre C et C++!
- Callbacks (Raph et Xavier ... pas Eric)
- Lourds à mélanger avec une autre lib qui gère sa MainLoop (Qt au hasard)
- pas de gestion d'applications distribuées, pas de gestion de péripheriques 3D.
Références
©Raphaël, Xadec et Eric