繁体   English   中英

为32位纹理(R11F_G11F_B10F)的每个像素存储3个带符号的浮点数(从-4到4)。

[英]Store 3 signed floats (from -4 to 4) for each pixel of a 32 bit texture (R11F_G11F_B10F)

编码方式

作为当前正在使用的图形应用程序的一部分,我需要为32位纹理的每个像素存储三个带符号的浮点数。 目前,为了达到这个目标,我正在使用以下C ++函数:

void encode_full(float* rgba, unsigned char* c) {
    int range = 8;
    for (int i = 0; i < 3; i++) {
        rgba[i] += range / 2;
        rgba[i] /= range;
        rgba[i] *= 255.0f;         
        c[i] = floor(rgba[i]);
    }
    c[3] = 255;
}

尽管此编码功能带来了相当大的精度损失,但由于考虑值的范围限于间隔(-4,4),因此使情况变得更好。

尽管如此,即使函数产生了不错的结果,我认为我可以通过利用alpha通道(当前未使用)来获得更高的精度,从而做得更好。 特别是我在考虑对第一个浮点使用11位,对第二个浮点使用11位,对于最后一个浮点使用10位,即10-10-10-2(未使用)。 OpenGL具有类似的格式,称为R11F_G11F_B10F。

但是,在为这种特定格式提供编码功能时遇到了一些困难。 有谁知道如何用C ++编写这样的函数?

解码

在解码方面,这是我在着色器中使用的功能。

float3 decode(float4 color) { 
    int range = 8;
    return color.xyz * range - range / 2; 
}

请注意,着色器是用Cg编写的,并在Unity引擎中使用。 此外,请注意,Unity的Cg着色器实现仅处理Cg语言的一个子集(例如,不支持打包/解包功能)。

如果可能的话,连同编码功能一起,将对解码功能的帮助有所帮助。 谢谢!

编辑

我已经提到过R11F_G11F_B10F仅作为参考帧,用于在色彩通道之间分配位。 我不希望使用浮点表示法,因为这实际上暗示了给定范围的精度损失,正如某些答案所指出的那样。

“ 10位”转换为0到1023之间的整数,因此从[-4.0,+ 4.0]的映射平凡是floor((x+4.0) * (1023.0/8.0)) 对于11位,用2047代替。

解码是另一种方式(y*8.0/1023.0) - 4.0

我认为使用GL_R11F_G11F_B10F对您的情况没有帮助。 就像格式名称所暗示的那样,此处的组件是11位和10位浮点数 ,这意味着它们以尾数和指数形式存储。 更具体地说,从规范:

无符号的11位浮点数没有符号位,5位指数(E)和6位尾数(M)。

无符号的10位浮点数没有符号位,5位指数(E)和5位尾数(M)。

在这两种情况下,与浮点格式一样,尾数有一个隐含的前导1位。 因此,尾数在11位情况下具有7位精度,在10位情况下具有6位精度。

这低于您当前使用的8位精度。 现在,重要的是要了解浮点大小写的精度相对于数字大小是不均匀的。 因此,非常小的数字实际上比8位定点数字具有更高的精度,而范围顶部的数字则具有较差的精度。 如果您使用[-4.0,4.0]范围的自然映射到正浮点数,例如在转换为11/10位带符号浮点数之前简单地添加4.0,对于接近-4.0的值,您将获得更好的精度,但是值接近4.0时精度较差。

浮点格式的主要优点实际上是它们可以存储更大范围的值,同时仍保持良好的相对精度。

只要您希望内存使用保持在4字节/像素,那么更好的选择是GL_RGB10类的格式,每个组件的实际精度为10位。 这与GL_RGB10_A2 (及其未签名的同级GL_RGB10_A2UI )非常相似,不同之处在于它不会公开您不使用的alpha组件。

如果您愿意将内存使用量增加到超过4字节/像素,则可以有很多选择。 例如, GL_RGBA16将为您提供每个组件16位的定点精度。 GL_RGB16F为您提供16位浮点数(相对精度为11位)。 或者,您可以使用GL_RGB32F ,它为每个组件提供32位浮点数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM