Author Topic: asfloat / asint en GLSL ?  (Read 14739 times)

0 Members and 1 Guest are viewing this topic.

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
asfloat / asint en GLSL ?
« on: 03 August 2011 à 18:39:59 »
Yo !

Est-ce que quelqu'un aurait une idée pour avoir un équivalent de "asfloat()" et "asint()" en GLSL ?
En gros, sur le projet sur lequel je bosse j'ai pas de MRT et j'ai absolument besoin d'écrire 2 couleurs RGB (6 composantes en tout).
Du coup je me suis dit que ça serait intéressant d'écrire 4 composantes dans la render target et les 2 restantes dans le ZBuffer, en utilisant le ZBuffer comme seconde target.
Mais bon pour ça il faudrait que je hack le Z !

En HLSL (Model 4) on peut faire :
uint Bisou = (uint( floor( 65535.0 * a )) << 16) | uint( floor( 65535.0 * b ));
Z = asfloat( Bisou );
Et on écrit ça dans le ZBuffer...

J'ai pas essayé, mais bon, ça doit marcher.

Est-ce que quelqu'un aurait une idée pour faire la même chose en GLSL ??
Et l'équivalent "asuint" bien sûr...

Biz+
.  Pom  .

Offline ponce

  • Base
    • Pouet.net
    • Coup de coeur
    • View Profile
  • Ancienneté: 2009
Re : asfloat / asint en GLSL ?
« Reply #1 on: 03 August 2011 à 19:24:44 »
Je vois pas trop... J'ai pas trouvé de doc sur comment le Z-buffer est non-linéaire dans sa version normale, ni sur un truc comme reinterpret_cast en GLSL.

http://www.opengl.org/registry/specs/EXT/packed_depth_stencil.txt
Quelques formats ont l'air sympa comme GL_UNSIGNED_INT_24_8_EXT. (mince, ça à pas l'air prévu comme internal format)

« Last Edit: 03 August 2011 à 19:37:12 by ponce »

Offline ponce

  • Base
    • Pouet.net
    • Coup de coeur
    • View Profile
  • Ancienneté: 2009
Re : asfloat / asint en GLSL ?
« Reply #2 on: 03 August 2011 à 20:05:46 »
Idée à la con pour stocker les deux valeurs avec la même précision : tu mappes 2 valeurs sur une avec une fonction f(t) = (sin(A * 2 * pi * t), sin((A - 1) * 2 * pi * t)

Exemple: ici (ça quadrille l'espace quoi)

A la lecture, tu as retrouve la phase (t) dans le depth buffer puis F(t) te donne ton couple de valeurs.

Le jeu consiste à inverser la fonction au moment de l'écriture.

F(t) = (x,y) = (sin(A * 2 * pi * t), sin((A - 1) * 2 * pi * t)
(arcsin(x), arcsin(y)) = (A * 2 * pi * t + N * 2 * pi, (A - 1) * 2 * pi * t + M * 2 * pi)

et là en soustrayant une équation de l'autre, A disparait
(arcsin(x) - arcsin(y)) = 2 * pi * t + K * 2 * pi
(arcsin(x) - arcsin(y))/(2*pi) + K = t

et là tu choisis K pour que t soit entre 0 et 1 (avec fract ?).


Reste à trouver la meilleur manière de mapper ce t sur le depth buffer.



Offline MsK`

  • Base
    • Pouet.net
    • View Profile
  • Rôle: Code
  • Ville: Paris/RP
Re : asfloat / asint en GLSL ?
« Reply #3 on: 03 August 2011 à 21:04:39 »
Le z-buffer linéaire ou non, ça dépend pas uniquement de la matrice de projection ? Si je comprend bien, ici, y'en a pas.

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : asfloat / asint en GLSL ?
« Reply #4 on: 04 August 2011 à 13:27:16 »
Sympa ton idée Ponce, j'essayais de voir en utilisant la norme d'un truc justement.
Sinon y a + simple, j'ai oublié de préciser que ma 2nde couleur est entre [0,1] : du coup on peut écrire un truc du genre Z = 1000.0 * y + x  puis reséparer les composants à la lecture...

'fin bref. merci de vos efforts mais de toute manière oubliez tout ça car le soft que j'utilise permet pas d'écrire dans le Z donc chuis baisé de toute manière. ;D

Le z-buffer linéaire ou non, ça dépend pas uniquement de la matrice de projection ? Si je comprend bien, ici, y'en a pas.
Bah heuu... Oui le ZBuffer pour moi ça a toujours été un truc où t'écris un float, que ça soit Z, 1/Z, Z/W ou n'importe quoi après c'est à toi de te démerder. C'est effectivement la matrice de projection qui détermine ce que tu vas écrire du coup t'as le contrôle sur ce que tu veux y mettre. Et effectivement dans ce cas-là j'ai une passe fullscreen où le Ztest est disabled mais pas le Zwrite, donc le ZBuff il prend ce qu'on lui dit de prendre et il ferme sa gu... oups je m'emporte ! ;D
.  Pom  .

Offline krabob

  • Base
    • Pouet.net
    • View Profile
    • www.m4nkind.com
  • Ancienneté: 1994
  • Groupe: Mankind
  • Rôle: code amiga / linux / OpenGL
  • Ville: Toulouse
Re : asfloat / asint en GLSL ?
« Reply #5 on: 04 August 2011 à 14:29:14 »
Je sais pas si ma réponse sera utile  (ça me parait une idée évidente et proche de ce qui a déjà été écrit, pas besoin d'être balaise), mais bon , hop:

 Pour stocker 2 valeurs A et B flottantes sans passer par des conversion en ints, sachant qu'on a besoin de n precision aprés la virgule pour A, et connaisant le "Max" du domaine de variation de B (edit: et B toujours positif): , en GLSL

 encriptage:
 Valeur = floor(A*precisionMultiplier) + (B/maxB);

 décriptage:
 A = floor(Valeur)/precisionMultiplier
 B = fract(Valeur)*maxB

... évidemment on perd potentiellement de la précision d'information sur A et B, mais toujours proportionnellement aux nombres de bit qui la contienne (quelque soit la techno)
(edit: si A est negatif, floor() va peut etre faire la gueule: classique)
Votez comme ça Mélenchon ... ou Clément Wittman, ... ou Eva ! Oo

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : asfloat / asint en GLSL ?
« Reply #6 on: 04 August 2011 à 15:02:11 »
Ah bah t'es revenu toi du coup ? ;D
.  Pom  .

Offline xoofx

  • Base
    • Pouet.net
    • View Profile
    • xoofx
  • Ancienneté: 1989
  • Groupe: FRequency
  • Rôle: code (+musique), web
  • Ville: Grenoble

Offline ponce

  • Base
    • Pouet.net
    • Coup de coeur
    • View Profile
  • Ancienneté: 2009
Re : asfloat / asint en GLSL ?
« Reply #8 on: 05 August 2011 à 01:13:40 »
Peut-être aussi que peux faire rentrer tes 6 composantes dans 4.
En passant en espace YUV tu peux te permettre de subsampler x2 ta chrominance. On s'en sert dans la video pour faire rentrer une couleur 24 bits en 12 bits sans trop de perte.

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : asfloat / asint en GLSL ?
« Reply #9 on: 05 August 2011 à 02:15:26 »
Peut-être aussi que peux faire rentrer tes 6 composantes dans 4.
En passant en espace YUV tu peux te permettre de subsampler x2 ta chrominance. On s'en sert dans la video pour faire rentrer une couleur 24 bits en 12 bits sans trop de perte.
J'y avais pensé, un peu comme le format RGBE où t'encodes un exposant pour 3 composantes, sauf que là les valeurs sont de magnitude vraiment différentes.
Comme je l'ai dit, il y en a une qui est [0,1] et l'autre [0,+oo[ et aucune des 2 n'est négligeable devant l'autre...
.  Pom  .

Offline xoofx

  • Base
    • Pouet.net
    • View Profile
    • xoofx
  • Ancienneté: 1989
  • Groupe: FRequency
  • Rôle: code (+musique), web
  • Ville: Grenoble
Re : asfloat / asint en GLSL ?
« Reply #10 on: 05 August 2011 à 02:24:16 »
A priori, le floatBitsToInt est dispo depuis la version 3.3 de GLSL http://www.opengl.org/sdk/docs/manglsl/xhtml/floatBitsToInt.xml
donc si tu colles un #version 330 ou 400 ou 410 au debut de ton fichier glsl ça devrait compiler... t'as testé?

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : asfloat / asint en GLSL ?
« Reply #11 on: 05 August 2011 à 11:34:11 »
A priori, le floatBitsToInt est dispo depuis la version 3.3 de GLSL http://www.opengl.org/sdk/docs/manglsl/xhtml/floatBitsToInt.xml
donc si tu colles un #version 330 ou 400 ou 410 au debut de ton fichier glsl ça devrait compiler... t'as testé?
Ouais alors très bien, merci, le truc c'est que j'essaie d'être compatible avec le maximum de machines... Moi tout ce que je sais c'est que je fais du Shader Model 3.0 (qui est déjà assez restrictif en soi) alors les extensions OpenGL j'ai vraiment aucune idée de ce qui est supporté ou pas, de ce qu'on a par défaut, etc.
C'est juste un gros bordel infâme OpenGL quand on y pense (comme tous les trucs Linux j'ai l'impression), et je veux absolument pas utiliser d'extensions obscures...

(et évidemment, intBitsToFloat() ne fonctionne pas par défaut dans ce soft)
« Last Edit: 05 August 2011 à 11:37:40 by Patapom »
.  Pom  .

Offline flure

  • Base
    • Pouet.net
    • View Profile
  • Ancienneté: 1998
  • Groupe: PoPsY TeAm
  • Rôle: Codeur Linux
  • Ville: Lyon
Re : asfloat / asint en GLSL ?
« Reply #12 on: 05 August 2011 à 11:38:52 »
C'est vrai que OpenGL avec le système d'extensions est un peu pénible, et pour les shaders ça complique encore plus. Tu rajoutes WebGL et là tu t'aperçois que ton shader qui marche très bien en "offline" ne marche pas en WebGL. Pourtant c'est la même carte vidéo !
Bref moi ça ne me touche pas trop parce que je ne fais rien de bien avancé avec, mais si j'étais une boîte de JV sous Windows, évidemment le choix serait vite fait (et pour encore plein d'autres raisons).
Par contre le grooos avantage de GL sur DX, c'est la portabilité. Mais peu de gens s'y intéressent malheureusement.

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : asfloat / asint en GLSL ?
« Reply #13 on: 08 August 2011 à 16:28:44 »
Yault !

Alors j'ai quand même un p'tit peu persisté avec cette histoire de packing de 2 couleurs dans 4 composantes.
Ce que j'avais oublié de dire c'est que je rendais dans une texture RGBA16F (hé ouais !) donc on a 8 octets par couleur en tout. Désolé, ça aurait pu vous faire avoir plein d'idées mais j'ai zappé.

Bon, bref du coup je me suis dit, c'est quand même con ! On a plein de bytes à disposition.
Alors j'ai décidé de faire le packing suivant :
Code: [Select]
RGB0 => YUV0
RGB1 => YUV1

Result.Red = YUV0.x    // Luminance 0 full resolution
Result.Green = Pack( YUV0.yz )  // UV0 packés sur 1 float16
Result.Blue = YUV1.x    // Luminance 1 full resolution
Result.Alpha = Pack( YUV1.yz )  // UV1 packés sur 1 float16

Il faut savoir que les float16 sont codés comme suit :
Code: [Select]
Sign | Exponent | Mantissa
  1  |     5    |    10

Idéalement, si on avait des opérations bitwise en GLSL sans utiliser d'extensions Feng-Shui, il suffirait d'écrire ce code pour décoder un float16 vers un float 32 bits :
Code: [Select]
UInt16 Value = *((UInt16*) &_fValue);
float fSign = (Value & 0x8000) != 0 ? -1.0 : 1.0;
int Exponent = (Value & 0x7C00) >> 10;
int Mantissa = Value & 0x3FF;
return fSign * exp2( Exponent - 15 ) * (1.0 + Mantissa / 1024.0);

Bon. Mais rien n'empêche d'émuler ces opérations bitwise en flottant !
L'idée est donc d'encoder U et V comme ça :
Code: [Select]
S|EEEEE|MMMMMMMMMM
U|UUUUU|UUVVVVVVVV
7|65432|1076543210

Voici donc mon code d'encodage :
Code: [Select]
half2 YUV2Half( float3 _YUV )
{
float U = floor( _YUV.y * 255.0 );
float V = floor( _YUV.z * 255.0 );

half Sign = step( 128.0, U );
U -= Sign * 128.0; // Remove bit 7 (sign)
Sign = 1.0 - 2.0 * Sign;
half Exponent = floor( 0.25 * U ); // Remove 2 LS bits
U -= 4.0 * Exponent; // Remove bits 2-6 (we're left with the 2 LS bits)
half Mantissa = 1.0 + (256.0 * U + V) * INV1024;
half PackedUV = Sign * exp2( Exponent - 15.0 ) * Mantissa;

return half2( _YUV.x, PackedUV );
}

Et le code de décodage :
Code: [Select]
float3 Half2YUV( half2 _PackedYUV )
{
float UV = _PackedYUV.y;
half Sign = step( UV, 0.0 );
UV = abs( UV ); // Remove sign
half Exponent = floor( log2( UV ) );
UV *= exp2( -Exponent ); // We should have a value in [1,2[
float Mantissa = 1024.0 * (UV - 1.0);

float U = (128.0 * Sign + (Exponent + 15.0) * 4.0 + floor( Mantissa * INV256 )) * INV256;
float V = frac( Mantissa * INV256 );

return float3( _PackedYUV.x, U, V );
}

A noter que UV ne sont pas comme d'habitude en [-0.5,+0.5] mais [0,1]. J'utilise ce code pour la conversion RGB (ça vient de là http://www.fourcc.org/fccyvrgb.php) :
Code: [Select]
float3 RGB2YUV( float3 _RGB )
{
float3 YUV;
YUV.x = 0.299 * _RGB.r + 0.587 * _RGB.g + 0.114 * _RGB.b;
YUV.y = saturate( 0.5 + 0.565 * (_RGB.b-YUV.x) );
YUV.z = saturate( 0.5 + 0.713 * (_RGB.r-YUV.x) );
return YUV;
}

float3 YUV2RGB( float3 _YUV )
{
_YUV.yz -= 0.5;
float3 RGB;
RGB.r = _YUV.x + 1.403 * _YUV.z;
RGB.g = _YUV.x - 0.344 * _YUV.y - 0.714 * _YUV.z;
RGB.b = _YUV.x + 1.770 * _YUV.y;
return RGB;
}

Evidemment, l'inconvénient de cette méthode est qu'on ne peut pas sampler le buffer packé autrement qu'en NEAREST. Mais bon ça permet d'utiliser 1 seul buffer au lieu de 2 !
Imaginez l'intérêt quand vous avez besoin, comme moi, de calculer Scattering + Exinction : si votre shader de calcul fait un ray-marching sur 64 steps, vous avez pas forcément envie de faire 2 passes ! ;D
« Last Edit: 08 August 2011 à 17:25:59 by Patapom »
.  Pom  .

Offline ponce

  • Base
    • Pouet.net
    • Coup de coeur
    • View Profile
  • Ancienneté: 2009
Re : asfloat / asint en GLSL ?
« Reply #14 on: 08 August 2011 à 19:14:53 »
Sympa ce follow-up pour voir comment tu t'en es tiré !

Par contre heu la conversion en YUV me parait douteuse si ta luminance sort de la range. A mon avis il faudrait la scaler vers le bas pour que la conversion/déconversion de la chroma se passe bien.