4

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?

chrispepper1989
  • 2,100
  • 2
  • 23
  • 48
  • the fragment shader expects the output color to be between 0 and 1 though – ratchet freak Dec 16 '14 at 16:30
  • By "function pointer approach", I assume you mean subroutine? That's a Shader Model 5.0 (GL4) feature and it also is not practical for a shader that only has two variations. If you had say 3 different boolean conditions for 6 combinations of behaivor, _then_ subroutines might start to make sense. – Andon M. Coleman Dec 16 '14 at 19:22

3 Answers3

7

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.

Community
  • 1
  • 1
Andon M. Coleman
  • 42,359
  • 2
  • 81
  • 106
  • 2
    I should point out that if you do not write to an output from a fragment shader, then the value of that output is undefined... so in theory the implementation is free to write anything it wants or nothing at all to the output that _*you*_ did not write to. _"If subsequent fixed functionality consumes fragment data and an execution of a fragment shader executable does not write a value to it, then the fragment data consumed is undefined."_ (effectively states that things like blending will have undefined results for the branch not taken). – Andon M. Coleman Dec 16 '14 at 19:33
3

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.

BDL
  • 21,052
  • 22
  • 49
  • 55
0

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.

ratchet freak
  • 47,288
  • 5
  • 68
  • 106