纹理值被削减到0-1的范围?

时间:2014-08-14 10:27:14

标签: c++ opengl textures

简单的问题:

默认情况下,OpenGL是否将纹理值剪辑到0-1范围?如果有,有办法禁用它吗?

详细问题:

我有一个纹理,在创建时,我将一些默认值放入。

我创建RGBA值大小为16x16的纹理,如下所示:

//Generate the texture and get its ID
GLuint texID;
glGenTextures(1, &texID);

//Bind the texture
glBindTexture(GL_TEXTURE_2D, texID);

//Define the size of the texture
int width = 16;
int height = 16;
int numberOfElementsPerTexel = 4;
int size = width * height * numberOfElementsPerTexel;

//Create an empty array of texel data
float data[size];
std::fill_n(data, size, 0.0f);

//Add the empty data to the texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, GL_RGBA, GL_FLOAT, data);

在我创建并填充纹理后测试它是否正常工作我检查内容如下:

//Bind the texture
glBindTexture(GL_TEXTURE_2D, texID);

//Get the data from the texture
float texData[size];
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, texData);
{
    for(int i = 0; i < size; i++)
    {
        printf("Value at %d: %f\n", i, texData[i]);
    }
}

所以这给出了0的加载,正如我所期望的那样,然后在我调用glTexImage2D之前的另一个测试我修改了数据数组中的一个值:

data[0] = 1.0f;

正如预期的那样,这将在要打印的第一个数字中增加1.0。 0到1之间的任何数字都按预期打印出来但是大于1或小于0的任何数字都会打印到该范围内?

这听起来可能是因为纹理存储了颜色值,因此会剪切到RGBA值的范围。是这种情况还是我做错了什么?

如果是这种情况有没有办法禁用它?我想在纹理中存储任意数据而不是颜色值它只是我希望提高性能,因为纹理/纹理查找结构在GPU中高度优化

1 个答案:

答案 0 :(得分:8)

  

默认情况下,OpenGL是否将纹理值剪辑到0-1范围?

有时 - 取决于您访问纹理的方式和纹理内部格式

  

如果有,有办法禁用它吗?

不是,但您可以更改内部格式以获得所需内容。

GL Spec 4.6,第2.3.5节定点数据转换:

  

当通用顶点属性和像素颜色或深度组件是   它们代表整数,通常(但并不总是)被考虑   要正常化。规范化的整数值在特殊处理时进行处理   被转换为浮点值和从浮点值转换,通常是   称为归一化定点。这些值总是如此   签名或未签名。

     

...

     

从浮点值f到相应的转换   无符号标准化定点值c由第一个钳位定义   f到范围[0,1] ,然后

以下调用是欺骗性的,因为纹理格式给出GL_FLOAT(只是说你给它的数据是32位浮点)。内部格式为GL_RGBA。我相信大多数实现最终都使用GL_RGBA8来存储它,即每个通道8位,如unsigned char r, g, b, a(虽然这不是规范要求)。根据GL规范的上一部分,输入数据值将被钳制,然后转换为固定点。 0.0f及以下变为0且1.0f及以上变为255.

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, GL_RGBA, GL_FLOAT, data);

当您在着色器中使用此类纹理进行读取和写入时,也会发生同样的情况。整数值透明地缩放到[0,1]范围。在您的情况下,使用glGetTexImage + GL_FLOAT进行处理也会将整数值缩放回[0,1],但您传入的数据已被限制。如果您使用GL_UNSIGNED_BYTEunsigned char / GLubyte数组阅读,则应该看到0到25​​5.访问纹理时,使用相同的格式访问纹理可能更快内部格式。然后就不需要转换了。

glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, texData);

简而言之,是的,0到1范围之外的任何东西都会被限制(例如,使用FBO写入典型的RGB / A纹理)。如果您不需要精度但仍希望数字大于1,则可以预先缩放值。

如果您需要更高的精确度,可以使用GL_RGBA32F,如下所示。在这种情况下,不需要转换 - 您的输入与纹理存储相同,钳位不会发生。缺点是它将占用数据的4倍,这意味着访问时传输的数量是4倍。当然,这不仅仅是常规精度,因为你得到了浮点格式的指数表示。

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, GL_RGBA, GL_FLOAT, data);