[英]How to call conditionally B::f only if derived from B in C++11?
[英]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.