컴퓨터 그래픽스에서 Opaque 오브젝트와 Transparent 오브젝트는 매우 다르게 다루어진다.
Opaque 오브젝트는 비교적 쉽다. 픽셀을 그리고.. 우리 입맛대로 색상을 출력해서 렌더링만 하면 되기 때문이다.
Transparent는 기존 컬러 버퍼에 Blending 요소가 들어간다는 점이 추가된다.
Transparent Object가 렌더링되는 방식
Opaque 오브젝트들이 렌더링이 완료된 후에, Transparent 오브젝트 렌더링을 해야하는데
Transparent 오브젝트들은 Opaque 오브젝트 앞에 있다면, 반드시 Depth Test 부터 통과해야 한다.
Opaque 오브젝트 뒤에 있다면, 그려지지 않는다.
Opaque 경우처럼, Framgent Shader에서 Depth Information을 쓰지(write) 않는다면, Transparent 오브젝트도 Early Depth Testing을 진행 할 수 있다.
Depth Test 성공 이후에는, Fragment Shader가 색상 정보를 반환하기 위해 동작할 것이다.
Transparent 오브젝트가 렌더링 될 때, 컬러 버퍼에 이미 저장된 값을 보존해야 하고, 특정 컬러와 혼합 시켜야 할 필요가 있다.
이건 이미 존재하는 색을 덮어 써버리는 기존의 Opaque 오브젝트 방식과 다른 점이다.
이 때, 컬러 혼합하는 방식을 Alpha Blending 이라고 한다.
Transparent 오브젝트는 alpha value와 연관이 깊다. 값은 0 에서 1의 값을 갖는다.
Fragment Shader의 결과물인 Color의 4번째 요소가 Alpha Component이다. 하지만, Opaque 오브젝트는 Alpha Component를 무시하기 때문에 중요하지 않다.
Alpha Blending 에서는 Fragment Shader의 Alpha Value 값은 Trnasparent 오브젝트와 컬러 버퍼에서 각각 출력 색상의 어느 비율을 가져올지 제어하는 데 사용된다.
* 비율을 Proportion이라고 표현하는 걸 보아하니 몇 대 몇 방식으로 가져오는 듯 하다.
렌더링 순서를 신경쓰기 위하여, Transparent 오브젝트들은 뒤에서 앞으로 먼저 정렬해야 한다.
렌더링 루프는 다음과 같다.
(1) 모든 Transparent 오브젝튿들을 뒤에서 앞으로 정렬한다.
- 정렬 조건은 Depth Value가 높은 오브젝트 (Camera Distance가 작을 수록) 먼저 렌더링 된다.
- 정렬은 Shader가 아닌 CPU에서 진행된다.
- 정렬은 오브젝트의 Origin Point를 기준으로 진행된다.
(2) 아직 렌더링 되지 않은 오브젝트들 중, 가장 멀리 있는 오브젝트를 선택하여 Vertex Shader를 가져온다.
(3) Early Depth Testing을 수행하고 실패한 픽실들은 버린다. 통과한 픽셀들의 Depth는 기본적으로 write하지 않는다.
(4) Alpha Value를 포함해서 얻어진 최종 컬러 값들을 Fragment Shader로 가져간다.
(5) Alpha Value를 이용해서, 오브젝트의 색상과 이미 Scene에 있는 색상을 혼합한다.
(6) 다음 Transparent 오브젝트를 선택한다.
Alpha Blending이 동작하는 방식
위에서 언급 했 듯이, Blendling이란 일종의 우리가 가져온 픽셀의 색상과 컬러 버퍼에 담겨 있는 색상의 혼합을 하는 프로세스이다.
코드를 이용해 살펴보자.
Shader "Lucid-Boundary/Transparent_Texture"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_BaseColor("Color", Color) = (1, 1, 1, 1)
}
SubShader
{
Tags
{
"RenderType"="Transparent"
"Queue" = "Transparent"
"RenderPipeline" = "UniversalPipeline"
}
Pass
{
Blend Off
Tags
{
"LightMode" = "UniversalForward"
}
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
texture2D _MainTex;
SamplerState sampler_MainTex;
CBUFFER_START(UnityPerMaterial)
float4 _MainTex_ST;
float4 _BaseColor;
CBUFFER_END
v2f vert (appdata v)
{
v2f o;
o.vertex = TransformObjectToHClip(v.vertex.xyz);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
float4 frag (v2f i) : SV_Target
{
float4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
return col * _BaseColor;
}
ENDHLSL
}
}
}
코드는 지금까지와 같은 Texture에 색상을 더하는 쉐이더이다.
렌더 타입같은 부분 외에 유일한 추가 점은 Pass 바로 아래에 Blend Off가 추가 되었다는 점이다.
쉐이더 내에서는 Default로 Blend Off 처리되어있다.
Blend Off 처리가 되어있으면, 렌더 타입이 Transparent라 렌더링 프로세스가 Transparent 시점이 되더라도
Blending이 이루어지지 않는다.
코드 내에서 반드시 Blending 옵션을 명시 해줘야 알파 블렌딩이 가능하단 이야기다.
Blend 키워드
Blend <source factor> <destination factor>
Blend 키워드는 생각보다 복잡한 형식으로 되어있다.
블렌딩 할 수 있는 채널이 생각보다 많이 있기 때문이다.
Color = (source factor * fragment RGB) + (destination factor * color buffer RGB)
| Source | fragment color 그 자체 |
| SourceFactor | 우리가 사용할 fragment color 값 |
| Detination | 렌더링 타겟 (color buffer 등) |
| DestinationFactor | color buffer value |
| One | 1 을 곱한다. |
| Zero | 0을 곱한다. |
| SrcColor | 소스 컬러의 값만큼 곱한다. |
| SrcAlpha | 소스 컬러의 알파만큼 곱한다. |
| DstColor | 데스티네이션의 값만큼 곱한다. |
| DstAlpha | 데스티네이션의 알파만큼 곱한다. |
| OneMinusSrcColor | 1 - 소스 컬러의 값만큼 곱한다. |
| OneMinusSrcAlpha | 1 - 소스 컬러의 알파값만큼 곱한다. |
| OneMinusDstColor | 1 - 데스티네이션 컬러의 값만큼 곱한다. |
| OneMinusDstAlpha | 1 - 데스티네이션 컬러의 알파값만큼 곱한다. |
그러면 우리가 원하는 키워드는 다음처럼 하면 될 것이다.
"Blend SrcAlpha OneMinusSrcAlpha"
이게 먼가 싶지만.. 수식으로 보면 좀더 편하다.
Color = (fragment alpha * fragment RGB) + ((1-framgent alpha) * color buffer RGB)
쉐이더에서 변수는 fragment alpha 값 뿐이다.
fragment alpha 값에 따라 블렌딩 정도가 달라진다.
바로 적용해보자.

Alpha Blending은 제일 기본적인 블렌딩 방식이다.
추가로 블렌딩 방식을 알아보자.
Premultiplied Blending
미리 곱해진 블렌딩이라..
기존의 블렌딩은 RGB와는 상관없이 독립적인 Alpha 값만 이용해서 블렌딩 했다.
Premultiplied Blending은 RGB값도 이용하는 방식이다.
*완전히 투명해지려면 RGB도 0,0,0이 되어야 한다.
기존 코드의 Blend를 다음 처럼 바꿔주자
Blend One OneMinusSrcAlpha
Color = (Fragment RGB) + (1 - Fragment Alpha) * ColorBufferRGB

Additive Blending
이번에는 Alpha값을 이용하지 않으며
색상만을 더할 뿐이다. Additively 하게
키워드를 이걸로 바꿔보자
Blend One One
Color = Fragment RGB + Color Buffer RGB

Multiplicative Blending
곱하며 블렌딩한다라?
Premultiplied Blending 처럼 생각 할 수 있을 것 같지만, 이 블렌딩은 Alpha값을 이용하지 않는다.
Fragment Color와 Color Buffer 값을 서로 곱한다.
tinted glass 효과를 줄 때 쓰인다.
이번에는 아래 두 키워드가 같다.
Blend DstColor Zero
Blend Zero SrcColor
Color = ColorBuffer RGB * Fragment RGB

Blend Mode Properties
Blend 키워드는 원하는 효과마다 채워놓기에는 하드코딩하는 감이 있다.
(지금 예제를 작성하면서 Shader 코드가 4개까지 늘어났다.)
좀 더 자동화 해야 할 필요가 있어보인다.
C#의 만능 동료 Enum 을 사용하면 편하게 설정을 바꿀 수 있다.
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_BaseColor("Color", Color) = (1, 1, 1, 1)
[Enum(UnityEngine.Rendering.BlendMode)]
_SrcBlend("Source Blend Factor", Int) = 1
[Enum(UnityEngine.Rendering.BlendMode)]
_DstBlend("Destination Blend Factor", Int) = 1
}
Pass
{
Blend [_SrcBlend] [_DstBlend]
...
}

이번 포스팅은 좀 편하게 쉬어가는 느낌이 강해진다..!
Blending을 Shader Graph로 만들기

그래프에서는 멀리 갈 것도 없이 Graph Setting을 살펴보자.
Surface Type을 Transparent로 하고
Blending Mode를 원하는 것으로 바꿔주면 끝이다.

마치며
이번 포스팅에서는 Transparent 와 Alpha 값을 다루어보았다.
책의 구성이 Depth Buffer에서 많이 지쳐 떨어질 것 같은데..
보상이라도 하 듯 숨쉴 수 있는 챕터인 듯
다음 포스팅은 마찬가지로 심화된 내용을 하도록 한다.
게임에서 아주 잘 쓰이는 Dissolve 내용도 포함된다.
'Game Dev > Unity Shader' 카테고리의 다른 글
| 12. Dissolve Effect 개선하기, C# 코드와 상호작용 - 다니엘 릿 쉐이더 프로젝트 (0) | 2025.10.17 |
|---|---|
| 11. Tranparancy And Alpha 심화 - 다니엘 릿 쉐이더 프로젝트 (0) | 2025.10.17 |
| 09. Depth Buffer 심화 (3) - 다니엘 릿 쉐이더 프로젝트 (0) | 2025.10.16 |
| 08. Depth Buffer 심화 (2) - 다니엘 릿 쉐이더 프로젝트 (0) | 2025.10.16 |
| 07. Depth Buffer 심화 (1) - 다니엘 릿 쉐이더 프로젝트 (0) | 2025.10.15 |