IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Précision de calculs trigo.


Sujet :

C++

  1. #1
    Membre éclairé
    Inscrit en
    Octobre 2004
    Messages
    616
    Détails du profil
    Informations forums :
    Inscription : Octobre 2004
    Messages : 616
    Par défaut Précision de calculs trigo.
    Bonsoir, je doit gérer une lasse caméra dans un projet en openGL . Je susi entrain de mettre au point plusieurs fonctions et l'une me pose problème. J'ai reprit le code d'un tutorial sur le web (qui semble très correct), le résultat escompté est là, mais au bout de quelques itératins des imprécisions apparaissent et les calculs sont faussé ( mes valeurs en X et Z finissent pas tendre vers zéro )

    Voila la fonction qui fait une rotation selon un angle :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    void Camera::RotationY(float Angle)
    {
    	// Set Angle in Rad.
    	Angle = static_cast<float>( (Angle/180)*M_PI );
     
    	m_Position.x = (m_Position.x - m_Focalisation->x)*cosf(Angle) - (m_Position.z - m_Focalisation->z)*sinf(Angle) + m_Focalisation->x  ;
    	//m_Position.y = 0 ;
    	m_Position.z = (m_Position.x - m_Focalisation->x)*sinf(Angle) + (m_Position.z - m_Focalisation->z)*cosf(Angle) + m_Focalisation->z ;
     
    }
    Je lui passe la valeur 10 par exemple, suffsament de fois pour faire un tour, puis2.... à chaque tour je constate que je me rapproche de mes axes ( X et Z diminue eet tendent vers zéro ). Au bout d'a peine 5 tour je suis deja tres proche de mes axes ....

    Je pense que cea vient soit de mon approximation de PI, soit des fonction cos et sin ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    #define M_PI     3.14159265358979323846
    cos et sin proviennent de math.h .... enfin <cmath> .

    edit : mes vecteurs de positions , focalisations sont des floats .

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    Le problème est surtout dû au nombre de bits disponibles pour représenter une valeur en virgule flottante...

    Sur PC (32 bits), on peut généralement considérer que
    • Les float sont codés sur 32 bits dont :
      • 23 bits pour la mantisse
      • 8 bits pour l'exposant
      • 1 bit pour le signe
    • Les type double sont codés sur 64 bits dont :
      • 52 bits pour la mantisse
      • 11 bits pour l'exposant
      • 1 bit pour le signe

    Comme, en plus, il y a des problèmes pour représenter certaines valeurs sous forme binaire, tous les éléments sont présents pour arriver au résultat que tu rencontre...

    L'idéal est donc, en gros, de préférer l'utilisation d'un double - voir d'un long double si ton système le supporte - car la précision en est bien meilleure, et permet donc de limiter - à défaut de l'éviter- le problème
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Expert confirmé

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    Surtout on ne fait *jamais* ca:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    	m_Position.x = (m_Position.x - m_Focalisation->x)*cosf(Angle) - (m_Position.z - m_Focalisation->z)*sinf(Angle) + m_Focalisation->x  ;
    	//m_Position.y = 0 ;
    	m_Position.z = (m_Position.x - m_Focalisation->x)*sinf(Angle) + (m_Position.z - m_Focalisation->z)*cosf(Angle) + m_Focalisation->z ;
    Sachant que l'utilisation de flottant induit obligatoirement une erreur, incrémenter "régulièrement" une variable par une valeur flottante augmente d'autant l'erreur en question...

    En général le code de la gestion des rotations est plutôt le suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    class Camera
    {
          float angleX;
     
          inline void RotationX(float angle)
          {
                angle = (angle*M_PI/180.0f);
     
                angleX += angle;
     
                // histoire de pas avoir trop d'erreur après plusieurs tours
                while (angleX < -M_PI) angleX += M_2PI;
                while (angleX > M_PI) angleX -= M_2PI;
     
                // calcul position en *absolu* 
          }
    };

  4. #4
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Si les donnees sont en degres, accumuler les degres et ne faire la transformation en radian qu'a la fin (ca evite de cumuler l'erreur introduite par PI qui n'est pas representable exactement).

  5. #5
    Membre éclairé
    Inscrit en
    Octobre 2004
    Messages
    616
    Détails du profil
    Informations forums :
    Inscription : Octobre 2004
    Messages : 616
    Par défaut
    Merci pour vos réponses :

    Effectivement les double ou long double ne suffisent aps à résoudre le problème. Par contre j'ai du mal à comprendre vos deux derniers messages pour résoudre cela.

    @nicroman, je ne vois pas ce que signifie le "calcul en absolue"

    Si les donnees sont en degres, accumuler les degres et ne faire la transformation en radian qu'a la fin
    A la fin? Quelle fin?


    Pour le moment j'ai juste une fonction qui effectue une rotation d'un certain angle, je ne stock nul part cet angle dans ma classe rotation . Donc je ne vois pas trop le rapport de vos méthodes avec ma classe. Dois-je changer totalement de méthode? (J'ai suivit un tutorial trouvé sur le net)

    Ma classe caméra dont voici le code reprend très exactement la facons de faire du tuto :

    Camera.hpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
     
    #include <Tools/Logger.hpp>
    #include <Engine/Math/Vector3D.hpp>
    #include <string>
     
    #include <windows.h>
    #include <gl/gl.h>
    #include <gl/glu.h>
     
    #define M_PI     3.14159265358979323846
     
    #ifndef CAMERA_HPP
    #define CAMERA_HPP
     
    	class Camera
    	{	
    		public:
    			// Position of the cam
    			Camera(Vector3D<float> Pos);
    			Camera(float x, float y, float z );
     
     
    		   ~Camera();
     
    		   void SetOrientation(Vector3D<float> Orientation);
     
    		   void SetPosition(Vector3D<float> Position);
     
    		   void SetFocalisation(Vector3D<float> * Focalisation);
     
    		   void Focalize();
     
    		   void Distance(float Dist);
     
    		   void DistanceOffset(float Dist);
     
    		   void RotationY(float Angle);
     
    		private :
    			// up
    			Vector3D<float> m_Orientation ;
    			// Focus
    			Vector3D<float> * m_Focalisation ;
     
    			Vector3D<float> m_Position ;
     
    			Vector3D<float> m_DefaultFocus ;
    	}; 
     
    #endif // CAMERA
    camera.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
     
    #include <Engine/Camera.hpp>
     
    // Vector as param for position
    Camera::Camera(Vector3D<float> Pos) : m_DefaultFocus(0.0, 0.0, 0.0 ), m_Orientation(0.0, 1.0, 0.0), m_Focalisation(&m_DefaultFocus) , m_Position( Pos.x, Pos.y, Pos.z )
    {
     
    }
     
    // Float's as param for position
    Camera::Camera(float x, float y, float z ) : m_DefaultFocus(0.0, 0.0, 0.0 ), m_Orientation(0.0, 1.0, 0.0), m_Focalisation(&m_DefaultFocus) , m_Position( x, y, z )
    {
     
    }
     
    Camera::~Camera()
    {
     
     
    }
     
    void Camera::SetPosition(Vector3D<float> Position)
    {
    	m_Position = Position ;
    }
     
    void Camera::SetOrientation(Vector3D<float> Orientation)
    {
    	m_Orientation = Orientation ;
    }
     
    void Camera::SetFocalisation(Vector3D<float> * Focalisation)
    {
    	m_Focalisation = Focalisation ;
    }
     
    // Set the camera in the openGL scene.
    void Camera::Focalize()
    {
    	gluLookAt( m_Position.x, m_Position.y , m_Position.z ,
    			   m_Focalisation->x, m_Focalisation->y, m_Focalisation->z,
    			   m_Orientation.x, m_Orientation.y, m_Orientation.z );	
    }
     
    // Move closer or away from the focalisation source.
    // Dist = distance from the source. ( >=0 )
    void Camera::Distance(float Dist)
    {
    	Vector3D<float> Temp = m_Position - *m_Focalisation ;
    	float Norm = Temp.Length() ;
     
    	m_Position.x = (Dist/Norm)*(m_Position.x - m_Focalisation->x) + m_Focalisation->x ;
    	m_Position.y = (Dist/Norm)*(m_Position.y - m_Focalisation->y) + m_Focalisation->y ;
    	m_Position.z = (Dist/Norm)*(m_Position.z - m_Focalisation->z) + m_Focalisation->z ;
    }
     
    // Move closer or away from the focalisation source.
    // Dist = distance from the actual position of camera
    void Camera::DistanceOffset( float Dist)
    {
    	Vector3D<float> Temp = m_Position - *m_Focalisation ;
    	float Norm = Temp.Length() ;
     
    	// Dont go behind the focus !
    	if ( Norm + Dist >= 0.0 )
    	{
    		m_Position.x = (Dist/Norm)*(m_Position.x - m_Focalisation->x) + m_Position.x ;
    		m_Position.y = (Dist/Norm)*(m_Position.y - m_Focalisation->y) + m_Position.y ;
    		m_Position.z = (Dist/Norm)*(m_Position.z - m_Focalisation->z) + m_Position.z ;
    	}
     
    }
     
    // Rotation on the y axis
    // Angle is in degree
    void Camera::RotationY(float Angle)
    {
    	// Set Angle in Rad.
    	Angle = static_cast<float>( (Angle/180)*M_PI );
     
    	m_Position.x = (m_Position.x - m_Focalisation->x)*cosf(Angle) - (m_Position.z - m_Focalisation->z)*sinf(Angle) + m_Focalisation->x  ;
    	//m_Position.y = 0 ;
    	m_Position.z = (m_Position.x - m_Focalisation->x)*sinf(Angle) + (m_Position.z - m_Focalisation->z)*cosf(Angle) + m_Focalisation->z ;
     
    }

  6. #6
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par Clad3 Voir le message
    Dois-je changer totalement de méthode?
    - Plutôt que de stocker un objet et de le transformer, tu stockes un objet et une transformation. Quand tu en as besoin, tu appliques la transformation. Ça évite une source d'accumulation d'erreurs.

    - Utilise pour la transformation les unités utilisateurs (degré pour les angles apparemment). Ça évite une autre source d'accumulation d'erreurs.

  7. #7
    Membre éclairé
    Inscrit en
    Octobre 2004
    Messages
    616
    Détails du profil
    Informations forums :
    Inscription : Octobre 2004
    Messages : 616
    Par défaut
    - Utilise pour la transformation les unités utilisateurs (degré pour les angles apparemment). Ça évite une autre source d'accumulation d'erreurs.
    Si je suis bien, dans le but d'éliminer le cast en float de la conversion rad/degrée . Il me fut donc juste une verson de sin et cos qui prend en paramètre des degrées donc? (je vais de ce pas voir si cela existe !)

    Plutôt que de stocker un objet et de le transformer, tu stockes un objet et une transformation. Quand tu en as besoin, tu appliques la transformation. Ça évite une source d'accumulation d'erreurs.
    Je crois saisir ta remarque : il est préférable de garder en mémoire : "je me suis déplacer de tant..." que d'effectuer le calcul du déplacement tout le temps.... ce dans le but de pouvoir si on a 2 déplacements successif dans la meme frame, faire un calcul de moins?
    Ca me parait tou a fait raisonable, mais je ne vois pas comment ca va changer mon problème, pusique pour le moment j'ai une rotation qui s'effectue petit à petit, frame par frame et qu'il me faut bien afficher le résultat tout le temps ... donc faire le calcul apres chaque appel a ma fonction rotationY :/

  8. #8
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Non, ce qu'on te propose, c'est de ne pas effectuer tes calculs de manière permanente:

    Considérons qu'au début, la caméra/le bonhome est au point 0, 0, 0, regard orienté "cap au nord".

    Tu retiens les déplacement/rotations effectuées par la caméra / le bonhomme, de manière que tu sache à tout moment déterminer sa position par rapport à son point de départ, et l'orientation de son regard.

    Mettons qu'à un moment T, ton bonhome/ ta caméra, se trouve au point +3.563, 0, -5, et ait le regard oritenté à 35° vers la droite.

    pour ce moment T bien précis, tu prend une copie l'ensemble des points représentant ton monde, et tu fais tout décaler de -3.563,0,+5.

    Puis tu effectue le calcul de rotation pour déterminer ce que le bonhomme/ la caméra voit.

    Le moment d'après, qui est le moment T1, tu recommence, mais pas en fonction de ce qui a été calculé pour le moment T, mais bien en fonction de la position et de l'orientation du regard d'origine.

    De cette manière, chaque calcule ne subit les déformations que d'au maximum 1* l'imprécision

    Maintenant, tu peux envisager de rendre les choses un peu moins lourdes à gérer en "pré calculant" les point qui sont susceptibles d'être proches/à portée de vue du bonhomme au moment d'après, tant il est peu probable que le bonhomme se trouve en 15,12,14 à un moment donné et en -63,-18,23 au moment suivant
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  9. #9
    Membre éclairé
    Inscrit en
    Octobre 2004
    Messages
    616
    Détails du profil
    Informations forums :
    Inscription : Octobre 2004
    Messages : 616
    Par défaut
    Pour le moment le regard de mon bonhomme (donc la focalisation de ma camra) est fixe, donc on peut enlever ca du problème).

    Ce que tu me conseille de faire c'est cela :

    - POUR Chaque frame :
    --- rendre ma scène sans tenir compte de la caméra
    --- récupérer les éventuel déplacement caméra (x,y,z) ainsi que le changement de focalisation
    --- translater la scène a l'inverse de la position courante de la caméra et ensutie fare un glulookat( cam.x, cam.y,cam.z, 0,0,0, 0,1,0) c'est ca?
    - FIN FRAME

    Je ne voi cependant pas ou cela me dispense de ces calculs approximatifs .

    En effet, mon problème est que je suis en mode 3ème personnes pour cette implémentation de caméra . J'ai besoin de trois fonctions pour simuler le déplacement de cette caméra en accord avec ce mode. Une qui me permet de m'éloigner/rapprocher du point de focalisation et 2 pour me déplacer sur la sphere autour de laquelle va graviter ma caméra ( ce sont les fonctions de roations).
    En gros, sans ces calculs je n'ai plus acces à la postions même de la caméra, je ne peux donc pas faire une translation de la scène simplement comme cela.


    Cela dit, je vois bien l'intéret de faire les calculs de manière a ne aps reprendre l'invertitude du calculs précédent et ainsi de suite, je vais réfléchir à une manière de faire de la sorte face à mon problème.
    Merci

    EDIT : Je crois que la seule solution est de repasser avec des angles ( coord polaire) et la norme du vecteur ( Foca-Position )plutot que de garder la position de la caméra en entier. Je trouve ca moins intuitif, c'est pour ca que j'essayais de garder la position de ma caméra à tout instant.

  10. #10
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Mais tu sais suffisemment pour faire une approximation suffisante pour tout ce qui t'inquiète...

    Au pire, tu maintiens également
    • un sens de déplacement (avant/arrière/glissement gauche /glissement droite)
    • un sens de rotation du regard (aucun / tourne à gauche / tourne à droite)

    qui peuvent être connu soit par l'intermédiaire des touches enfoncées qui ont mené le perso à sa position et son orientation actuelles, soit par comparaison avec la position et l'orientation du perso à la frame précédente

    Comme tu sais que, quoi qu'il arrive, dans sa situation actuelle (blessure/ équipement/ à cheval ou autre) le perso ne pourra de toutes façons pas se déplacer au delà de certains points, tu peut déterminer, même de manière "approximative", les limites au delà desquelles la caméra n'a aucune chance de se retrouver
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  11. #11
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    - Plutôt que de stocker un objet et de le transformer, tu stockes un objet et une transformation. Quand tu en as besoin, tu appliques la transformation. Ça évite une source d'accumulation d'erreurs.

    - Utilise pour la transformation les unités utilisateurs (degré pour les angles apparemment). Ça évite une autre source d'accumulation d'erreurs.
    Je retiendrais cette solution.

    En gros, tu stocke un angle en degré et une translation dans une classe transformation.
    Les coordonnées de position et d'orientation de ton perso/de ta cam sont eux stockés dans ta classe de personnage/de camera.

    Lorsque tu appliques une rotation de 30°, tu fais angle += 30 et tu recalcule l'orientation du perso/de la cam. Il y aura une erreur très faible puisque l'angle en degré est conservé.

  12. #12
    Membre éclairé
    Inscrit en
    Octobre 2004
    Messages
    616
    Détails du profil
    Informations forums :
    Inscription : Octobre 2004
    Messages : 616
    Par défaut
    Effectivment je vais faire comme cela : (dés que je serai de retour chez moi)

    Dans ma classe caméra je vais stocker la focalisation (le regard donc), la distance de ma caméra par rapport a sa focalisation, et deux angle représentant sa position sur la sphére. Ainsi a chaque frame, quand je devrai positionner ma caméra, j'aurais un seul calcul a faire ( a base de sin et cos) et je ne me baserai pas sur mes imprécisions précédente puisque je vais juste garder en mémoire des angles que je changerai au fur et à mesur de mes mouvement de caméra) .

    Je pense que ca va marcher sans problème .

    En fin de compte la position de ma caméra ne sera plus sotcké dans ma classe, car elle n'aura plus d'utilité... c'est juste ca que je trouve dommage. ( mais c'est simplement que je n'aime pas les angles et que je me repère assez mal avec ^^)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Débutant] Améliorer la précision des fonctions trigo
    Par candrau dans le forum MATLAB
    Réponses: 3
    Dernier message: 12/01/2012, 10h10
  2. scipy.poly1d : précision du calcul des racines
    Par ryced dans le forum Calcul scientifique
    Réponses: 5
    Dernier message: 25/01/2010, 10h04
  3. précision de calcul de fsolve
    Par Nabuchodonosor15 dans le forum MATLAB
    Réponses: 3
    Dernier message: 22/07/2009, 13h34
  4. Choisir la précision pour calculs en nombres flottants
    Par ciol2.6.12 dans le forum Algorithmes et structures de données
    Réponses: 2
    Dernier message: 02/06/2008, 14h14
  5. Précision de calcul
    Par Mucho dans le forum Général Java
    Réponses: 10
    Dernier message: 21/02/2008, 14h02

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo