캐릭터 그림자를 만드는 법
2026.09 · 기술 노트 · 그림자
2D 게임에서 그림자는 보통 캐릭터 발밑에 검은 타원을 하나 깔고 끝냅니다. 값도 싸고 대부분은 그걸로 충분합니다.
저도 그렇게 시작했는데, 어느 날 보니 도끼를 든 캐릭터도 타원, 활을 든 캐릭터도 타원, 곰도 타원이었습니다. 크기만 달랐습니다.
실루엣을 그대로 눕히기
그래서 접지 원판 대신 캐릭터의 실제 모양을 바닥에 눕히기로 했습니다.
캐릭터는 스프라이트 스킨이라 이미 뼈대 행렬을 갖고 있습니다. 그 행렬을 GPU로 한 번 더 넘겨서, 같은 정점을 이번엔 지면 쪽으로 눕혀 그립니다. 애니메이션이 돌아가면 그림자도 같이 돌아갑니다. 팔을 들면 그림자도 팔을 듭니다.
개체마다 렌더러를 만들면 드로우콜이 캐릭터 수만큼 늘어나니까, 화면에 보이는 유닛을 모아 메시 하나로 굽습니다. 뼈대는 최대 4096개까지 한 버퍼에 담고요.


그림자가 받을 바닥이 평평하지 않습니다
여기서 문제가 생겼습니다. 이 게임의 지형은 블록 층으로 되어 있어서 바닥에 단차가 있습니다. 절벽도 있고 물도 있고요.
처음에는 그림자를 화면 평면에 그렸습니다. 그러니까 나무 그림자가 절벽 아래로 뚝 떨어져야 할 자리에서도 그냥 화면에 납작하게 붙어 있었습니다.
그래서 그림자를 화면이 아니라 높이에서 받도록 바꿨습니다. 캐스터의 높이를 태양 방향으로 투영한 자리에 기록해 두고, 지형과 수면이 각자 자기 높이로 그 기록과 비교합니다. 나보다 높은 게 있으면 그늘입니다.
수면도 같은 걸 읽습니다. 나무 그림자가 물에 비치는 게 아니라 물 위에 지는 거죠.
몬스터가 언덕 뒤에 있는데 그림자가 언덕 위에 있다
이건 제보를 받고 한참 들여다본 건인데, 결론은 버그가 아니었습니다.
몬스터 머리가 언덕 위로 솟아 있으면 그 그림자는 언덕 위에 지는 게 맞습니다. 높이를 비교해서 그리니까요. 몸통이 언덕에 가려져 있어도 머리는 안 가려졌으면 그림자가 생깁니다.
대신 일반 몬스터는 화면에서 1.4배로 키워 그리고 있어서 실루엣이 생각보다 넓습니다. 그래서 "몸이 안 보이는데 그림자만 크게 나온다"로 읽혔던 겁니다.
벽 모서리에서 나온 삼각형
벽면에 그림자가 지는 걸 켜고 나니 벽 모서리 아래에 이상한 삼각형이 생겼습니다.
원인은 필터였습니다. 그림자 경계를 부드럽게 하려고 주변을 몇 군데 더 훑는데, 그 주변 지점들의 "받는 높이"를 전부 중심점 높이로 쓰고 있었습니다. 평평한 바닥에서는 맞는 가정인데 기울어진 벽면에서는 틀립니다. 벽이 자기 자신을 어둡게 만들고 있었습니다.
지금은 주변 지점마다 벽의 가로축과 태양 방향으로 받는 높이를 각각 복원합니다.
부드럽게 만들 때 생기는 얼룩
가장 최근 이야기입니다. 그림자 가장자리가 계단처럼 각져 있어서 부드럽게 만들기로 했습니다.
표본을 4개에서 13개로 늘렸습니다. 표본 수와 부드러움이 비례하지는 않습니다.
얼룩덜룩해졌습니다.
재어 보고 나서야 알았습니다. 그림자 판정은 "가렸다 / 안 가렸다" 둘 중 하나입니다. 그러니까 13개를 평균해도 값이 열네 단계밖에 안 나옵니다. 부드러워지는 게 아니라 계단이 열네 칸이 될 뿐이고, 표본 자리가 픽셀마다 다르면 그게 얼룩으로 보입니다.
필요한 건 개수가 아니었습니다. 표본 한 번이 연속된 값을 내야 했습니다. 이웃한 네 칸의 판정 결과를 위치에 따라 섞으니 한 번에 매끄러워졌습니다.
그림자 맵 해상도는 오히려 낮췄습니다. 칸이 굵어질수록 이 방식은 저절로 더 부드러워지고, 굽는 비용도 절반 이하가 됩니다. 해상도를 올리는 게 화질을 올리는 게 아닌 경우가 있다는 걸 이때 배웠습니다.
불빛은 그림자를 하나 더 만듭니다
모닥불을 켜고 나서 든 생각인데, 불 옆에 선 나무는 그림자가 반대쪽으로 누워야 합니다.
처음엔 있던 그림자를 불빛 쪽으로 꺾었습니다. 그랬더니 해가 멀쩡히 떠 있는 대낮에 모닥불 하나가 태양을 이기고 있었습니다.
그림자는 꺾는 게 아니라 하나 더 생기는 겁니다. 지금은 같은 물체를 두 번 굽습니다. 한 번은 태양, 한 번은 불빛. 태양 그림자는 제자리에 있고 불빛 그림자가 한 장 더 깔립니다. 밤일수록 세게 들어가서, 낮에는 태양이 이깁니다.
전투 중에 검을 휘두를 때 나오는 섬광은 그림자에서 뺐습니다. 0.2초짜리 광원이라 한 대 칠 때마다 온 동네 그림자가 경련을 일으켰습니다.

정리하면
그림자 하나에 이만큼 붙어 있습니다. 실루엣 투영, 높이 기반 수광, 벽면 필터, 이중선형 PCF, 광원별 추가 그림자.
플레이하면서 이걸 의식하는 사람은 아마 없을 겁니다. 그게 맞고요. 다만 타원 하나였을 때와 지금을 나란히 놓고 보면 확실히 다릅니다.