10
votes

Floats 16 bits et gl_half_float

Je cherche / écrire une implémentation C ++ d'un numéro de point flottant de 16 bits à utiliser avec des tampons de vertex OpenGL (coordonnées de texture, normales, etc.). Voici mes exigences jusqu'à présent:

  • doit être 16 bits (évidemment). Li>
  • doit pouvoir être téléchargé sur un tampon de sommet openGL à l'aide de GL_HALF_FLOAT. LI>
  • doit être capable de représenter des nombres au-delà de -1,0 - +1,0 (sinon je voudrais simplement utiliser GL_SHORT NORMALISÉ). LI>
  • doit être capable de convertir et d'un flotteur 32 bits normal. LI>
  • Les opérations arithmétiques n'aiment pas - je me soucie seulement de stockage. Li>
  • la vitesse n'est pas une préoccupation principale, mais la correction est la correction. li> ul>

    Voici ce que j'ai jusqu'à présent pour une interface: p> xxx pré>

    finalement, la vraie viande de la classe se situe dans le tofloat () et Fromfloat () Code> Fonctions, ce qui est ce dont j'ai besoin d'aide. J'ai été en mesure de trouver de nombreux exemples d'implémentations de float de 16 bits, mais aucun d'entre eux ne mentionne si elles peuvent être téléchargées ou non sur OpenGL ou non. P>

    Quelles sont certaines préoccupations que je devrais être au courant de la mise en téléchargement d'un flotteur 16 bits sur OpenGL? Existe-t-il une implémentation à moitié float qui traite spécifiquement de ces préoccupations? P>

    Edit: par la demande populaire, voici comment mes données de sommet sont générées, téléchargées et rendues. P>

    Voici comment Les données sont définies dans la classe wirecubeentity: p> xxx pré>

    VA code> est une instance de vertexarray. Va.load CODE> est défini comme suit: P>

    void VertexArray::draw(void)
    {
        if (ready == false)
            return;
    
        /* Bind our vertex array */
        bindArray();
    
        /* Draw it's contents */
        if (ibo == 0)
            glDrawArrays(prim, 0, vcount);
        else
            glDrawElements(prim, icount, iformat, NULL);
    
        unbindArray();
    }
    


3 commentaires

Cela vaut la peine d'être vérifiée: Half.Sourceforge.net (Disclaimer: c'est de moi). C'est IEEE / OPENGL-CONFORMANT, prend en charge tous les arithmétiques et conversions et s'efforce à la fois de performances et d'intégration simplifiée dans l'infrastructure C ++ existante (avec un support possible C ++ 11 lorsque cela est réalisable). Il devrait être parfaitement capable d'être up / téléchargé vers / depuis OpenGL immédiatement sur tout système raisonnable.


Le format que OpenGL attend est décrit dans OpenGL.org/registry/Specs/arb/ Half_float_Pixel.txt comme 5 bits d'exposant et 10 bits de Mantissa. Pour flotteur, il est respectivement 8 et 23. Vous ne pouvez-on pas simplement tapisser un float dans un pittoresque et copier le signe, la mantissie et l'exposant à un autre Bitfield?


@Damon Malheureusement, avec simplement la copie sur le champ de Bitfield, il est pas fait. Même désagréger toutes les valeurs spéciales telles que INFS et NANS, vous devrez toujours m'occuper de sous-flux (et bien sûr les différents biais exposants). Cependant, je suis d'accord, il est plus facile de ne pas vous soucier de la conformité de l'IEEE strict et de chaque cas séparé, mais la copie des bits est toujours un peu moins moins.


3 Réponses :


4
votes

the bibliothèque GLM prend en charge Types de demi-float . Le préfixe utilisé est "h 'alors où GLM :: Vec3 est un vecteur de 3 éléments de valeurs de points flottants, GLM :: hvec3 est un vecteur de 3 éléments de demi-floattes .


9 commentaires

J'ai parcouru à travers le GLM et je n'arrive pas à trouver une implémentation pour le type moitié . Même dans demi_float.inl, je n'arrive pas à le trouver ...


J'ai copié la mise en œuvre de GLM, mais je reçois des résultats bizarres. Par exemple, lorsque je convertitons "0.9001F" à une demi puis retour à un flotteur, je reçois "0,899902F". Est-ce quelque chose qui inhérent à utiliser des flotteurs 16 bits ou est-il imparfait?


Oui, il est inhérent à 16 bits flotteurs. Vous avez moins de morceaux de précision afin que vous allez avoir une différence de potentiel plus importante entre le flotteur d'entrée et le flotteur de sortie. Vous obtenez la même chose avec des flotteurs normaux, avec plus de chiffres de précision.


Devrais-je avoir des préoccupations concernant l'envoi à OpenGL?


Je viens de le tester, et non, ça n'a pas fonctionné. Ce qui était utilisé pour être un beau cube est maintenant soupe au sommet.


OpenExR a également une classe «moitié» qui est compatible OpenGL. Cela ressemble à une copie ici: Sidefx.com/docs/hdk12.1 /half_8h_source.html


J'ai besoin de la mise en œuvre de "Convertir", ce qui n'est pas dans ce fichier.


Quelle est la performance comme pour GLM :: moitié? Je ne peux pas imaginer que c'est très rapide s'il n'y a pas de support matériel pour cela. Est-ce plus performant dans de grandes matrices, où la localité de données entre en jeu? Si oui, quelle est la taille d'un tableau doit être de justifier son utilisation?


Le point n'est pas vraiment nécessairement de commencer à utiliser GLM :: moitié où vous pourriez utiliser autrement float. Il s'agit généralement d'un mécanisme permettant de stocker des données que vous pourriez ensuite transmettre au GPU. Avoir un tableau de GLM :: moitié va être plus facile à traiter dans le débogueur que de simplement avoir un caractère non signé * ou annulé * à un groupe d'octets qui n'ont aucun sens.



13
votes

modifier em> strong>: l'erreur la plus évidente apparaît dans votre structure Vertexhalf. Vous avez un élément de rembourrage. Pourtant, lorsque vous spécifiez votre GLVERTEXATTRIBPOISER, vous spécifiez un 0 dans la foulée qui l'indique qu'il est bien emballé. Vous pouvez donc changer de vertexhalf pour éliminer le rembourrage ou modifier votre GLVERXATTRibpoinger pour avoir une foulée de 8 octets.

J'utilise la classe suivante avec DirectX pour le support float16 et cela fonctionne parfaitement. P>

float16.h : p> xxx pré>

float16.cpp: p> xxx pré>

/ + ---- + - + - + - + ---- + ----- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + - + ---- + ---- + ----- + ---- + ---- + ---- + ---- + EM> / P>

float Float16ToFloat( short fltInt16 )
{
    int fltInt32    =  ((fltInt16 & 0x8000) << 16);
    fltInt32        |= ((fltInt16 & 0x7fff) << 13) + 0x38000000;

    float fRet;
    memcpy( &fRet, &fltInt32, sizeof( float ) );
    return fRet;
 }

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/


14 commentaires

J'ai déjà une conversion float32-flottante16, avec courtoisie de Jherico. Le problème consiste à obtenir celui que OpenGL peut lire.


@ Haydnv.harach: Pourquoi OpenGL ne serait-il pas capable de le lire? OpenGL s'attend à ce que les données soient dans le bon modèle de bits et être de 16 bits par entrée. Ces données pourraient être stockées en short ou emballées dans des flotteurs pour toutes les cordes OpenGL ...


@ Haydnv.harach: J'ai ajouté ma mise en œuvre de la classe du flotteur16. Je l'utilise sous DirectX pendant un moment et je n'ai pas remarqué aucun problème.


Je l'ai testé, mais quand je convertit un numéro à moitié puis de retour à un flotteur, je reçois 0.0f.


@ Haydnv.harach: point équitable, j'ai repoussé quelque chose là-haut, tenez-vous malade de votre apparence ...


@ Haydnv.harach: OK après plus d'autres creuser, il semble que le code que j'ai sur Mac soit sur la date. Essayez ce qui précède.


Bien que sa mine signalant la mine ne fait pas de protection de trop-plein, etc. C'est très rapide à condition que vous puissiez être sûr que les données d'entrée sont valides.


Je peux convertir un flotteur à moitié et retour à un flotteur en toute sécurité, mais il mangue mes sommets comme les autres implémentations.


@ Haydnv.harach: L'objet est-il certainement assez petit pour être représenté par des moitiés?


Oui, c'est un cube composé entièrement d'arêtes, chaque position de sommet est (+ -1.0f, + -1.0f, + -1.0f).


@ Haydnv.harach: Puis-je vous suggérer de poster votre modèle de génération et de votre code de rendu?


@ Haydnv.harach: Vérifiez mon édition, je suis à peu près sûr que j'ai repéré votre erreur.


Je serai damné, vous aviez absolument raison. Merci beaucoup! PS, j'aime la simplicité de votre mise en œuvre, mais quelles sont les préoccupations que je devrais avoir sur "Données d'entrée valides"? Assurez-vous simplement que ce n'est pas NAN / INF?


@ Haydnv.harach: Fondamentalement, vous devez être prudent que vos flotteurs ne sont pas trop grands ou trop petits (maximum / minimum est +/- 65504, je crois). Au-dessus de ces valeurs, vous obtiendrez des résultats totalement invalides car les choses vont commencer à "envelopper". En dessous de la représentation minimale, vous continuerez à obtenir des zéros plutôt que de tout ce qui est utile. Une mise en œuvre meilleure, bien que plus lente, la protection contreflow (rond à l'infini, par exemple).