Inverted Colour Blending?

Does anyone see a means to have an object render such that its colour is the inverse of the colour behind it, blended via transparency.

So, for a given pixel, the result should be something like this, I think:
finalColour = (1 - frameBufferColour)*incomingAlpha + frameBufferColour*frameBufferAlpha

Right now I’m using a ColorBlendAttrib set to subtract the frame-buffer colour from one. Something like this:

np.setAttrib(ColorBlendAttrib(ColorBlendAttrib.MSubtract, ColorBlendAttrib.OOne, ColorBlendAttrib.OOne)

And this works!

Save that it seems to lose all transparency above “0”. That is, regardless of alpha-values from texture or vertex-colour, there is no semi-transparent blending between the inverted-colour object and whatever is behind it.

If I simply remove the call to “setAttrib”, transparency resumes as expected, so it does seem to be a result of the blending-attrib.

And this makes sense! I have the object in question producing a result that doesn’t involve its alpha. But right now I don’t see a clear way of incorporating that alpha-value…

So, does anyone see a way of producing the effect that I’m looking for, while still retaining transparency…?

(Without using a shader, that is; I don’t want to make a shader specifically for this, ideally.)

I think you want to ignore the framebuffer alpha. It’s not relevant for alpha blending. Usually, you use 1-incoming_alpha instead.

Try passing OIncomingAlpha to the first operand and OOneMinusIncomingAlpha to the second.

Hmm… Those operands don’t seem to produce the desired effect, either: with a blending-mode of “MSubtract” (as before), I see largely the texture’s colour (white fading to black), again with no sign of partial transparency, and with a blending-mode of “MAdd” I see much the same, but now with partial transparency.

In either case I see no inversion of the background colour.

It looks like what you’re trying to achieve is beyond my comprehension. However, I assume you can influence the transparency or restore it through the material, which you can calculate mathematically and apply after color inversion.

There’s already a texture applied that includes transparency. Alas, when inverting as I currently am, that only seems to have effect when the texture is fully transparent. :/

To perhaps better explain what I’m trying to do, I have a bit of UI that I want to have be visible against just about any backdrop.

A simple (note that I don’t say “easy” :P) way of doing this–albeit one that fails against 50%-grey backdrops–is to have the colour of the UI element be an inversion of the colour of the background. So, when the background is blue, the UI element would be red; when the background is white, the UI element would be black; and so on.

Using a colour-blending mode of “subtract”, an “incoming” operand of “1”, and a “source” operand of “1”, together with a white UI element, results in a given pixel being, essentially, “1 - backdrop”–i.e. the desired inversion.

But alas, as mentioned above, the transparency doesn’t seem to be working as I desire when I do use that approach! :/

Now I understand, this is something similar to the mode for the visually impaired. I think this problem can be solved by loading the alpha channel with a separate texture. I’m not sure what will be ignored when blending, but I think you can try.

https://docs.panda3d.org/1.11/python/reference/panda3d.core.Texture#panda3d.core.Texture.set_alpha_filename

I think theoretically you can assign a transparency texture in each frame after the blending operation. Again, I’m not sure if there is something like a callback to implement such a trick.

1 Like

Hmm, no, I see no apparent effect from the use of that method, I’m afraid. :/

To be clear, what I tried was something like this:

tex = loader.loadTexture(<filename>, minfilter = SamplerState.FTLinearMipmapLinear)
tex.setAlphaFilename(<other_filename>)
myNodePath.setTexture(tex)

What colour is the object itself? Does it matter? And you want to show the inverse of the framebuffer colour where the object’s alpha is 1.0, and the framebuffer colour where the object’s alpha is 0.0, right?

The normal blending formula with “subtract” mode is:

result = incolor * o1 - fbcolor * o2

But what you want to achieve is the following, ignoring the incoming color:

result = (1 - fbcolor) * inalpha + fbcolor * (1 - inalpha)

So you need to refactor it to look like one of the blending equations. Let’s factor out fbcolor:

result = inalpha - fbcolor * inalpha + fbcolor - fbcolor * inalpha
result = fbcolor * (1 - 2 * inalpha) + inalpha

So, you actually need factors OOneMinusTwiceIncomingAlpha and OIncomingAlpha (and make sure the incoming colour itself is white). Unfortunately, the former does not exist.

One approach is to write a shader to take the alpha value that would have been written, and multiply it by two, so that you can use OOneMinusIncomingAlpha. But you said you don’t want to write a shader, so we have to get a bit more creative.*

We haven’t really used the incoming colour term, and using it would give us a little more flexibility. So instead of writing the transparency to the alpha channel of the object’s textures, is it at all possible to assign it to the colour channels? Making the object appear white where it should be fully opaque (inverting), and black where it should be fully transparent (non-inverting)? Depending on how you are loading your texture this could be just a tweak in the format assignment, or you can use a different texture stage mode to achieve this.

Replacing inalpha with incolor in your equation makes it look like this:

result = (1 - fbcolor) * incolor + fbcolor * (1 - incolor)

Which already fits the standard blending equation with the parameters MAdd, OOneMinusFbufferColor, OOneMinusIncomingColor!

All this assumes that you indeed don’t intend to use the colour of the rendered object. If you do, then we may have to get even more creative. :slight_smile:


* It may perhaps be possible to apply the transparency texture twice in additive mode, or use a fancy texture combine mode, but we may have to do something to disable clamping as well if we do this, I’m not sure.

Ah, indeed, that does seem to work nicely! Thank you very much, and a clever idea! :slight_smile:

1 Like

Great, glad it works!

Just make sure that the object being rendered is not affected by lighting or fog or other things that would cause its “whiteness” (prior to blending) to be affected by something other than your alpha map.

1 Like

Indeed, I think that in this case there’s little that might affect it so. :slight_smile: