Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Untangling When and What Values are Clamped in OpenGL Blending on Different Render Targets

TL;DR: What values are clamped and under what circumstances (enabled flags and renderbuffer types (esp. RGBA_F32)), when blending is enabled?

  • The fragment shader output?
  • The blending factors?
  • The result of the blend equation?
  • Others?

The mechanisms I have found for clamping:

  1. Shader output (via glClampColor): This appears to control glReadPixels, but there are extension flags GL_CLAMP_VERTEX_COLOR and GL_CLAMP_FRAGMENT_COLOR which do "something". As far as I can tell from the extension spec., they clamp the output from the vertex or fragment shader.
  2. Shader output (via render to fixed-point): See this answer which quotes the GL spec.: "The conversion from a floating-point value f to the corresponding unsigned normalized fixed-point value c is defined by first clamping f to the range [0, 1] . . ." By contrast, (when writing to a floating point render target, presumably), Nicol Bolas writes here that "What gets written by the fragment shader will always be unclamped.".
  3. Implied clamping: From the documentation for glBlendFunc: "All scale factors have range [0,1]." Does this mean the source and destination factors are clamped before the equation happens?
  4. Implied clamping: From the documentation for glBlendEquation: "For these equations all color components are understood to have values in the range [0,1]." Does this mean the source and destination colors are clamped before the equation happens?
  5. Result clamping: From the same page: "The results of these equations are clamped to the range [0,1]."

In my experiments on an RGBA_F32 render target, none of these modes of clamping happen (I confirm this by reading back values from the render target with glGetTexImage). I need preferably (3) to occur, but I am requesting clarification on the documentation so that I can figure it out myself.

like image 299
imallett Avatar asked Oct 14 '25 09:10

imallett


1 Answers

Part of the stuff you quoted is very old, and there might lie the root of the confusion. I'm going through your points from the perspective of modern GL, and I'm going to cite the OpenGL 4.5 core profile spec for this. However, none of that is specific to OpenGL 4.x. This is basically unchanged since GL 3.2 core.

1. glClampColor()'s only remaining function is clamping during glReadPixels. Quoting the spec on page 680:

Note that the FrontFace and ClampColor commands are not deprecated, as they still affect other non-deprecated functionality; however, the ClampColor targets CLAMP_VERTEX_COLOR and CLAMP_FRAGMENT_COLOR are deprecated."

Clamping the vertex shader output did only make sense for the depracted builtin varyings like gl_FrontColor, gl_BackColor and so on. Those were only needed to mimic the fixed-function vertex processing, and were never a good idea to use at all. With generic outputs, the GL has no chance to know which values are colors and which one's aren't.

2. The situation for the fragment shader is similiar. With modern rendering approaches, the outputs aren't necessarily colors any more, but represent generic data, so implicitly clamping the values is harmful. You always can manually clamp the values in the shader if you want to.

The quote from the spec Reto Koradi's answer is unchanged in the GL 4.5 spec. The shader outputs will only be clamped if the respective render target is of fixed-point or integer format.

3.,4. and 5. Those documentations are outdated. The GL spec has this to say about this in section 17.3.8:

If the color buffer is fixed-point, the components of the source and destination values and blend factors are each clamped to [0; 1] or [-1; 1] respectively for an unsigned normalized or signed normalized color buffer prior to evaluating the blend equation. If the color buffer is floating-point, no clamping occurs. The resulting four values are sent to the next operation. Blending applies only if the color buffer has a fixed-point or floating-point format. If the color buffer has an integer format, proceed to the next operation.

The clamping of the blending result happens in the next step, which handles the optional sRGB conversion (however, the clamping step there is not tied to the sRGB conversion). Quoting section 17.3.9:

The resulting cs values for R, G, and B, and the unmodified A form a new RGBA color value. If the color buffer is fixed-point, each component is clamped to the range [0; 1] and then converted to a fixed-point value using equation 2.3. The resulting four values are sent to the subsequent dithering operation.

So yes, when using a GL_RGBA32F framebuffer, no implicit clamping happens at all. And actually, this is the only useful mode of operation for the generic case. If you need some clamping to occur at step 3: just clamp the factors before you send them to glBlendFunc().

like image 144
derhass Avatar answered Oct 17 '25 18:10

derhass