Limiter nombre fps [opengl & queryperformance & devcpp]

Description

Dans la plupart des jeux, il est possible de limiter le nombre d'images par seconde (FPS, frames per second) que peut afficher un jeu.

Il est souvent inutile de gaspiller du temps machine pour afficher jusqu'à 3000 FPS avec des cartes graphiques dernier cri (aaaaaahhh !). L'oeil n'en percoit qu'une centaine au maximum.

Ce programme :
  • calcule le nombre de FPS.
  • limite le nombre de FPS selon votre choix.
  • déplace les objets selon la méthode du TimeStep (déplacement en fonction du temps).
  • toutes les valeurs des variables sont affichées en temps réel (toutes les 1s).


Comment faire ?
  • Le principal soucis pour calculer le nombre d'images par seconde est de réussir à trouver des fonctions de timing très précises. Les fonctions classiques sont trop imprécises (de l'ordre de 1 à 10 ms). C'est une précision insuffisante lorsqu'on désire afficher plus de 100 FPS (ca nous fait une image toutes les 10ms ou moins). Les seules fonctions intéressantes sont QueryPerformanceFrequency et QueryPerformanceCounter (qui existent bien sur tous les processeurs, quoi qu'en dise la MSDN, qui doit dater un peu). Leur seul inconvénient est de ne pas donner directement le temps, il faut au préalable diviser le nombre de cycle par la fréquence du nombre de cycles par seconde. Il y a donc un coût en temps supplémentaire pour les divisions et également un coût en mémoire pour stocker les résultats en seconde dans des variables de type double.
  • Le nombre de cycles est un résultat beaucoup plus précis que le millième de seconde. Un cycle correspond environ (sur mon PC, Barton 3200+) à 270 nano secondes.
  • Pour calculer le nombre de frames par seconde (FPS), nous allons comptabiliser toutes les frames affichées (temps.nbFrames). Ensuite, toutes les secondes, on affiche le résultat et on remet le compteur à 0. Le résultat est assez précis.
  • Pour limiter le nombre de FPS, il faut 2 variables. Il faut comptabiliser le nombre de cycles maintenant (temps.cSuiv) et le nombre de cycles pour la prochaine frame (temps.cSuiv). Dès que temps.cNow > temps.cSuiv, on dessine une nouvelle image et on augmente temps.cSuiv. Si on veut beaucoup de FPS, on ajoutera un peu de cycles à temps.cSuiv, ou inversement.
  • Pour animer un objet, on n'incrémentera pas son déplacement de manière statique à chaque image (pos++). On utilisera le temps qu'il s'est écoulé entre deux frames (pos += temps.cSuiv - temps.cPrec) pour savoir où l'objet sera placé.
  • Concernant l'affichage OpenGL, la fonction glutSwapBuffers() permet un affichage en double buffering. Il faut uniquement l'utiliser lorsqu'on est sur le point d'afficher une nouvelle image (temps.cNow > temps.cSuiv). La fonction glutPostRedisplay() permet de redemander l'affichage d'une nouvelle image, il faut toujours utiliser cette fonction à la fin de l'affichage, que la frame précédente soit affichée ou non.

Source / Exemple :


[code]
//------------------------------------------------------------------------------
// Structures
//------------------------------------------------------------------------------

    // Gestion du temps : toutes les variables ne sont pas indispensables
    struct TEMPS
    {
        // Par rapport au démarrage de Windows
        LONGLONG cBase;             // Nombre de cycles depuis le démarrage de Windows, trouvé au démarrage de l'application
        LONGLONG cPrec;             // Nombre de cycles depuis le démarrage de Windows, trouvé lors du dernier rendu
        LONGLONG cNow;              // Nombre de cycles depuis le démarrage de Windows, trouvé actuellement
        LONGLONG cSuiv;             // Nombre de cycles depuis le démarrage de Windows, qu'on doit atteindre pour le prochain rendu
        
        // Par rapport au démarrage de l'application
        LONGLONG cBegin;            // Nombre de cycles écoulés uniquement depuis le démarrage de l'application
        LONGLONG allFrames;         // Nombre de frames depuis le démarrage de l'application
        LONGLONG allFramesPrec;     // Nombre de frames depuis le démarrage de l'application
        LONGLONG cUneSeconde;       // On attend une seconde pour comptabiliser le nombre de frames
        long int ns;                // Nombre de nano secondes depuis le démarrage de l'application

        // Par rapport aux conversions temps <=> cycle
        LONGLONG frequence;         // Nombre de cycles par seconde (de l'ordre de 3 millions avec un Barton 3200+)
        double   tpsPerC;           // Temps en seconde entre deux cycles
        
        // Par rapport aux frames
        LONGLONG cPerFrame;         // Nombre de cycles qui doivent s'écouler entre deux frames (pour la limitation)
        LONGLONG cEcoule;           // Nombre de cycles écoulés entre deux frames (pour le TimeStep)
        double   ecoule;            // Temps en secondes entre deux frames (pour le TimeStep)
        LONGLONG nbFrames;          // Nombre de frames affichées (remis à 0 toutes les secondes)
        double   fps;               // Nombre de frames par seconde (mis à jour toutes les secondes via nbFrames)
    };
    struct TEMPS temps;
/code

Conclusion :


Utiliser les touches '-' et '+' pour changer le framerate.
Si vous avez une autre méthode : laissez moi un message.

Vous pouvez comparer les résultats inscrits dans la barre du titre de la fenêtre OpenGL avec des programmes tels que FRAPS (qui affichent le nombre de FPS). Ils sont identiques normalement.

Enjoy,
BeLZeL

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.