GLES Encode/Decode 32 bits float to 2 16 bits

GLES Encode/Decode 32bits float to 2x16bits

我正在尝试优化纹理内存,所有阻止我将 GL_RGBA32F LUT 转换为 GL_RGBA16F 的因素是(可能)超过限制的一个索引。无论如何,我可以在 C 中获取一个浮点数并将其拆分为 2 个值,然后在 GLSL 中从存储在 LUT 中的 2 个值重建该浮点数吗?

我的意思是这样的:

[C]

float v0,v1, *pixel_array;

magic_function_in_c( my_big_value, &v0, &v1 );

pixel_array[ index++ ] = pos.x; // R
pixel_array[ index++ ] = pos.y; // G
pixel_array[ index++ ] = v0;    // B
pixel_array[ index++ ] = v1;    // A

[GLSL]

vec4 lookup = texture2D( sampler0, texcoord );

float v = magic_function_in_glsl( lookup.b, lookup.a );

ps:我正在使用 GLES 2.0(也与 WebGL 兼容)

如果您只需要比 float16 提供的范围更大,并且只在一个方向(更大或更小),您可以乘以一个固定的比例因子。

例如,如果您需要某个数字 N,大于 65503,您可以 'encode' 将 N 除以 2,'decode' 乘以 2。这会向上移动有效范围,牺牲 1/N 的范围,但扩大 +/-N 的范围最大值。如果您需要 1/N 比 +/-N 更大的范围,您可以交换乘法和除法。如果您需要它根据数据进行更改,您可以使用第二个值来存储比例因子。

您还可以尝试使用 exp2 和 log2,例如:

void
magic_function_in_c(float fVal, uint16_t* hExponent, uint16_t* hMult)
{
    float fExponent = log2f(f);
    *hExponent = f32_to_f16(fExponent);

    // Compensate for f32->f16 precision loss
    float fActualExponent = f16_to_f32(*hExponent);
    float fValFromExponent = exp2f(fActualExponent);

    float fMult;
    if (fValFromExponent != 0.0f) {
        fMult = fVal / fValFromExponent;
    } else if (fVal < 0.0f) {
        fMult = -1.0f;
    } else {
        fMult = 1.0f
    }
    *hMult = f32_to_f16(fMult);
}

highp float
magic_function_in_glsl(highp float hExponent, highp float hMult)
{
    return exp2(hExponent) * hMult;
}

请注意,如果您的 GLSL 着色器中没有 highp 浮点数,其中的 none 将起作用。