Voice Quest 게임 개발

Voice Quest 개발 연대기 #11 — 누구에게 하는 말인지, 캐릭터가 눈으로 답한다 (08.07~08.09)

Kenneth Kang · 공유 · 2026.08.09

해커톤 마감(8/10)을 하루 앞두고 쓰는 기록입니다. 지난 연대기 #10 이후 사흘 동안 있었던 일을 정리했습니다.

1. 화면이 "게임처럼" 보이기 시작했습니다

X에서 Opus 5로 만들었다는 3D 포켓몬 데모를 보고 충격을 받았습니다. 집과 숲의 디테일이 확연히 달랐거든요. 무엇이 다른지 뜯어보니 모델링 실력의 차이가 아니라 렌더링 파이프라인의 차이였습니다.

그래서 후처리 합성기를 넣었습니다. 블룸 → 비네트 → 필름 그레인 → 감마 보정 → SMAA 순서입니다. 여기서 하루를 태운 함정이 하나 있었는데, 감마 보정 패스를 빼면 화면 전체가 어두워집니다. 합성기는 선형 색공간 렌더 타깃에 그리는데 마지막 ShaderPass에는 인코딩 청크가 없어서, 직접 감마를 되돌려주지 않으면 그대로 어두운 화면이 나옵니다.

텍스처도 이미지 파일을 쓰지 않고 코드로 굽습니다. 주기적 값 노이즈로 fBm 높이맵을 만들고, 같은 높이맵에서 소벨 필터로 노멀맵까지 함께 뽑습니다. 격자를 주기로 감싸서 이음매 없이 타일링됩니다. 에셋이 0바이트인데 땅에 요철이 생겼습니다.

색 관리도 다시 잡았습니다. sRGB 출력 인코딩과 ACES 톤매핑을 켰더니 흰색이 다 날아가더군요. 코드에 적어둔 헥스 색상은 sRGB 기준으로 고른 값이라, 머티리얼 생성 시점에 선형으로 변환해주지 않으면 전부 빛바랜 색이 됩니다.

2. 로컬 모델을 Gemma로 갈아탔습니다

Qwen3에서 gemma-4-26b-a4b-it-qat로 바꿨습니다. 바꾸면서 배운 것이 있는데, /no_think 같은 프롬프트 접미사는 모델마다 다릅니다. Qwen3 전용 문법이라 Gemma에 붙이면 그냥 프롬프트를 오염시킬 뿐입니다. 그래서 모델 id를 보고 조건부로 붙이도록 고쳤습니다.

Gemma는 대신 마크다운 굵게 표시를 자주 뱉어서, 응답 정제 단계에서 별표를 걷어냅니다. 지연시간은 서버 쪽에서 재보니 1.2~2.1초입니다. 무협 말투 한 문장 답하기에는 충분합니다.

3. "누구에게 하는 말인가" — 추론을 포기했습니다

이게 이번 연대기에서 제일 오래 고민한 부분입니다.

멀티플레이라 옆에 사람이 있는데, "오늘 사냥 같이 가실래요?"라고 말하면 이게 옆 사람에게 하는 말인지 내 AI 동행에게 하는 말인지 알 수가 없습니다. 실제로 이 문장이 사냥 명령으로 실행돼버리는 버그도 있었습니다.

닉네임 호명, 거리 판정, AI로 의도 분류까지 검토했는데 어떤 규칙을 세워도 계속 애매한 문장이 나왔습니다. 결론은 사용자가 직접 고르게 하는 것이 100% 정확하다였습니다.

  • 🎤 (기존 마이크) — 📢 필드, 옆 사람들에게. 토글 방식입니다. 사람과의 대화는 길어서 계속 누르고 있기 불편하거든요.
  • 💬 (신규) — 💬 동행, 내 캐릭터에게만. 누르고 있는 동안만 듣습니다. 명령은 짧아서 이 방식이 맞고, 덤으로 인식 정확도도 오릅니다.
  • ⌨️ 키보드 — 열면 지금 대상이 칩으로 보이고 탭으로 바꿉니다.

여기서 한 번 걸려 넘어진 것이 있습니다. 처음에는 버튼을 뗄 때 대상을 원래대로 되돌리게 짰는데, 음성 인식 결과는 stop() 이후에 도착합니다. 되돌려버리면 방금 말한 내용이 엉뚱한 대상으로 갑니다. 그래서 뗄 때는 건드리지 않고, 다음 발화 때 어느 버튼이든 누르는 순간 다시 정하도록 했습니다.

세션이 시작될 때는 항상 '필드'입니다. 저장해두면 어제 골라둔 '동행'인 줄 모르고 남에게 할 말을 혼잣말로 보내게 되니까요.

4. 그리고 캐릭터가 저를 봅니다

말은 거는데 캐릭터가 등을 돌리고 있으면 "동행에게 말한다"는 느낌이 전혀 나지 않았습니다. 그래서 💬를 누르는 순간부터 캐릭터가 몸을 돌려 저를 봅니다.

구간지속
누르고 있는 동안뗄 때까지
뗀 뒤3초 (인식 결과가 도착할 때까지)
동행이 대답할 때말풍선과 같은 길이

구현하면서 재밌었던 지점은, 이게 이 게임의 시그니처인 갸웃 제스처와 정확히 같은 기법이라는 것이었습니다. 인식에 실패하면 캐릭터가 뒤돌아 고개를 갸웃하는 연출인데, 그때 쓰는 핵심 트릭이 카메라 각도를 고정하는 것입니다. 고정하지 않으면 카메라가 캐릭터를 따라 돌아서 영영 마주 볼 수가 없거든요.

같은 트릭을 대화에도 썼습니다. 우선순위는 갸웃이 위이고, 걷기 시작하면 즉시 풀립니다. 이동 방향 회전과 다투면 캐릭터가 떨리니까요.

남은 것

내일이 마감이라 이제 리허설입니다. 5분짜리 데모 시나리오는 6장면으로 정리해뒀고, 각 장면마다 "무엇을 말할 것인가"까지 적어놨습니다.

제출 후에는 방치형 RPG를 붙여보려 합니다. 명령해두면 알아서 사냥하고 집을 꾸미는 구조인데, 지금은 은자·처치 수·집이 전부 세션 안에서만 살아 있어서 영속화가 선행 과제입니다. 배경 탭에서는 렌더 루프가 멈추니 오프라인 보상은 시간 차 계산식으로 줘야 하고, 지금 경제로는 분당 60100은자가 벌려서 100은자짜리 오두막이 12분이면 지어집니다. 밸런스부터 다시 잡아야겠습니다.

다음 기록은 해커톤 결과와 함께 남기겠습니다.

#VoiceQuest#음성인식#해커톤#LLM#three.js
은하계에서 보기나도 은하계 만들기