0
\$\begingroup\$

So, complicated title, but I am not sure how to properly describe this phenomenon.

I have switched recently from Unity version 2019 to 2021 to use the URP 2D-Renderer and make use of the _CameraSortingLayer for blending in custom shaders.

Since then the Sprite-Unlit-Default shader produces weird results for unrelated GameObjects in the same scene.

as example this Characters mouth, the character itself consists of stacked sprites, which are captured by another camera and rendered onto a render texture. That render texture is then used in the scene. The mouth has a slight transparency in the lipstick to fade it onto the face:
Mouth sprite

Resulting face as it should be:
Mouth as should be

When I use the Sprite-Unlit-Default shader (which I assume is the proper choice, since I am not using lights), however the mouth transfers that transparency over to the render texture and the background color bleeds through. It looks then like this:
Mouth, bleeding transparency

Literally any other shader (lit, builtin Sprites-Default) is fine.

I tried playing around with the camera settings an such. Disabling post processing on the character camera also fixes this, but then the whole render texture is filled with black background.

Whats happening here?

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

This occurs because of this line in the default unlit sprite shader:

Blend SrcAlpha OneMinusSrcAlpha

This says to use the standard "layer" transparency function:

resultColour = outputColour * outputAlpha + backgroundColour * (1 - outputAlpha)

The trouble is, it's using this formula for both the colour channels and the alpha channel.

So blending partially-transparent red over the background will both nudge the texture colour toward red and nudge the texture alpha toward partially-transparent.

You can fix this to only accumulate alpha into the background like so:

Blend SrcAlpha OneMinusSrcAlpha, One OneMinusSrcAlpha

This ensures the resulting alpha is never less than what was in the texture already.

Copy the default unlit sprite shader and change the Blend line to use this, then make your own sprite material that uses this shader.

Note though, when you're pre-composing images to a staging texture to later render over a different background, what you really want to use is pre-multiplied alpha rendering (see "super-power #2" in that answer). Otherwise you can get some subtle fringing in the blend against the background where multiple translucent layers mingle in the pre-composed texture.

\$\endgroup\$
5
  • \$\begingroup\$ Thanks for your answer! I will try this. However I am still puzzled, why this happened after updating unity. I was using URP in the old version, too, just not the 2D renderer. The shader on the sprite hasn't been changed. \$\endgroup\$
    – Raphael
    Apr 24, 2023 at 14:19
  • \$\begingroup\$ I took a look at the post you linked, I would need to premultiply all my sprites to use a premultiply shader correct? \$\endgroup\$
    – Raphael
    Apr 30, 2023 at 20:30
  • \$\begingroup\$ No, the post shows how you can take a non-premultiplied sprite and multiply its rgb colour by its alpha value in the shader just before outputting the colour. \$\endgroup\$
    – DMGregory
    Apr 30, 2023 at 20:43
  • \$\begingroup\$ I'm still very inexperienced with this whole shader stuff and I cannot wrap my head around that other post. I tried multiplying the rgb with alpha but it just makes dark spots where the sprites overlap. Did I misunderstand where (and when) that blending should happen? \$\endgroup\$
    – Raphael
    Apr 30, 2023 at 21:20
  • \$\begingroup\$ I can't tell you that without seeing your code. Want to post a question "Help debug a pre-multiplied alpha sprite compositing shader"? \$\endgroup\$
    – DMGregory
    Apr 30, 2023 at 21:32

You must log in to answer this question.

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