Configuration d'une Caméra HUD
La création d'une interface Heads-Up Display (HUD) dans OpenSceneGraph (OSG) nécessite l'utilisation d'une caméra dédiée fonctionnant avec une matrice de projection orthographique. Pour garantir un affichage optimal et indépendant de la scène 3D principale, plusieurs paramètres doivent être rigoureusement configurés :
- Isoler le HUD dans une nouvelle instance de caméra.
- Désactiver l'éclairage pour assurer une luminosité constante des éléments 2D.
- Désactiver le test de profondeur (Depth Test) pour éviter l'occlusion des éléments HUD par la géométrie 3D.
- Définir l'ordre de rendu sur
POST_RENDERafin que le HUD soit dessiné par-dessus la scène principale. - Utiliser un référentiel absolu :
setReferenceFrame(osg::Transform::ABSOLUTE_RF). - Réinitialiser la matrice de vue à l'identité pour ignorer les transformations des nœuds parents.
- Configurer la matrice de projection pour qu'elle corresponde aux dimensions de la fenêtre d'afficahge.
Concepts Fondamentaux : Caméra et Viewport
Dans l'architecture d'OSG, la caméra (osg::Camera) et le viewport (osg::Viewport) sont indissociables pour le rendu 3D. La caméra agit comme un objectif virtuel capturant la scène, tandis que le viewport définit la zone rectangulaire de la fenêtre où cette capture sera projetée.
Transformations de la Caméra
- Transformation de vue : Positionne et oriente la caméra dans l'espace monde.
- Transformation de projection : Définit le volume de vue (frustum). OSG supporte la projection perspective (simulant la vision humaine avec déformation) et la projection orthographique (conservant les proportions indépendamment de la distance).
- Transformation de viewport : Mappe les coordonnées normalisées du volume de vue vers les coordonnées pixel de l'écran.
Définition du Viewport
Le viewport est défini par ses coordonnées inférieures gauches et ses dimensions. L'assignation se fait via la méthode setViewport :
hudCamera->setViewport(new osg::Viewport(x_offset, y_offset, view_width, view_height));
Configuration de la Matrice de Vue (LookAt)
La fonction setViewMatrixAsLookAt permet d'orienter précisément la caméra :
void setViewMatrixAsLookAt(const osg::Vec3d& eye, const osg::Vec3d& center, const osg::Vec3d& up);
eye: Position de la caméra dans l'espace monde.center: Point focal vers lequel la caméra est dirigée.up: Vecteur définissant l'orientation verticale de la caméra.
Note : Lors de l'utilisation de cette méthode, il est impératif de désactiver le manipulateur de caméra (viewer->setCameraManipulator(nullptr)) pour éviter qu'il n'écrase la matrice de vue à chaque frame. OSG utilisant un système de coordonnées droitier, assurez-vous que vos vecteurs respectent cette convention.
Implémentation de la Caméra HUD Synchronisée
Voici l'implémentation d'une caméra HUD qui synchronise sa rotation avec la caméra principale, tout en restant fixée dans un coin de l'écran.
Initialisation de la Caméra HUD
// Création et configuration de la caméra HUD
osg::ref_ptr<SynchronizedHudCamera> hudCam = new SynchronizedHudCamera;
hudCam->attachMainCamera(_viewer->getCamera());
// Référentiel absolu et matrice de vue neutre
hudCam->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
hudCam->setViewMatrix(osg::Matrix::identity());
// Nettoyage du buffer de profondeur et ordre de rendu final
hudCam->setClearMask(GL_DEPTH_BUFFER_BIT);
hudCam->setRenderOrder(osg::Camera::POST_RENDER);
hudCam->setAllowEventFocus(false);
// Configuration des états de rendu pour le nœud géométrique
osg::ref_ptr<osg::StateSet> hudState = hudGeode->getOrCreateStateSet();
hudState->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
hudState->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
hudCam->addChild(hudGeode.get());
rootNode->addChild(hudCam.get());
Définition de la Classe SynchronizedHudCamera
#ifndef SYNCHRONIZED_HUD_CAMERA_H
#define SYNCHRONIZED_HUD_CAMERA_H
#include <osg/Camera>
#include <osg/CopyOp>
class SynchronizedHudCamera : public osg::Camera
{
public:
SynchronizedHudCamera();
SynchronizedHudCamera(const SynchronizedHudCamera& src, const osg::CopyOp& copyOp = osg::CopyOp::SHALLOW_COPY);
META_Node(osg, SynchronizedHudCamera);
void attachMainCamera(osg::Camera* mainCam);
virtual void traverse(osg::NodeVisitor& nv) override;
protected:
virtual ~SynchronizedHudCamera();
osg::observer_ptr<osg::Camera> _mainCameraRef;
};
#endif
#include "SynchronizedHudCamera.h"
SynchronizedHudCamera::SynchronizedHudCamera() : osg::Camera() {}
SynchronizedHudCamera::SynchronizedHudCamera(const SynchronizedHudCamera& src, const osg::CopyOp& copyOp)
: osg::Camera(src, copyOp), _mainCameraRef(src._mainCameraRef) {}
SynchronizedHudCamera::~SynchronizedHudCamera() {}
void SynchronizedHudCamera::attachMainCamera(osg::Camera* mainCam)
{
_mainCameraRef = mainCam;
}
void SynchronizedHudCamera::traverse(osg::NodeVisitor& nv)
{
if (_mainCameraRef.valid())
{
double fov, aspect, zNear, zFar;
_mainCameraRef->getProjectionMatrixAsPerspective(fov, aspect, zNear, zFar);
// Application d'une projection orthographique pour annuler l'effet de zoom
const double orthoScale = 50.0;
this->setProjectionMatrixAsOrtho(-orthoScale * aspect, orthoScale * aspect,
-orthoScale, orthoScale, zNear, zFar);
// Synchronisation de la rotation avec la caméra principale
osg::Matrix viewMat = _mainCameraRef->getViewMatrix();
// Translation pour ancrer le HUD en bas à gauche de l'écran
osg::Vec3d anchorOffset(-40.0, -40.0, 0.0);
viewMat.setTrans(anchorOffset);
this->setViewMatrix(viewMat);
}
osg::Camera::traverse(nv);
}
Dépannage et Optimisations
1. Problèmes de Dimension et de Centrage du Viewport
Symptôme : Le HUD ne s'affiche pas correctement au centre ou est tronqué lors du redimensionnement de la fenêtre.
Analyse : Ce problème survient souvent lors de l'intégration d'OSG avec des frameworks GUI comme Qt. La projection orthographique et les dimensions du viewport doivent être parfaitement alignées. Si le ratio de la fenêtre ne correspond pas à la zone de projection, des artefacts de troncature apparaissent.
Solution : S'assurer que le viewport initial possède une résolution minimale cohérente (par exemple, 800x800) et que la classe d'intégration Qt-OSG ne force pas des valeurs par défaut inférieures qui brideraient le calcul de la matrice de projection.
2. Gestion de la Transparence du Fond HUD
Symptôme : Le fond de la caméra HUD reste opaque malgré les tentatives d'application d'alpha.
Analyse : Contrairement à un simple nœud texte HUD, une caméra dédiée possède son propre buffer de couleur. Si le masque de nettoyage (clear mask) n'est pas configuré pour inclure le buffer de couleur avec une valeur alpha, le fond restera opaque.
Solution : Ajuster les paramètres de setClearColor avec une valeur alpha à 0.0 et s'assurer que le pipeline de rendu supporte le mélange (blending) au niveau du StateSet du HUD.
3. Géométries Blanches après Désactivation de l'Éclairage
Symptôme : Les formes géométriques intégrées apparaissent entièrement blanches lorsque GL_LIGHTING est désactivé.
Solution : Lorsque l'éclairage global est éteint, OSG utilise les couleurs des matériaux par défaut. Il est nécessaire d'activer le mode GL_COLOR_MATERIAL ou d'assigner explicitement un osg::Material avec des couleurs ambiantes et diffuses définies pour le StateSet du HUD.
4. Textes Hors Champ ou Illisibles
Symptôme : Les étiquettes textuelles ne sont pas visibles ou semblent massives.
Solution : Cela indique que l'échelle de la projection orthographique est trop petite par rapport aux coordonnées du texte. Augmentez les paramètres de setProjectionMatrixAsOrtho (par exemple, de ±50 à ±100) pour élargir le champ de vision de la caméra HUD, ce qui réduira visuellement la taille des éléments.
5. Désalignement du Centre de Rotation
Symptôme : Le gizmo ou l'indicateur de rotation du HUD pivote autour d'un point qui n'est pas le centre géométrique de l'objet.
Solution : Le centre de rotation par défaut dans OSG est l'origine (0,0,0). Au lieu de modifier les matrices de transformation de manière complexe, il est préférable de modéliser la géométrie du HUD de sorte que son centre logique soit exactement à (0,0,0), puis d'appliquer une translation uniquement aux étiquettes textuelles pour les décaler de l'origine.
6. Inversion de l'Axe de Rotation
Symptôme : Les mouvements de rotation du HUD sont inversés par rapport à la caméra principale.
Solution : Cette anomalie provient généralement d'une erreur dans les paramètres de la projection orthographique. Si les valeurs Y sont définies de 50 à -50 au lieu de -50 à 50, l'axe vertical est inversé. Corrigez l'appel à setProjectionMatrixAsOrtho pour respecter l'ordre (left, right, bottom, top). Pour les problèmes d'éclairage inversés qui en découlent, il est recommandé d'ajouter une source lumineuse directionnelle locale directement attachée au nœud du HUD plutôt que de dépendre de l'éclairage global de la scène.