'How to render to a unsigned integer format
When rendering to an FBO that has an unsigned integer format presumably I can not:
gl_FragColour = uvec4(100,100,100,100);
as gl_FragColour is a vec4. So presumably I would have to define my own out?
out uvec4 colour
But will this be interpreted correctly without any other changes?
Also I wanted to use the same shader for both unsigned int formats and normal float textures with a if on a uniform (static branch). I am guessing that would be out of the question (unless I can have 2 outs and only set one?) and I might have to explore a function pointer approach?
Solution 1:[1]
So presumably I would have to define my own out?
Yes, absolutely. You must declare your own fragment data output to write anything other than a floating-point color value.
Mind you, "UNORM" (unsigned normalized) formats like GL_RGB8 take floating-point color as their input even though they are fixed-point data types. The real oddballs are actually the new INT/UINT formats introduced in OpenGL 3.0; they do not have floating-point to integer conversions defined and thus can only be written to using integer colors.
But will this be interpreted correctly without any other changes?
Traditionally what happens is that the value gets clamped to the range [0.0,1.0] and then since 99% of the time the output color format is unsigned normalized, each component is re-scaled to the fixed-point range (e.g. if GL_RGB8 => (float_color * 255)).
If you have a floating-point or integer color buffer the clamping and scaling behavior no longer applies, but of course writing a floating-point color to an integer color buffer is undefined as discussed earlier. This is why when integral color formats (signed and unsigned integer) were introduced to core GL, gl_FragColor became deprecated (GL 3.0).
Also I wanted to use the same shader for both unsigned int formats and normal float textures with a if on a uniform (static branch). I am guessing that would be out of the question (unless I can have 2 outs and only set one?) and I might have to explore a function pointer approach?
Actually, this is doable. But it would require you to use two different FBO image attachment locations.
Imagine the following shader:
#version 330
uniform bool is_float;
layout(location = 0) out vec4 frag_color_float;
layout(location = 1) out uvec4 frag_color_uint;
void main (void) {
if (is_float)
frag_color_float = vec4 (0.1f, 0.2f, 0.3f, 1.0f);
else
frag_color_uint = uvec4 (1,2,3,0xff);
}
In the above scenario, you would attach a traditional floating-point or fixed-point color buffer (GL_RGBA32F or GL_RGBA8) to GL_COLOR_ATTACHMENT0 and an unsigned integer color buffer (GL_RGBA32UI) to GL_COLOR_ATTACHMENT1.
I do not know how practical this approach is in the long-run, but it is possible.
Solution 2:[2]
gl_FragColor is deprecated since GLSL 130. Since then, you can define any output for a fragment shader you want and especially also in uvec4 format:
layout(location = 0) out uvec4 fragColor;
void main()
{
fragColor = uvec4(100,100,100,100);
}
If the framebuffer has an unsigned integer format, this should work without any problems.
Solution 3:[3]
The output of the fragment shader is always automatically rescaled from 0.0-1.0 to the range that fits in the FBO. So there is no need to change how you output in the shader.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Community |
| Solution 2 | BDL |
| Solution 3 | ratchet freak |
