Author Topic: asfloat / asint en GLSL ?  (Read 16204 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
Re : asfloat / asint en GLSL ?
« Reply #15 on: 09 August 2011 à 04:56:08 »
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.

Bah écoute, j'ai pris le code sur fourcc et j'ai un rendu HDR où la luminance varie énormément (genre de 0.01 à 40) et ça fonctionne très bien... Je sais pas trop ce que tu veux dire en fait, la chroma est indépendante de la luma non ? 'fin dans ce code-là, on voit qu'on utilise Red et Blue relativement à la luma, mais Red et Blue ont a priori la même magnitude que  la luma donc j'imagine qu'on retombe sur nos pieds ?
Je t'avouerais que je me suis pas posé la question sur le code de conversion RGB <=> YUV, j'ai appliqué tel quel et ça a fonctionné... 8)
.  Pom  .

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : Re : asfloat / asint en GLSL ?
« Reply #16 on: 09 August 2011 à 14:57:22 »
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.
Han t'as raison en fait ! J'ai fait des tests et les UV sortent du range [0,1] si la luminance dépasse 1 et ça occasionne pas mal de pertes ! >:(

Du coup, mon code de conversion RGB <=> YUV devient ceci :
Code: [Select]
float3 RGB2YUV( float3 _RGB )
{
float3 YUV;
YUV.x = 0.257 * _RGB.r + 0.504 * _RGB.g + 0.098 * _RGB.b;
_RGB /= max( 1.0, YUV.x );   // On renormalise la luminance
YUV.y = saturate( 0.5 - 0.7 * (0.148 * _RGB.r - 0.291 * _RGB.g + 0.439 * _RGB.b) );  // * 0.7 pour compresser encore + les UV qui dépasseraient
YUV.z = saturate( 0.5 + 0.7 * (0.439 * _RGB.r - 0.368 * _RGB.g - 0.071 * _RGB.b) );
return YUV;
}

float3 YUV2RGB( float3 _YUV )
{
_YUV.yz = (_YUV.yz - 0.5) * max( 1.0, _YUV.x ) / 0.7;  // On dénormalise et on divise par 0.7 pour rescaler les UV correctement

float3 RGB;
RGB.r = 1.164 * _YUV.x + 1.596 * _YUV.z;
RGB.g = 1.164 * _YUV.x - 0.391 * _YUV.y - 0.813 * _YUV.z;
RGB.b = 1.164 * _YUV.x + 2.018 * _YUV.y;
return RGB;
}

Ca marche à peu près bien... J'ai une erreur relative en moyenne de 4% max sur un tirage aléatoire de 10000 couleurs dont RGB varie dans [0,10].
Je vais quand même essayer un autre color space pour voir si on s'en sort pas mieux parce que des fois j'ai des trucs qui sortent de la moyenne (genre un vert 2 fois plus élevé qu'en entrée !)
« Last Edit: 09 August 2011 à 15:29:36 by Patapom »
.  Pom  .

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : asfloat / asint en GLSL ?
« Reply #17 on: 09 August 2011 à 16:22:06 »
Chuis trop con ! J'utilisais déjà une conversion RGB <=> xyY pour mon tone mapping, du coup ça se prête parfaitement à l'opération de packing puisque xy sont dans [0,1] !

Sur 1,000,000 de couleurs tirées au hasard, avec un cycle RGB => xyY => Pack => UnPack => xyY => RGB j'obtiens une erreur relative moyenne de 5.3% ce qui est vraiment pas mal.

On notera aussi que les intervalles min/max de la chroma xy ne couvrent pas entièrement [0,1] (cf. le fer à cheval http://en.wikipedia.org/wiki/CIE_1931_color_space#The_CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space). Sur 1,000,000 de couleurs au pif, j'ai mesuré :
 x min/max = 0.150 / 0.65    => couvre 0.5 seulement
 y min / max = 0.06 / 0.599  => couvre 0.54 seulement

Du coup, en multipliant les xy par 2 et en soustrayant (0.3 , 0.12) on couvre tout le range nécessaire, on a plus de précision et l'erreur relative moyenne tombe à 3.5%, ce qui est encore mieux ! ;D

Et le code de conversion devient donc (désolé, en C#) :
Code: [Select]

// RGB -> XYZ conversion
// http://www.w3.org/Graphics/Color/sRGB
//
Vector3 RGB2xyY( Vector3 _RGB )
{

// The official sRGB to XYZ conversion matrix is (following ITU-R BT.709)
Vector3[] RGB2XYZ = new Vector3[] {
new Vector3( 0.5141364f, 0.3238786f, 0.16036376f ),
new Vector3( 0.265068f, 0.67023428f, 0.06409157f ),
new Vector3( 0.0241188f, 0.1228178f, 0.84442666f ) };

Vector3 XYZ = new Vector3(
Vector3.Dot( RGB2XYZ[0], _RGB ),
Vector3.Dot( RGB2XYZ[1], _RGB ),
Vector3.Dot( RGB2XYZ[2], _RGB ) );

// XYZ -> Yxy conversion
Vector3 xyY;
xyY.Z = XYZ.Y;
 
// x = X / (X + Y + Z)
// y = X / (X + Y + Z)
float InvSum = 2.0f / Math.Max( 1e-3f, XYZ.X + XYZ.Y + XYZ.Z );
xyY.X = Clamp01( XYZ.X * InvSum - 0.3f );
xyY.Y = Clamp01( XYZ.Y * InvSum - 0.12f );

return xyY;
}

// XYZ -> RGB conversion
//
Vector3 xyY2RGB( Vector3 _xyY )
{
// The official XYZ to sRGB conversion matrix is (following ITU-R BT.709)
Vector3[] XYZ2RGB = new Vector3[] {
new Vector3( 2.5651f, -1.1665f, -0.3986f ),
new Vector3( -1.0217f, 1.9777f, 0.0439f ),
new Vector3( 0.0753f, -0.2543f, 1.1892f ) };

_xyY.X = 0.5f * (0.3f + _xyY.X);
_xyY.Y = 0.5f * (0.12f + _xyY.Y);

// xyY -> XYZ conversion
float InvY = 1.0f / Math.Max( 1e-3f, _xyY.Y );
Vector3 XYZ;
XYZ.Y = _xyY.Z;
XYZ.X = _xyY.X * _xyY.Z * InvY; // X = x * Y / y
XYZ.Z = (1.0f - _xyY.X - _xyY.Y) * _xyY.Z * InvY; // Z = (1-x-y) * Y / y

// RGB conversion
return new Vector3(
Math.Max( 0.0f, Vector3.Dot( XYZ2RGB[0], XYZ ) ),
Math.Max( 0.0f, Vector3.Dot( XYZ2RGB[1], XYZ ) ),
Math.Max( 0.0f, Vector3.Dot( XYZ2RGB[2], XYZ ) ) );
}

Ensuite, à la place de YUV, on pack donc xyY (chroma/luma) avec la méthode indiquée précédemment et on jouit.
.  Pom  .

Offline MsK`

  • Base
    • Pouet.net
    • View Profile
  • Rôle: Code
  • Ville: Paris/RP
Re : asfloat / asint en GLSL ?
« Reply #18 on: 10 August 2011 à 11:34:26 »
Quote
packing multiple 8 and 16 bit values into a single 32-bit value for efficient shader processing with significantly reduced  memory storage and bandwidth, especially useful when transferring data between shader stages.
http://www.khronos.org/news/press/khronos-enriches-cross-platform-3d-graphics-with-release-of-opengl-4.2-spec

Patapom demande, Patapom obtiens !

;D

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : asfloat / asint en GLSL ?
« Reply #19 on: 10 August 2011 à 12:12:03 »
J'ai une très forte influence sur le Khronos group en effet : c'est ma maman qui leur fait la cuisine. ;D
.  Pom  .