0
\$\begingroup\$

I've run into a problem where using the CanvasGroup component to fade in/out several Image components under a hierarchy produces an unwanted result, where each individual sprite that overlaps with another sprite will "blend" its color values in the overlapping areas like so:

enter image description here

The intended effect I'd want is for the red and blue squares to fade out together like they were one sprite.

enter image description here

As you can see, the overlapping parts of the squares are not "blending together".

One hack is to just overlay a blank image of the same size as all of the image components shown on the screen and just fade that. However, this doesn't work at all if the overlayed image also has several other image components.

I would like to know if there are any other alternatives that aren't too complicated.

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

CanvasGroup applies its alpha value to each child UI element individually. That's why your sprites don't blend like they were one.

You can avoid this problem using a Render Texture before applying transition effects. This temporary texture contains all your UI elements in a single image. Then, you change its alpha value to fade it out.

Arrange the UI elements

We will render certain UI elements separately from the others. To do so, we first create a new Canvas GameObject. Then, we move the UI elements of interest in the Hierarchy as its children. Note: such new Canvas has no CanvasGroup Component. Let's call it FadeCanvas for simplicity.

Set up the Canvas Component

Select the FadeCanvas GameObject, and change the Canvas Component Render Mode value to 'Screen Space - Camera'. Unity will prompt you to specify a Render Camera.

Create a new Camera as a child of your Main Camera. (It's a child just for in-editor management purposes). Let's call it UICamera, and set its Culling Mask to 'UI' only.

Now, select FadeCanvas again, and drag and drop UICamera in the Render Mode field box.

Create and assign the Render Texture

Create a Render Texture from the Project window (or via Assets > Create > Render Texture). Select the UICamera, and drag and drop the Render Texture in the Target Texture field box.

Note: you need to set the Render Texture size to the current screen size via code. Otherwise, the Render Texture won't be the correct size when rendering.

Display the Render Texture

In your primary Canvas GameObject, create a RawImage and assign the Render Texture as its Texture source. Transparency is achieved by changing the alpha value of the color attribute.

If the Render Texture's size is the same as the screen's, stretch it across the whole Canvas via RectTransform's Anchor Presets.


This solution may be a bit tricky to set up. I recommend it for complex, dynamic UI setups. If no elements are overlapping, fall back to CanvasGroups and alpha values. If objects overlap but then nothing else moves, you can optimise by rendering UI on the Render Texture only when changes occur. If you deactivate the UICamera, the Render Texture will contain the last rendering pass.

\$\endgroup\$
0
\$\begingroup\$

It would be better if you told about what the objects really are and why all of them can't be a single sprite, but given what you said, I suggest using a sprite mask:

In your example, add a sprite mask component and set the sprite to the blue box, and set the Mask interaction to not visible under mask so the part of the red box under the blue box will be ignored

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .