
언리얼에서 카툰 쉐이딩을 구현해보도록 하자.
핵심은 람베르트 코사인 법칙을 조금 변형한 하프 람베르트 + 밴드 쉐이딩이다.
우선 람베르트 코사인 법칙이 무엇인지 부터 보도록하자.
람베르트 코사인 법칙이란?
표면의 법선 벡터(N)와 광원 방향 벡터(L) 사이의 각도에 따라 반사되는 빛의 세기를 계산하는 원리이다.

빛의 방향을 빨간 선이라고 했을때 이 빨간 선을 뒤집은 것과 표면에 수직인 법선 벡터의 cos값을 구하는 것은 정규화된 두 벡트를 내적한 것과 동일하다.
내적은 ||a|| * ||b|| * cos(setha)이기 때문에 크기가 1이라면 cos(setha)를 구하는 것인 내적과 동일하다.
때문에 빛의 방향과 법선 벡터가 동일하다면 그 값은 1이고 90도를 이룰 수록 값은 0에 가까워진다.
때문에 90도를 이룰 수록 점점 색이 어두워지다가 반대편 부터는 갑자기 검은색으로 칠해지는 것이다.
이를 보완하고자 등장한 것이 하프 람베르트 법칙이다.

빛의 방향을 뒤집은 것과 90도를 이루더라도 완전히 다 어두워지지 않게 렘버트 모델에서 0.5를 곱해서 압축시킨다.
그럼 최대값이 1인 부분이 0.5가 되고 최소값인 -1이 -0.5가 된다. 이 다음에 여기 0.5더해주게 되면 모든 값은 0~1사이의 값을 가지게 된다.
이를 응용한 카툰 쉐이딩을 이제 알아 보도록 하자.
카툰 쉐이딩이란?

람베르트나 하프 람베르트는 특정 영역을 기준으로 서서히 명암이 지는데 카툰 렌더링은 특정 영역 기준으로 명암이 확확 지는 것을 볼 수 있다.
이것을 구현하기 위해서는 전체 영역을 나누고 이 나누어진 값들을 하나의 값을 가지도록 뭉쳐주어야한다.
이때 사용되는 것이 올림함수이다.
float3 N = normalize(Normal);
float3 L = normalize(Light);
// 1) N·L 구하기 (-1 ~ 1)
float NdotL = dot(N, L);
// 2) Half-Lambert 적용 (-1~1 → 0~1)
float halfLambert = NdotL * 0.5 + 0.5;
halfLambert = saturate(halfLambert);
// 3) Toon 단계 수
float Steps = 4;
// 4) 계단형 툰 셰이딩
float Toon = floor(halfLambert * Steps) / Steps;
// 5) (선택) 최소 밝기 깔기 – 너무 까매지 않게
float MinBrightness = 0.2;
Toon = max(Toon, MinBrightness);
return Toon;
코드는 위와 같이 간단하게 만들 수 있다.
본인은 하르 람베르트를 적용해서 완전히 까맣게 나오는 부분을 예방하고자 이를 사용했다.
빛이 들어오는 빛의 방향벡터와 법선 벡터를 내적하여 해당 수치를 Steps라는 것으로 단계적으로 나누었다.
이때 올림함수에 floor가 사용되었음을 알아두도록 하자.
이를 언리얼에서 구현할 수 있는데 크게 어려운 부분은 없다.

기존 색상에 툰 렌더링을 적용하고 싶다면 본인 처럼 return값에 기존의 color값을 곱하여 BaseColor로 설정해주면 음영이 단계적으로 생기게 된다.
참고
https://www.youtube.com/watch?v=6qCYaGne8H8
'컴퓨터 그래픽스' 카테고리의 다른 글
| 빌보드 기법 (1) | 2025.08.27 |
|---|---|
| 원근 투영 변환 행렬과 투영 변환 행렬의 의미 (수정) (0) | 2024.08.05 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!