I am trying to implement an image-space technique (caustics mapping) in OpenGL and Cg and I am having problems with one of its steps.
What I haven't figured out is how to store world positions ( a 3d vector of integer values where each coordinate is in the range say [-300,300] ) in a texture instead of color values. Specifically, I would output the position of each fragment in the fragment shader instead of its color.
It seems like the storage format of textures (according to glTexImage2D description) is always clamped to the range [0,1].
Do I perhaps need some fancy extension to implement this?
Thanks for your time,
There are two ways you could go about this:
First, if your positions are all within a certain range such as [-300, 300], you could map that range linearly into the [0, 1] interval. Then when you read the texture later on in another shader, execute the opposite mapping to get back the original values.
However, this has the problem that with a standard RGBA texture you still only get 8 bits of precision per component, and for representing positions that is often not enough (you'll get ugly artifacts due to rounding errors). To get around this, it is possible to use extensions to get a floating-point texture format, which lets you store either a 16-bit half-precision or a 32-bit single-precision floating point number per component. Besides having more precision, these are also not clamped to [0, 1] and so you can just store the positions directly.
Floating-point textures are provided by ARB_texture_float. If you want to render to such a texture you'll also need ARB_color_buffer_float and perhaps ARB_half_float_pixel. (BTW, all these are native under OpenGL 3.0, so if you have that you don't need to mess around with extensions at all.)
Extensions? What's wrong with just specifying GL_FLOAT in the glTexImage2D function? Works fine for me.
If you're talking about specifying it for the 'format' (7th) parameter, that just controls the input format, not the internal format. If the internal format is 8-bit then it will clamp all the pixels to [0, 1], round everything off to 8 bits, etc. as the image is uploaded.
To get a floating-point texture you need to specify RGBA32F or RGBA16F or similar for the 'internalFormat' (3rd) parameter. These enumerants are provided by ARB_texture_float.
Hmm, you're right. I just did a quick texture copy test and it did truncate my input. I always thought using the generic GL_RGB / GL_RGBA the driver would just chose the internal format based on your format type, but it appears it just defaults to GL_RGB8. A little ugly, but defining the internal types using the ARB extensions you mentioned does seem to do the trick.
So there you have it sveinn, lookup GL_RGB32F_ARB in glext.h and you'll also see a bunch of other floating point formats to use should you need them.