learn.ericfromkorea.com / pixel-model

게임에서 픽셀아트를 뜯어
AI에게 그리는 법 가르치기 — 개발 일지

데이터 수집부터 정제·캡션·학습·후처리까지. 무엇을 시도하고, 무엇이 실패했고, 무엇이 통했는지 — 실제 숫자와 결과로 기록한 여정

차례
  1. 큰 그림과 파이프라인
  2. ① 데이터 수집 — 게임에서 4.3만 장
  3. ② 정제 — 임계값 한 줄이 4,300장을 살리다
  4. ③ 캡션 — WD 태거의 배신, JoyCaption으로
  5. ④ 학습 — 흐림의 원인과 결정적 돌파
  6. ⑤ 후처리 — 팔레트와 외곽선
  7. 핵심 교훈 · 라이브 링크
OVERVIEW

무엇을, 어떻게

목표는 Core Keeper 같은 고품질 픽셀아트를 생성하는 AI. 그림 모델 전체가 아니라, 이미 똑똑한 Anima(2B 애니 모델)에 픽셀 화풍만 덧입히는 작은 부품(LoRA)을 학습시킨다. 트리거 키워드는 ssw.

[Steam 게임] → ① 수집·추출 → ② 정제 → ③ 캡션 → ④ Anima LoRA 학습 → ⑤ 후처리 → [픽셀아트]

이 일지는 각 단계의 실제 결과와, 막혔던 지점을 어떻게 풀었는지를 담는다.

① 데이터 수집

게임을 직접 받아서 뜯는다

고품질 픽셀아트는 잘 만든 게임 안에 수천 장씩 있다. 보유한 Steam 게임을 steamcmd로 내려받아 엔진별 도구(Unity→UnityPy, XNA→xnbcli)로 스프라이트를 추출했다.

Core Keeper레퍼런스 화풍 · 7,861장UnityPy
Terraria아이템·타일 · 12,413장xnbcli
Graveyard Keeper디테일 픽셀 · 21,130장UnityPy
Stardew Valley시트 · 944장xnbcli
Enter the Gungeon아틀라스 · 923장UnityPy
5
게임
43,271
추출 스프라이트
게임별 추출 스프라이트

↑ 게임마다 화풍이 조금씩 다르다. 텍스처 이름으로 character/item/environment 자동 분류

② 정제

임계값 한 줄이 4,300장을 살리다

4.3만 장이 다 쓸만하진 않다. 빈 조각·단색·흐릿한 효과(연기·유령)·시트를 지표로 측정해 걸러냈다 (불투명비율·연결요소·색수·소프트엣지). 시트는 가장 큰 조각 1장만.

걸러낸 비픽셀 효과물

↑ 걸러낸 '이질적' 비픽셀 — 글로우·유령·연기. 소프트엣지 비율로 자동 검출

🔍 막혔던 지점: 첫 정제에서 Core Keeper가 29%(2,288장)만 남았다. 타깃 화풍인데 71%가 사라진 것. 측정해보니 버려진 것의 불투명도 중앙값이 0.72(꽉 참) — 빈 게 아니라 트림 후 크기가 16px 미만이라 잘린 것이었다. Core Keeper 아이템 내용이 보통 10~14px라서.

최소 크기 기준을 16px → 8px로 한 줄 바꾸자, Core Keeper가 6,592장으로 회복(소형 스프라이트 +4,300).

정제 전/후 게임별

↑ 게임별 원본(회색) vs 정제 후(파랑). 전체 43,271 → 37,490 (87%)

③ 캡션

WD 태거의 배신, JoyCaption으로

처음엔 WD tagger(Danbooru 태거)로 태깅했는데, 픽셀 스프라이트가 애니 일러스트 분포 밖이라 "가장 비슷한 태그"로 오매칭했다 — 로봇팔→"sex toy", 갑옷→"1girl/pokemon" 같은 노이즈.

같은 스프라이트, 캡션 방법 비교
Item_4888 (잼단지)
WD: item (무명) → JoyCaption: jar of jam, food, fruitVLM이 실제 내용 파악
Chain24 (8px 사슬)
JoyCaption: abstract(실패) → 이름: chain너무 작아 VLM 실패 → 파일명이 보완
캡션 비교 대상 스프라이트

↑ 결론: 이름(정답 라벨) + JoyCaption(실제 내용) 결합이 최선. 서로의 약점을 메운다

최종 포맷: ssw, pixel art, simple background, <이름>, <JoyCaption 내용 태그>. 8B VLM이라 단일은 29시간 → 배치 처리로 2.4시간(0.23s/img)으로 단축.

④ 학습

흐림의 원인과 결정적 돌파

Anima에 LoRA(rank32)를 학습. 그런데 첫 1024 결과가 전부 흐릿한 블롭이었다.

흐릿한 초기 결과

↑ 문제: 인식은 되지만 선명한 픽셀이 아니다

💡 원인 두 가지: ① kohya가 16px 스프라이트를 1024로 보간(LANCZOS) 업스케일해 흐려짐. ② 투명 PNG가 RGB 변환 시 검정으로 합성돼 배경이 어두워짐. 해결: 데이터를 미리 NEAREST 정수배율로 업스케일(픽셀 그대로 확대) + 흰 배경 합성. 그리고 Anima 네이티브 해상도인 1024로 학습.
크리스프 학습 진행

↑ NEAREST+1024 후: 흐린 블롭 → 선명한 기사·상자·슬라임 (step 800→1400)

최종 결과

↑ 최종(step 3000): 게임용 픽셀 스프라이트. 트리거 ssw로 활성화

📉 곁다리 교훈: diffusion 학습 loss는 랜덤 타임스텝 MSE라 거의 평평하다 — 안 줄어도 정상. 진짜 진척은 샘플 이미지로 본다.
⑤ 후처리

팔레트와 외곽선

생성물을 게임용 스프라이트로 마무리: ①픽셀화 ②게임 팔레트 스냅(실제 Core Keeper 79만 픽셀에서 48색 추출) ③배경 제거(투명) ④어두운 외곽선(보더라인).

후처리 단계

↑ RAW → 픽셀화 → 팔레트 스냅 → 배경제거+외곽선. 체커보드 = 투명(게임 즉시 사용 가능)

정리

핵심 교훈

라이브로 보기:

📱 픽셀 에셋 갤러리 🎨 학습 대시보드

진행: 수집·정제·캡션(JoyCaption 재작업) 완료 · 통합 LoRA 학습 예정