The process of pasting RenderTexture into RawImage and incorporating it into the UI is a standard process, but when drawing soft translucent effects like smoke or objects with transparent textures like hair or glass, you often come across a bug (commonly known as fringing or black border problem) where the borders of the objects turn unnaturally dark as if they were burnt. This bug is caused by the alpha blending mechanism that is the basis of digital color compositing. In this article, we will explain the mechanism by which this bug occurs in an easy-to-understand manner using the analogy of ``double layers of colored glass,'' and present practical solutions for implementing beautiful and smooth UI expressions.
1. Understanding with an analogy: ``Black acrylic board and cellophane tape'' slip past each other
In order to intuitively understand this phenomenon, let's use the analogy of ``Layering transparent tape on a black acrylic board, cutting it out, and pasting it onto white construction paper.''
Suppose you colored a piece of transparent cellophane tape (semi-transparent effect) with a red permanent marker. Then, I attached the tape to a ``black acrylic board (clear background color for the sub camera: transparent black #00000000)'' as a pedestal for cutting the tape. At this point, since the acrylic board is black, the components of the black acrylic board (black color value) will be perfectly adsorbed and mixed with the adhesive layer and edges of the tape.
Next, try to ``peel off only the tape from this acrylic board and reattach it to clean white drawing paper (bright UI screen)''. However, when I peeled off the tape, the thin edge (semi-transparent edge) of the tape had "black adhesive stains (black pixel information)" on the acrylic board that was used as the pedestal, and was peeled off. Because this stain is attached to the white drawing paper, the transparency of the edge of the red tape increases and the thinner it becomes, the more the black stain that has stuck to it stands out, making the border line appear as a darkened edge.
This is the blackhead bug due to inconsistency in ``Premultiplied Alpha''. When the sub camera draws an object to the RenderTexture, the background is specified as transparent (Alpha=0) and cleared, but the color itself is "black (RGB=0)", so when the semi-transparent border of the object is drawn, it is blended with the "black" background and written to the RenderTexture. Then, when the UI system composites that texture onto the screen, it uses normal alpha blending, which does not assume that the background black has already been mixed into the color, so the mixed black appears on the edges.
2. Solution A: Change the clear color of the sub camera to ``transparent white''
The easiest and no-code solution is to change the color value of the ``transparent background color'' that the sub camera uses to clear the scene from black to **white (or a similar color to the background UI)**.
Setup steps:
- Open the inspector of the sub camera that is drawing to RenderTexture.
- Set the "Background Type" of the Camera component to "Solid Color".
- Open the background color palette (Background).
- Set the color code to "#FFFFFF" and the alpha channel (A value) to "0 (fully transparent)".
As a result, the color of the ``pedestal acrylic plate'' in the analogy earlier will change from black to ``transparent white.'' The color that blends into the border of a translucent object is "white," so when pasted on white drawing paper (bright UI), the color value that blends into the border is white, completely eliminating dark spots and eliminating unnatural dark edges.
3. Solution B: Apply a UI shader that supports multiplied alpha (advanced solution)
If your game's background UI is very colorful or dynamically switches between dark and light themes, just setting the clear color to white won't achieve perfect blending. In that case, assign ``Custom material that accurately blends Premultiplied Alpha'' to the RawImage that draws RenderTexture on the UI side.
The standard shader for the UI works with `Blend SrcAlpha OneMinusSrcAlpha` (regular alpha blending), but since the color is already multiplied by alpha when drawn to the RenderTexture, the UI side needs to draw with `Blend One OneMinusSrcAlpha` (multiplied alpha blending). Create a material and apply it to the RawImage's "Material" slot.
// Example of a multiplied alpha blend capable shader for UI
Shader "UI/PremultipliedAlphaRawImage"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
// ★Super important: Set blending mode to One / OneMinusSrcAlpha (multiplied support)
Cull Off
Lighting Off
ZWrite Off
ZTest [unity_GUIZTestMode]
Blend One OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
sampler2D _MainTex;
fixed4 _Color;
v2f vert(appdata_t IN)
{
v2f OUT;
OUT.vertex = UnityObjectToClipPos(IN.vertex);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color * _Color;
return OUT;
}
fixed4 frag(v2f IN) : SV_Target
{
// Sample color from RenderTexture
fixed4 color = tex2D(_MainTex, IN.texcoord) * IN.color;
return color;
}
ENDCG
}
}
}
By applying a material using this shader to a RawImage, the edge alpha blending will be mathematically correct regardless of the background color, and you can achieve an extremely sharp and beautiful 3D preview UI with no darkening on the outline.