Jak spakować jeden 32-bitowy int do 4, 8-bitowych intów w glsl / webgl?

Szukam paraleli do jakiejś skomplikowanej matematyki, a webgl wygląda na idealny sposób, aby to zrobić. Problem w tym, że z tekstur można odczytać tylko 8-bitowe liczby całkowite. Chciałbym, aby numery 32 bitowe z tekstury. Miałem pomysł, aby użyć kanałów kolorów 4, Aby uzyskać 32 bity na piksel, zamiast 4 razy 8 bitów.

Mój problem polega na tym, że glsl nie ma operatora " % " ani żadnego operatora bitowego!

TLDR: Jak przekonwertować 32-bitową liczbę na 4 8-bitowe liczby za pomocą operatorów w glsl.

Kilka dodatkowych informacji na temat techniki (przy użyciu operatorów bitowych):

Jak przechowywać 64-bitową liczbę całkowitą w dwóch 32-bitowych liczbach całkowitych i konwertować z powrotem

Author: Community, 2013-08-27

2 answers

Można bitshift mnożąc / dzieląc przez potęgi dwóch.

Jak zaznaczono w komentarzach podejście, które pierwotnie opublikowałem, działało, ale niepoprawne, Oto jeden autorstwa Arasa Pranckevičiusa , zauważ, że kod źródłowy w samym poście zawiera literówkę i jest to HLSL, jest to port GLSL z literówką poprawioną:

const vec4 bitEnc = vec4(1.,255.,65025.,16581375.);
const vec4 bitDec = 1./bitEnc;
vec4 EncodeFloatRGBA (float v) {
    vec4 enc = bitEnc * v;
    enc = fract(enc);
    enc -= enc.yzww * vec2(1./255., 0.).xxxy;
    return enc;
}
float DecodeFloatRGBA (vec4 v) {
    return dot(v, bitDec);
}
 20
Author: LJᛃ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-12 23:11:21

Ogólnie rzecz biorąc, jeśli chcesz spakować znaczące cyfry liczby zmiennoprzecinkowej w bajtach, musisz kolejno wyodrębnić 8-bitowe Pakiety cyfr znaczących i zapisać je w bajcie.

Kodowanie liczby zmiennoprzecinkowej w predefiniowanym zakresie

Aby spakować wartość zmiennoprzecinkową do 4 * 8-bitowych buforów, należy najpierw określić zakres wartości źródłowych.
jeśli zdefiniowano zakres wartości[minVal, maxVal], musi być zmapowany do zakresu [0.0, 1.0]:

float mapVal = clamp((value-minVal)/(maxVal-minVal), 0.0, 1.0);

Funkcja Encode pakuje wartość zmiennoprzecinkową z zakresu [0.0, 1.0] do vec4:

vec4 Encode( in float value )
{
    value *= (256.0*256.0*256.0 - 1.0) / (256.0*256.0*256.0);
    vec4 encode = fract( value * vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0) );
    return vec4( encode.xyz - encode.yzw / 256.0, encode.w ) + 1.0/512.0;
}

Funkcja Decode wyodrębnia wartość zmiennoprzecinkową z zakresu [0.0, 1.0] z vec4:

float Decode( in vec4 pack )
{
    float value = dot( pack, 1.0 / vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0) );
    return value * (256.0*256.0*256.0) / (256.0*256.0*256.0 - 1.0);
}

Następujące funkcje pakują i wyciągają wartość zmiennoprzecinkową z zakresu [minVal, maxVal]:

vec4 EncodeRange( in float value, flaot minVal, maxVal )
{
    value = clamp( (value-minVal) / (maxVal-minVal), 0.0, 1.0 );
    value *= (256.0*256.0*256.0 - 1.0) / (256.0*256.0*256.0);
    vec4 encode = fract( value * vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0) );
    return vec4( encode.xyz - encode.yzw / 256.0, encode.w ) + 1.0/512.0;
}

float DecodeRange( in vec4 pack, flaot minVal, maxVal )
{
    value = dot( pack, 1.0 / vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0) );
    value *= (256.0*256.0*256.0) / (256.0*256.0*256.0 - 1.0);
    return mix( minVal, maxVal, value );
}

Kodowanie liczby zmiennoprzecinkowej z wykładnikiem

Inną możliwością jest zakodowanie cyfr znaczących do 3 * 8-bitowe wartości RGB i wykładnik do 8-bitów kanału alfa:

vec4 EncodeExp( in float value )
{
    int exponent  = int( log2( abs( value ) ) + 1.0 );
    value        /= exp2( float( exponent ) );
    value         = (value + 1.0) * (256.0*256.0*256.0 - 1.0) / (2.0*256.0*256.0*256.0);
    vec4 encode   = fract( value * vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0) );
    return vec4( encode.xyz - encode.yzw / 256.0 + 1.0/512.0, (float(exponent) + 127.5) / 256.0 );
}

float DecodeExp( in vec4 pack )
{
    int exponent = int( pack.w * 256.0 - 127.0 );
    float value  = dot( pack.xyz, 1.0 / vec3(1.0, 256.0, 256.0*256.0) );
    value        = value * (2.0*256.0*256.0*256.0) / (256.0*256.0*256.0 - 1.0) - 1.0;
    return value * exp2( float(exponent) );
}

Uwaga, Ponieważ standardowa liczba 32-bitowa IEEE 754 ma tylko 24 znaczące cyfry, całkowicie wystarcza do zakodowania liczby w 3 bajtach.

Zobacz także odpowiedzi na następujące pytania:

 1
Author: Rabbid76,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-19 09:51:59