c++ - 纹理值被限制在 0-1 范围内?

标签 c++ opengl textures

简单的问题:

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

详细问题:

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

我像这样创建大小为 16x16 的 RGBA 值纹理:

//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 中得到了高度优化

最佳答案

Does OpenGL clip texture values to the range 0-1 by default?

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

And if it does is there a way to disable this?

不是真的,但您可以更改内部格式以获得您想要的内容。

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

When generic vertex attributes and pixel color or depth components are repre- sented as integers, they are often (but not always) considered to be normalized. Normalized integer values are treated specially when being converted to and from floating-point values, and are usually referred to as normalized fixed-point. Such values are always either signed or unsigned.

...

The conversion from a floating-point value f to the corresponding unsigned nor- malized fixed-point value c is defined by first clamping f to the range [0, 1], then

下面的调用具有欺骗性,因为 GL_FLOAT 是针对纹理格式给出的(这只是说您提供的数据是 32 位 float )。内部格式为 GL_RGBA。我相信大多数实现最终基本上使用 GL_RGBA8 来存储它,即每个 channel 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 到 255。访问纹理时,访问它可能更快它的格式与内部格式相同。那么就不需要转换了。

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);

关于c++ - 纹理值被限制在 0-1 范围内?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25305816/

相关文章:

opengl - Shader - 性能和功能

OpenGL : SSAO vs Shadow mapping

c++ - 如何在 Qt 应用程序中替换 'gluOrtho2d'

javascript - 如何使用加载的图像数据更新 ThreeJS 中的纹理?

c++ - 如何编辑文本文件中的特定行?

c++ - 如何调用类的析构函数/构造函数

c++ - OpenGL 将纹理应用于曲面 segmentation

html - 背景渐变/图像上的对 Angular 线/纹理叠加

c++ - 关于继承/类型转换的一些最后问题

Mac 上的 C++ : linker command failed with exit code 1 (use -v to see invocation)