GLES编码/解码32位浮动到2x16bits

时间:2017-03-21 10:06:33

标签: opengl-es glsl webgl glsles

我试图优化纹理内存,所有阻止我将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兼容)

1 个答案:

答案 0 :(得分:1)

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

例如,如果您需要某个数字N,大于65503,则可以编码'将N除以2,然后解码'乘以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浮点数,则这些都不会起作用。