Opacity of a sprite hierarchy

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By SasQ
:warning: Old Version Published before Godot 3 was released.

Suppose I have a cutout character made of a hierarchy of multiple sprites.
Now I want to turn it into a “ghost” for a while, by modulating its transparency.
The problem is, when I set the transparency of the top-level sprite (the parent of the entire hierarchy), it pretty much works by setting the transparency on all of its subnodes, which looks terrible, because the parts that weren’t supposed to be visible (because they were previously obscured by other parts, like clothes, body etc.), now can be seen through other parts :stuck_out_tongue: Here’s a simple mockup example that demonstrates this problem:

Bad opacity

What I rather expected is this:

Good opacity
(not made in Godot; I made it in a graphics editing software)

that is, I want the entire image of the sprite to become semi-transparent, not its particular consistuent parts.

If it makes any difference, there may be more than one such a “ghost” on screen, each with different transparency (since some of them will gradually disappear and appear again).

How can this be achieved in Godot?

I tried to save the hierarchy as a scene, then instantiate it and change its opacity instead, but the effect is the same.

Did you find any better solution to this? Is there anything new on Godot 3.1 to achieve it?

Samuel Pedrajas | 2019-02-17 00:12

:bust_in_silhouette: Reply From: Zylann

I don’t know how this can be done easily in Godot, because it relates to how drawing transparent stuff works in OpenGL in the first place.

Taken litterally, it means that all parts of your character must be rendered NOT on screen, but on a temporary buffer at full opacity, and then draw this buffer with transparency (and I bet that’s what you did in your image editing software, using 2 layers).

In Godot world, I don’t know much ways of doing this.
Maybe you can with a separate viewport, set it to target an offscreen texture, draw your character inside, and render the result on the screen using a single sprite with transparency.

But that’s my own theory, it may not be efficient, maybe other people have a better solution.

Using a light as mask to “cut” the back object can help, but masks may not work fine if you need many (there can be workarounds, though)

eons | 2017-11-26 21:08

Well, I wouldn’t expect an effect that is quite common in computer games to be that hard to achieve in as good engine as Godot is :confused: So far I’ve been very satisfied with what I learned about its features.

I thought about the render-to-texture approach too, but I thought that it will be a bad idea, because it would complicate the rendering a lot - I would have to go through that process for every “ghost” I need to draw. So I figured it would not only be a MESS in code, but also might damage the efficiency. (Speaking of which: how many render targets is considered too much? :q ) But I suppose I would need it anyway if I want to apply some other effects (e.g. shaders) to the entire composited hierarchy?

Yes, that’s how I made that image. I composited the fully opaque images first into a merged layer, then applied the transparency to the final result. So you’re saying that this is the only way to achieve the same effect in Godot? Ech… if only Godot could do that automatically for me for the entire hierarchy by setting some “global transparency” on the top-most node… :confused:

I’ll try the render-to-texture approach for now, maybe it’ll do, but I’ll wait for some other answers, maybe there’s a better solution.

As for using lights for anything not light related: I consider it an ugly hack, and not very reliable either, since the number of light maps applied is limited. I already tried that for another effect I needed (masking the hierarchy to a region), but it didn’t work well when the lights started overlapping :stuck_out_tongue: (Maybe I’ll ask about that too in a separate question later.)

SasQ | 2017-11-26 21:36

OK I tried the render target approach:
http://mistu.info/Stuff/Godot/Test_mask.zip
and it seems to work as I expected, but with some minor problems:

  1. Everything I attach as a subnode of the Viewport node disappeared from the scene. The sprites are visible in the ViewportSprite, but I can no longer select any of them in the editor. (I suppose that they’re only images in the ViewportSprite, but why did they disappear from the editor? :q )

  2. There’s a yellow warning sign next to the ViewportSprite saying that I have to connect it to a viewport set up as “render target” - which is odd, because that’s what I did :stuck_out_tongue: It is already connected and it works fine in the editor.

  3. It is quite a mess now, as I suspected. Here’s how my test hierarchy looks like now:

    Node2d
      Forest background
        ViewportSprite      # Replaces my hierarchy, I set opacity here.
          AnimationPlayer   # Moves it around and modulates the opacity.
      Viewport
        Sprite1             # This is the root of my original hierarchy.
          Sprite2           # I can't select these anymore, they're gone.
          AnimationPlayer   # Controls the animation of the hierarchy

Now it would be great if I could somehow reuse this structure and apply it to other hierarchies I have (perhaps programmatically?). Any ideas?

SasQ | 2017-11-26 22:36

Unfortunately, this “common” effect is as hard to do in many game engines AFAIK (if you care that much) and as you may have guessed, it always relies on doing two-pass rendering of some sort. If you think there should be a mechanism in Godot to simplify this, perhaps you could ask for a feature on Github, explaining your situation. I’ve had the same problem with my UI when I wanted it to fade, like you I could see everything through but I didn’t bother fixing that…

Zylann | 2017-11-27 00:47

:bust_in_silhouette: Reply From: Hammer Bro.

This may be a bit of a dated response but since it came up on Google I’ll bite:

Put all of those sprites onto a new Node2D then set the new Node2D’s self_modulate.a to whatever the transparency you want to be.

It will, much like the other posters suggest, render all the children of that Node2D as opaque, then change just the opacity of the final result (the Node2D’s self_modulate).

I don’t know exactly when self_modulate was introduced, but the mechanism of changing opacity via a [self_]modulate.a property was new to 3.0.

:bust_in_silhouette: Reply From: Noelb

This is an old question, but I had difficulty finding an obvious way to do this in Godot 3.3.2, so I think it’s still unresolved?

The way I was able to achieve this was to take my collection of sprites and nest them in a Viewport that was itself nested inside a ViewportContainer.

Node2d
  ViewportContainer
    Viewport
      RandomSprite1
      RandomSprite2

Adjusting the “modulate” property of ViewportContainer achieved the desired effect.

Note: Once the children are parented under a Viewport, I found it very difficult to edit them in the visual editor. You may need to move them outside the viewport to move them around and then reparent them back in the viewport when done (there may be a better trick to this that I missed?).