Render Targets
Introduction
Rendering translucent content onto an offscreen render target (MonoGame's RenderTarget2D, raylib's RenderTexture2D) and then compositing that target elsewhere is a common pattern, but it has a gotcha that does not show up when drawing straight to the screen: the render target's own alpha channel matters.
When you draw straight to the screen, nothing reads the screen's alpha channel afterward, so a blend mode that leaves it in whatever state is harmless. A render target is different: its alpha channel gets read again the next time the target itself is composited onto something else. If drawing multiple translucent objects onto the target uses a blend mode that does not correctly accumulate that alpha, the target ends up with an alpha channel that is wrong even though the colors on screen look correct at the time. The most common symptom is content that appears fine while you are drawing to the target, but darkens, fades unevenly, or loses transparency where you did not expect it once the target itself is drawn somewhere else.
The fix in every backend is the same idea: use blend factors that add to the target's alpha rather than ones designed for compositing straight onto an opaque screen. The exact code differs per backend.
MonoGame
GumBatch can draw Gum objects onto a RenderTarget2D the same way a regular SpriteBatch can:
// Draw
// Assuming MyRenderTarget is a valid render target:
GraphicsDevice.SetRenderTarget(MyRenderTarget);
gumBatch.Begin();
gumBatch.Draw(SomeGumObject);
gumBatch.End();
// now set the render target to null to draw it to screen:
GraphicsDevice.SetRenderTarget(null);
spriteBatch.Draw(MyRenderTarget, new Vector2(0, 0), Color.White);A container only ever drawn through GumBatch (never AddToRoot) has no EffectiveManagers, which breaks Forms controls that depend on it — most notably a Menu/ComboBox popup, which opens but never closes on an outside click. Call container.AttachManagersOnly(SystemManagers.Default) once after creating it so this works correctly.
For a runnable example, see the RenderTarget screen in the Gum immediate-mode sample. It draws a scaled, offset render target alongside a full-screen UI drawn at 1:1, both interactive in the same frame:
If you are rendering multiple translucent objects onto a render target, the BlendState must be set so that alpha accumulates rather than getting overwritten. The default BlendState can "remove" alpha from the render target when new instances are drawn on top of existing content.
The following shows a BlendState for objects which have partial transparency and are drawn onto a render target, using separate alpha source/destination factors:
Raylib
Raylib's canned BlendMode.Alpha uses the same source-alpha factor for both the color and alpha channels. That is correct for compositing onto an opaque screen, but drawing multiple translucent objects onto a RenderTexture2D with BlendMode.Alpha leaves the texture's alpha channel under 255 even when the colors look correct, because each draw multiplies the destination alpha down instead of accumulating it. Compositing that texture again elsewhere (for example, blitting it to the window) then darkens the result a second time using that leftover alpha.
The fix is to set separate alpha blend factors with Rlgl.SetBlendFactorsSeparate instead of using the canned BlendMode.Alpha, then select BlendMode.CustomSeparate. Keep the color factors as a normal alpha blend, but set the alpha factors to accumulate (GL_ONE, GL_ONE_MINUS_SRC_ALPHA) instead of overwrite:
Last updated
Was this helpful?

