Storing pointers in textures, how to? - opengl

I have a ARGB float texture that contains data. One of the data entries is an index that points to another pixel in the texture.
This is the code decoding the index into a UV coordinate, which can be used with a texelfetch to read the pixel it points to:
ivec2 getTexelfetchCoord_TEXTURE(float index)
{
return ivec2( mod(index, TEXTURE_WIDTH), int(index / TEXTURE_WIDTH) );
}
This works fine as long as the texture is no larger than 4096x4096. Any larger than that, and the floating point index value becomes inaccurate due to float precision issues.
The problem is that the 32 bit floating point only uses 24 bit for the integer part, which means the U and V components only have 12 bits each. 2^12=4096, alas the max range is 4096. Using the sign I could extend this to 8192, but that is still not enough for my purpose.
The obvious solution would be to store the index as two separate entries, U and V coordinates. However, for reasons that are too complex to get into here, this option is not available to me.
So, I wonder, is there a way to pack a signed 32 bit integer into a float, and unpack it back into an int that has the full 32 bit precision? Actually, I am not even sure if int's in OpenGL are really 32 bit, or if they are in fact internally stored as floats with the same 24 bit range...
Basically I would like to pack UV coordinates into a single float, and unpack to an UV coordinate again, with an accurate range beyond 4096x4096. Is this possible in GLSL?

Related

How to Unpack Each Byte of a 4-byte Int Uniform in WebGL GLSL?

WebGL doesn't support bit wise operation. So I convert my int uniform to float. Then use dividing and mod to extract each byte.
However, because of the precision issue, converting int to float loses some precision if my int is too big. Is there any elegant solution to deal with this? Currently my idea is only storing 3 bytes in my 4-byte int uniform.
It's not a 100% clear what you want to do. First, realize that a 32 bit float has 23 bits of mantissa. That's a one less than 3 bytes. Also, your shader might run at less precision, like fp16 or 8.8 fixed point. So the answer to your question is: No.
Take a step back and think about why you want ints in a low end shader. Usually the mod trick was used to pack (and unpack) float values into and rgba bytes texture or framebuffer.
For uniforms it makes little sense. The shader will still run at low (float) precision. So any math you do will run at at most 23bits. And you can supply that just fine as a float uniform.

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

Encoding
As part of a graphical application I'm currently working on, I need to store three signed floats per each pixel of a 32 bit texture. At the moment, to reach this goal, I'm using the following C++ function:
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;
}
Although this encoding function brings along a considerable loss in precision, things are made better by the fact that the range of considered values is limited to the interval (-4,4).
Nonetheless, even though the function yields decent results, I think I could do a considerably better job by exploiting the alpha channel (currently unused) to get additional precision. In particular I was thinking to use 11 bits for the first float, 11 bits for the second, and 10 bits for the last float, or 10 - 10 - 10 - 2 (unused). OpenGL has a similar format, called R11F_G11F_B10F.
However, I'm having some difficulties coming up with an encoding function for this particular format. Does anyone know how to write such a function in C++?
Decoding
On the decoding side, this is the function I'm using within my shader.
float3 decode(float4 color) {
int range = 8;
return color.xyz * range - range / 2;
}
Please, notice that the shader is written in Cg, and used within the Unity engine. Furthermore, notice that Unity's implementation of Cg shaders handles only a subset of the Cg language (for instance pack/unpack functions are not supported).
If possible, along with the encoding function, a bit of help for the decoding function would be highly appreciated. Thanks!
Edit
I've mentioned the R11F_G11F_B10F only as a frame of reference for the way the bits are to be split among the color channels. I don't want a float representation, since this would actually imply a loss of precision for the given range, as pointed out in some of the answers.
"10 bits" translates to an integer between 0 and 1023, so the mapping from [-4.0,+4.0] trivially is floor((x+4.0) * (1023.0/8.0)). For 11 bits, substitute 2047.
Decoding is the other way around, (y*8.0/1023.0) - 4.0.
I think using GL_R11F_G11F_B10F is not going to help in your case. As the format name suggests, the components here are 11-bit and 10-bit float numbers, meaning that they are stored as a mantissa and exponent. More specifically, from the spec:
An unsigned 11-bit floating-point number has no sign bit, a 5-bit exponent (E), and a 6-bit mantissa (M).
An unsigned 10-bit floating-point number has no sign bit, a 5-bit exponent (E), and a 5-bit mantissa (M).
In both cases, as common for floating point formats, there is an implicit leading 1 bit for the mantissa. So effectively, the mantissa has 7 bits of precision for the 11-bit case, 6 bits for the 10-bit case.
This is less than the 8-bit precision you're currently using. Now, it's important to understand that the precision for the float case is non-uniform, and relative to the size of the number. So very small numbers would actually have better precision than an 8-bit fixed point number, while numbers towards the top of the range would have worse precision. If you use the natural mapping of your [-4.0, 4.0] range to positive floats, for example by simply adding 4.0 before converting to the 11/10-bit signed float, you would get better precision for values close to -4.0, but worse precision for values close to 4.0.
The main advantage of float formats is really that they can store a much wider range of values, while still maintaining good relative precision.
As long as you want to keep memory use at 4 bytes/pixel, a much better choice for you would be a format like GL_RGB10, giving you an actual precision of 10 bits for each component. This is very similar to GL_RGB10_A2 (and its unsigned sibling GL_RGB10_A2UI), except that it does not expose the alpha component you are not using.
If you're willing to increase memory usage beyond 4 bytes/pixel, you have numerous options. For example, GL_RGBA16 will give you 16 bits of fixed point precision per component. GL_RGB16F gives you 16-bit floats (with 11 bits relative precision). Or you can go all out with GL_RGB32F, which gives you 32-bit float for each component.

Storing one float value in vec3

I'm working with 2D shadows in LWJGL and i'm storing distances in shadowmap in 3 color pixels (GL_RGB16), however i only use the 16-bit R channel and the other ones are left unused, which leads to bad shadow quality due to loss in float precision. So i'm looking for a way to store a float into one vec3 in glsl without precision loss (and unpacking it).
You have two options, realistically, you could either use a higher precision format (which would probably be much better since you would pass one uniform instead of three) or you could use a multiplication format to store your higher precision number.
For example, you could have the integer part of the number in the R (X) component, a floating point part in the G (Y) component and an additional multiplier in the B (Z) component. in the shader, to get the value out you would do the following operation:
float distance = (shadow.r + shadow.g) * shadow.b;
Now, I strongly discourage you use this system for a few reasons. Firstly, its computationally expensive to have to store a high precision value into this format and then to take it from this format back to the original value, especially considering you would be doing this very often (especially if you do the calculation in the fragment shader). Secondly, this is just a proof of concept, as I stated above, it would be a better idea to use a higher precision type, and send a single float uniform instead of a three component vector.

How do I specify Normals using GL_INT_2_10_10_10_REV in a VBO array?

I have normals which are (x,y,z) as 3 floats, and I want to pack these into a VBO array as GL_INT_2_10_10_10_REVs in order to reduce memory consumption on the graphics card. Can anyone provide an example of how to do this in C++ / C#?
The OpenGL documentation says you can do this -
https://www.opengl.org/wiki/Vertex_Specification_Best_Practices
However, I can't find any examples of how to place the three floats (which can be positive or negative) into the single packed 4 byte structure.
You'll need to pack them in a bitfield that looks something like:
struct norm{
int a:2;
int Z:10;
int y:10;
int X:10; //order may need to be different
}
ensure the field you put in are scaled to -512 to 511
Check the spec, section 10.3.8, "Packed Vertex Data Formats", page 343:
For INT_2_10_10_10_REV, the x, y and z components are represented as 10-bit signed two’s complement integer values and the w component is represented as a 2-bit signed two’s complement integer value.

what is need of integer and SNORM textures

What is the advantage or need of integer and SNORM textures? when do we use (-1,0) range for textures?
Any example where we need specifically integer or SNORM textures?
According to https://www.opengl.org/registry/specs/EXT/texture_snorm.txt,
signed normalized integer texture formats are used to represent a floating-point values in the range [-1.0, 1.0] with an exact value of floating point zero.
It is nice for storing noise, especially Perlin.
Better than float textures because no bits wasted on the exponent.
Unfortunately, as of GL4.4 none of the snorm formats can be rendered to.
You can use the unorm formats and *2-1 for the same effect, although there may be issues with getting an exact 0.