3
\$\begingroup\$

I'm wanting to create a custom blend state that is similar to XNA's BlendState.Additive, but slightly different. I'm wanting something like the 'custom' output below:

desired blend state

Is something like this possible? I'd even appreciate an answer that could help point me in the right direction. Blend states are a little bit baffling to me at the moment.

For an explanation of why I need this: I'm trying to add emissive maps to our game's rendering. I think most shading that uses emissive maps handle that in the lighting shader. Unfortunately, the emissive maps aren't available to our lighting shader, so I'm just trying to draw them over the top of what's already been rendered. Using BlendState.Additive almost works, but doesn't handle situations where emissive textures are overlapping.

Thanks in advance.

\$\endgroup\$
6
\$\begingroup\$

How blend states/ blend modes work

A blend state defines how newly rendered fragments should combine with existing pixel data. They define how to mix two values:

  1. The Source Color - the color you are trying to render. In your case, this is a grayscale value ranging from white (in the center of the disc) to black (at the border of the disc).
  2. The Destination Color - the color that already exists in the exact position where you want to draw. In your example, this is a color ranging from blue to white.

The additive blend mode you experimented with says: calculate the new color value by adding all individual channels. For example, the new blue value becomes source_blue + dest_blue.

I found this page regarding blend states in XNA: https://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.blendfunction.aspx

Unfortunately, I don't think any of these will produce the effect you are looking for. I'm not sure if it's even possible to describe the effect you want as a blend function. Here are three alternative solutions you could try:


Solution 1: Make your texture blue/white coloured

This will only work if your use-case only requires you to draw on the blue background you've shown in your example. If so, you could use a disc texture that goes from blue (edges) to white (center) and use the standard 100% source pixel blending. Be sure to render from left to right obviously.


Solution 2: Pre-render to an intermediate texture

This is probably the cleanest method, that will work for any type of background. Rather than rendering to the screen instantly, render to an intermediate texture first.

  1. Initialize the intermediate texture to be filled with a black color. Then draw your spheres from left to right with 100% source pixel blending. This will produce a texture that looks like the bottom image in your example, but with a black background rather than a blue one.
  2. Next, render the intermediate texture to the screen using an additive blend mode. This will produce additive blending, while preserving the disc shapes as shown in your example. It will work with any background as well.

Solution 3: Z-buffering method to achieve your effect

There is also a trick you could use to achieve the effect you describe. Z-buffering is a technique used in 3D rendering, that makes sure only the front most fragments are rendered/visible for each pixel. This works by writing the depth (= distance to the camera) of a fragment as it is drawn. Whenever a new fragment is drawn, the renderer checks whether a closer fragment was rendered before, by checking the depth buffer. You can achieve the described effect by:

  1. Enable depth testing/ z-buffering
  2. Draw your circles from right to left, with increasing depth

This will only work if your draw your texture on actual circular polygons, not if you draw on quads.


In summary, I do not believe it is possible to achieve the described effect by using an XNA blend mode. Out of the proposed solutions, think the second approach using an intermediate texture will produce the cleanest result. It is the most robust method as well, working on any background. The Z-buffering method will allow you to render to the screen instantly (not requiring an intermediate texture), but is more involved and only works for simple shapes such as circles and rectangles (as you need to construct polygonal meshes for the shapes to render on).

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I really appreciate the in-depth answer. The 2nd solution ended up being what we went with, and it works fine. Thanks for the help! \$\endgroup\$ – Graeme Collins Apr 20 '15 at 19:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.