Ma scène OpenGL contient des objets qui sont positionnés à des distances ridiculement éloignées de l'origine. Lorsque je regarde ces objets et que je fais un panoramique / rotation / zoom d'une caméra autour d'eux, ils «tremblent». Autrement dit, les sommets comprenant les objets semblent se casser autour d'une grille de points 3D imaginaire. J'ai lu que c'est un problème courant en raison de la quantité d'informations qui peuvent être stockées en utilisant la précision en virgule flottante (qu'OpenGL, et à peu près tout le reste utilise). Je ne comprends pas pourquoi cela se produit cependant.
Lors de la recherche d'une solution, je suis tombé sur le très simple correctif «origine flottante», et il semble fonctionner. Je transforme simplement tout pour que mes objets soient dans les mêmes positions relatives mais tout ce que mon appareil photo regarde est proche de l'origine. J'ai trouvé une explication ici: http://floatingorigin.com/ , mais je n'ai pas pu la suivre.
Alors ... Quelqu'un pourrait-il expliquer pourquoi le fait de positionner ma scène très loin (disons 10 millions d'unités) de l'origine entraîne le comportement erratique que j'ai observé? Et aussi pourquoi le déplacer près de l'origine résout le problème?
Réponses:
Tout cela est dû à la façon dont les virgules flottantes sont représentées dans les ordinateurs.
Les entiers sont stockés assez simplement; chaque unité est exactement "une" à part de la "précédente" comme vous pouvez vous y attendre avec des nombres dénombrables.
Avec les nombres à virgule flottante, ce n'est pas exactement le cas. Au lieu de cela, plusieurs bits indiquent l'exposant, et le reste indique ce qui est connu comme la mantisse , ou partie fractionnaire qui est ensuite MULTIPLIÉE par la partie exposante (implicitement 2 ^ exp) pour donner le résultat final.
Regardez ici pour une explication visuelle des bits.
C'est précisément parce que cet exposant est une partie réelle des bits que la précision commence à décroître une fois que les nombres augmentent.
Pour voir cela en action, faisons une représentation en virgule flottante sans entrer dans le vif du sujet: prenez un petit exposant comme 2 et faites quelques parties fractionnaires pour tester:
2 * 2 ^ 2 = 8
3 * 2 ^ 2 = 12
4 * 2 ^ 2 = 16
...etc.
Ces chiffres ne croissent pas très loin l'un de l'autre sur l'exposant 2. Mais maintenant, essayons l'exposant 38:
2 * 2 ^ 38 = 549755813888
3 * 2 ^ 38 = 824633720832
4 * 2 ^ 38 = 1099511627776
Whoa, énorme différence maintenant!
L'exemple, même s'il ne va pas spécifiquement à la VERY NEXT COUNTABLE (ce serait la toute prochaine partie fractionnaire en fonction du nombre de bits), est là pour démontrer la perte de précision une fois que les nombres augmentent. L'unité "suivant dénombrable" dans les flottants est très petite avec de petits exposants et TRÈS grande avec des exposants plus grands, alors qu'en entier, elle est TOUJOURS 1.
La raison pour laquelle la méthode de l'origine flottante fonctionne est parce qu'elle met à l'échelle tous ces nombres à virgule flottante à exposant potentiellement grand vers le bas à petit exposant afin que les "prochains comptes" (précision) puissent être très petits et heureux.
la source
Parce que les nombres à virgule flottante sont représentés sous la forme fraction + exposant + signe, et vous n'avez qu'une quantité fixe de bits pour la partie fraction.
http://en.wikipedia.org/wiki/Single_precision
Comme vous obtenez des nombres de plus en plus grands, vous n'avez tout simplement pas les bits pour représenter les plus petites portions.
la source
Le classique du domaine doit être évoqué: ce que tout informaticien doit savoir sur les nombres à virgule flottante .
Mais l'essentiel a à voir avec la façon dont les nombres à virgule flottante de précision simple (double) ne sont qu'un nombre binaire de 32 bits (64 bits) avec 1 bit représentant le signe, un exposant de 8 bits (11 bits) de la base 2 et une signification de 23 bits (52 bits) (les parenthèses sont les valeurs des doubles).
Cela signifie que le plus petit nombre positif que vous pouvez représenter en simple précision est 0,000000000000000000000001 x 2 -127 = 2 -22 x 2 -127 = 2 -149 ~ 1,40 x 10 -45 .
Le nombre positif suivant est le double de: 0,000000000000000000000010 x 2 -127 = 2 -148 ~ 2,80 x 10 -45 , puis le nombre suivant est la somme des deux précédents 0,000000000000000000000011 x 2 -127 = 3 x 2 -149 ~ 4,2 - 45 .
Cela continue d'augmenter de la même différence constante jusqu'à ce que: 0,111111111111111111111111 x 2 -127 = 2 -126 - 2 149 ~ 1,17549435 x 10 -38 - 0,0000000014 x 10 -38 = 1,17549421 x 10 -38
Maintenant , vous avez atteint le nombre normal (où le premier chiffre du significand est 1) spécifiquement: 1,0000000000000000000000 x 2 -126 = 2 -126 = 1,17549435 x 10 -38 et le numéro suivant est alors 1,0000000000000000000001 x 2 -126 = 2 -126 (1 + 2 -22 ) = 1,17549435 x 1,00000023.
la source
La raison pour laquelle les nombres à virgule flottante deviennent moins précis plus loin de l'origine est qu'un nombre à virgule flottante est censé pouvoir représenter de grands nombres. La façon dont cela se fait lui confère le terme "virgule flottante". Il divise les valeurs possibles qu'il peut prendre (qui est déterminée par sa longueur en bits) de sorte qu'il y ait environ le même nombre pour chaque exposant: Pour un flottant de 32 bits, 23 des bits définissent la mantisse ou la signification. Il pourra donc prendre la valeur de 2 ^ 23 valeurs différentes dans chaque plage d'exposants. L'une de ces plages d'exposants est 1-2 [2 ^ 0 à 2 ^ 1], donc la division de la plage 1 à 2 en 2 ^ 23 valeurs différentes permet une grande précision.
Mais en divisant la plage [2 ^ 10 à 2 ^ 11] en 2 ^ 23 valeurs différentes, l'espace entre chaque valeur est beaucoup plus grand. Si ce n'était pas le cas, 23 bits ne suffiraient pas. Le tout est un compromis: vous avez besoin d'un nombre infini de bits pour représenter n'importe quel nombre réel. Si votre application fonctionne d'une manière qui vous permet de vous en sortir avec une précision inférieure pour des valeurs plus grandes, et que vous bénéficiez de la possibilité de représenter réellement de grandes valeurs , vous utilisez une représentation en virgule flottante.
la source
Il peut être un peu difficile de proposer des exemples spécifiques de fonctionnement de la précision en virgule flottante. Pour compléter les autres réponses, en voici une. Disons que nous avons un nombre décimal à virgule flottante, avec trois chiffres de mantisse et un chiffre d'exposant:
Lorsque l'exposant est égal à 0, chaque entier compris entre 0 et 999 peut être représenté avec précision. Lorsqu'il est égal à 1, vous multipliez essentiellement chaque élément de cette plage par 10, vous obtenez donc la plage 0–9990; mais maintenant, seuls les multiples de 10 peuvent être représentés avec précision, car vous n'avez encore que trois chiffres de précision. Lorsque l'exposant est à son maximum de 9, la différence entre chaque paire d'entiers représentables est d' un milliard . Vous échangez littéralement la précision contre la portée.
Cela fonctionne de la même manière avec les nombres binaires à virgule flottante: chaque fois que l'exposant augmente de un, la plage double , mais le nombre de valeurs représentables dans cette plage est divisé par deux . Cela s'applique également aux nombres fractionnaires, ce qui est bien sûr la source de votre problème.
la source
En général, la résolution empire car la résolution est multipliée par la valeur de l'exposant (2 ** partie d'exposant).
en reconnaissance du commentaire de Josh: ce qui précède était juste de mettre la réponse dans une déclaration succincte. Bien sûr, comme j'ai essayé de l'indiquer sur http://floatingorigin.com/ , cela ne fait que commencer vers une solution globale et votre programme pourrait avoir de la gigue à plusieurs endroits: dans le pipeline de précision ou dans d'autres parties du code .
la source
Le tampon de profondeur OpenGL n'est pas linéaire . Plus vous irez loin, plus la résolution sera mauvaise. Je recommande de lire ceci . Quelque chose tiré de là (12.070):
Et un autre (12.040):
Vous devez donc déplacer votre avion de détourage proche le plus loin possible et votre avion lointain le plus proche possible.
la source