공부용으로 작성되는 페이지입니다. 틀린 부분이나 환경에 따라 오류가 발생할 수 있습니다.
원래 디더링이 어떤 역할을 하는지, 어떤 개념인지도 같이 작성했었는데 글이 한 번 날아갔다...
개념까지 다시 정리할 힘이 없으므로 개념은 생략하고 코드 작업만 작성했다. (개념 자체는 참고자료에 잘 적혀있다)
간단히 말하자면 알파 블렌딩을 쓰지 않는다는 뜻!
코드 원문(Git Hub)
코드 원문은 참고자료에 GitHub주소를 달아두었다.
Properties
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Main Texture", 2D) = "white" {}
_DitherScale("Dither Scale", Float) = 10
[NoScaleOffset]_DitherTex ("Dither Texture", 2D) = "white" {}
}
_DitherScale과 _DitherTex로 디더링 시 패턴 스케일과 디더 패턴 텍스쳐를 받아온다.
이 때, 디더링 텍스쳐는 4x4, 8x8을 권장한다.
Tag
Tags{ "RenderType" = "Opaque" "Queue" = "Geometry" }
디더링 개념을 보고 왔다면 알겠지만 디더링은 어디까지나 유사 투명 오브젝트이므로 불투명 객체이다.
챗Gpt같은데에 물어보면 RenderType을 Opaque를 쓰면 안된다며 그럴싸한 이유를 마구마구 뱉어내지만 오답이므로 주의하길.
Pass- Setting
CGPROGRAM
#include "UnityCG.cginc"
#include "Dither Functions.cginc"
#pragma vertex vert
#pragma fragment frag
눈에 띄게 특별한 점은 Dither Functions.cginc 뿐이다. 이는 참고로 하고 있는 코드에 내장되어있는 함수 파일이다.
Dither Functions - isDithered
float isDithered(float2 pos, float alpha, sampler2D tex, float scale)
{
pos *= _ScreenParams.xy;
pos.x -= _ScreenParams.x / 2;
pos.y -= _ScreenParams.y / 2;
pos.x /= scale;
pos.y /= scale;
return alpha - tex2D(tex, pos.xy).r - 0.0001 * (1 - ceil(alpha));
}
Dither Functions - DitherClip
void ditherClip(float2 pos, float alpha, sampler2D tex, float scale)
{
clip(isDithered(pos, alpha, tex, scale));
}
이런 함수들의 도움을 받아 Color.a의 값에 따라 디더링 되는 Shader가 완성된다.
추가로 작성한 부분
흔히들 게임에서 작동하는 디더링은 플레이어와 오브젝트가 겹칠 때 발생하므로,
카메라가 오브젝트와 z축선상에서 가까워 지면 디더링이 적용되어 물체가 투명해지도록 수정해주었다.
1. _FadeDistance
디더링이 시작되는 기준이 카메라-오브젝트의 거리이므로 이를 담아줄 변수를 선언했다.
이를 위해 버텍스 구조체에는 월드 포지션 : float3 worldPos : TEXCOORD2; 을 작성해주었다.
2. Vertex Shader
버텍스 쉐이더는 worldPos 관련만 추가작성해주었다.
float4 worldPos = mul(unity_ObjectToWorld, v.vertex);
o.worldPos = worldPos.xyz;
현재 픽셀(이 경우 shader가 적용되는 객체)가 월드상에서 카메라와 얼마나 떨어져 있는지를 계산했다.
3. Fragment Shader
버텍스 쉐이더에 비해 추가된 부분이 좀 많다.
float4 col = _Color * tex2D(_MainTex, i.uv);
ditherClip(i.spos.xy / i.spos.w, col.a, _DitherTex, _DitherScale);
return col * i.col;
원문에서는 깔끔하게 _Color와 Texture를 받아와서 Ditherclip()함수로 Dithering을 넣어준 반면 나는 카메라 연산이 들어가야했다.
따라서 camera 값에 따른 Fade 효과를 적용해서 fade값에 따라 ditherClip을 적용할지 말지 결정하도록 수정했다.
float fade = saturate(dist / _FadeDistance);
//Alpha minvalue : 0
float rawAlpha = _Color.a * fade;
float4 texColor = tex2D(_MainTex, i.uv);
float4 col = _Color * texColor;
col.a = rawAlpha;
// fade < 1일 때만 ditherClip()
if (fade < 1.0)
{
ditherClip(i.spos.xy / i.spos.w, col.a, _DitherTex, _DitherScale);
}
else
{
col.a = 1.0;
}
return col * i.col;
}
결과물
위에서 레퍼런스로 가져왔던 이미지대로, 보통 디더링이 될 때 알파값이 0까지 떨어지기보다는 홀로그램처럼 보이는 경우가 많으므로 최종 결과물에서는 알파값이 최소 0.2는 남도록 수정해주었다.
참고자료
디더 투명도 셰이더를 만들어보자
직방 3D 단지투어에서는 내가 보고있는 단지의 건물을 가리는 물체들을 반투명처리를 해 줍니다. 반투명처리를 할 때알파 블렌딩(Alpha Blending)으로 처리하지않고 디더 투명도(Dither Transparency) 를
medium.com
GitHub - gkjohnson/unity-dithered-transparency-shader: Unity material and shader for applying clipped, dithered transparency
Unity material and shader for applying clipped, dithered transparency - gkjohnson/unity-dithered-transparency-shader
github.com
'Shader' 카테고리의 다른 글
[Shader] Fog with SkyBox (0) | 2025.05.08 |
---|---|
[Shader] OPaque Error with Unlit Shader (불투명 쉐이더 문제) (0) | 2025.04.25 |
[Shader] HLSL 작성 숙달을 위한 구조 파악 with Reflection Example (0) | 2025.04.24 |
[Shader] Hologram shader 제작 연습 with HLSL (0) | 2025.04.09 |