연재

앱인토스 입점 후기 2. Blender MCP와 3D 에셋

TL;DR

  • Blender MCP는 모델을 만드는 조작 비용을 줄여줬지만, 결과물의 합격 기준까지 만들어주지는 않았다.
  • 왁뿌볼 에셋은 정지 화면이 아니라 런타임 셰이더에서 깨지고 눌리는 재료다.
  • 뷰포트에서 좋아 보이는 모델도 앱 안에서는 너무 빨리 깨지거나, 눌림이 뭉치거나, 음영 줄무늬가 생길 수 있다.
  • 검수 기준은 실루엣, 크기 비율, 삼각형 밀도, displacement 진폭, 앱 안에서의 반복 횟수까지 포함해야 했다.

왁뿌볼 뿌수기의 중심에는 3D 볼 하나가 있다. 화면을 누르면 왁스층이 버티다가 깨지고, 안쪽의 흰 속살이 드러난다. 이 효과는 단순한 3D 모델 하나로 끝나지 않는다. 앱은 런타임에서 여러 텍스처와 셰이더 값을 합성한다.

single mesh
  + intact basecolor / roughness / normal
  + cracked basecolor
  + crack field
  + crack displacement
  + shader uniforms

Blender를 직접 다루지 못하는 상태였기 때문에 Claude Code와 Blender MCP를 연결했다. 기대한 역할은 분명했다. 모델링 조작은 AI에게 맡기고, 나는 앱에 넣을 수 있는지만 검수한다. 실제로 어려웠던 쪽은 후자였다.

Blender MCP의 역할

사용한 도구는 ahujasid/blender-mcp다. Claude Code가 bpy 코드를 만들고, MCP 서버가 그 코드를 Blender 애드온에 전달하는 구조다.

Claude Code
  -> MCP server
  -> Blender addon
  -> bpy 실행
  -> viewport screenshot / exported asset

이 흐름으로 청사과 왁뿌볼 모델을 만들었다. 흰 실리콘 속, 초록 왁스 껍질, 투명 막, 매듭 같은 요소를 프롬프트로 요구하고, 텍스처를 같은 UV 위에 구운 뒤 GLB로 내보냈다. 문제는 MCP가 보여주는 피드백이 대부분 정지한 뷰포트라는 점이다. 앱에서 필요한 것은 정지 화면의 형태가 아니라 누를 때의 반응이다.

Blender viewport
  -> 형태, 색, 머티리얼 확인

App runtime
  -> hold progress
  -> dent
  -> crack mask
  -> displacement
  -> 완파 판정

뷰포트에서 통과한 모델도 앱에 넣으면 실패할 수 있다.

검수 기준 1. 형태 비율

청사과 이후 볼 종류를 늘리면서 길쭉한 과일 형태를 시도했다. 뷰포트에서는 형태가 좋아 보였지만, 앱에서는 두세 번 누르면 바로 완파됐다. 왁뿌볼의 완파 판정은 표면 커버리지에 묶여 있다. 얇은 축이 너무 작으면 한 번의 크랙이 단면을 넓게 덮고, 몇 번 누르지 않아도 커버리지가 급격히 찬다. 그래서 형태 기준을 숫자로 만들었다.

기준 이유
최소 축은 최대 축의 일정 비율 이상 얇은 단면에서 크랙이 과도하게 번지는 문제 방지
최소 축 절대값 하한 화면에서 너무 작은 피킹 영역 방지
구형에서 벗어날수록 앱 안에서 완파 횟수 확인 실루엣만으로 플레이 감각을 판단할 수 없음

뷰포트에서 “예쁜 모델”과 앱 안에서 “여러 번 눌러도 재미있는 모델”은 다르다.

검수 기준 2. 삼각형 밀도

납작한 막대 형태의 볼에서는 다른 문제가 나왔다. 표면은 매끈해 보였지만 앱에서 누르면 눌린 자국이 뭉쳤다. 왁뿌볼의 눌림은 셰이더가 정점을 밀어서 만든다. 정점이 성긴 영역에서는 부드러운 dent가 나오기 어렵다. 전체 정점 수만 보면 부족하지 않았다. 문제는 분포였다. bevel 영역에 삼각형이 몰리고, 넓은 평면부는 큰 삼각형으로 남아 있었다. 검수 기준은 정점 수에서 삼각형 면적 분포로 바뀌었다.

나쁜 기준
  -> vertices count

더 나은 기준
  -> triangle area max / median
  -> surface section별 triangle density

해결은 Voxel Remesh였다. 목표 정점 수와 표면적을 기준으로 voxel size를 잡고, adaptivity를 낮춰 삼각형 크기를 균일하게 만들었다.

voxel_size ~= sqrt(surface_area / target_vertices)
adaptivity = 0

리메쉬 이후에는 UV를 다시 만들어야 한다. geometry를 다시 짜면 기존 UV와 baked texture는 더 이상 같은 표면을 가리키지 않는다.

검수 기준 3. displacement 진폭

crack displacement는 조각이 깨질 때 얼마나 어긋나는지를 만든다. 구형 볼에서는 일정 진폭이 자연스러웠지만, 평면이 넓은 볼에서는 같은 값이 사선 줄무늬를 만들었다. 이 문제는 삼각형이 찢어지는 버그와 다르다. 지오메트리가 크게 뒤집히지 않아도, 평면에서는 리메쉬 격자 자체가 음영으로 드러날 수 있다. 그래서 displacement 진폭은 공통 상수 하나로 두기 어려웠다.

형태 진폭 기준
구형 과일 비교적 큰 displacement 허용
도넛형 곡률과 구멍 주변 변형을 고려해 낮춤
평면이 넓은 형태 음영 줄무늬가 보이지 않는 상한으로 제한

진폭을 정할 때는 삼각형 뒤집힘만 보면 부족하다. 실제 렌더에서 표면 음영이 어떻게 보이는지도 함께 봐야 한다.

검수 기준 4. 앱 안에서의 반복성

왁뿌볼 에셋의 합격 기준은 모델 파일 안에만 있지 않다. 몇 번 누르면 깨지는지도 에셋 품질의 일부다.

model scale
  -> pointer picking 감각
  -> crack radius의 상대 크기
  -> coverage 증가 속도
  -> 완파까지 걸리는 횟수

너무 빨리 깨지면 반복할 이유가 줄어든다. 너무 오래 버티면 짧게 즐기는 앱인토스 환경과 맞지 않는다. 따라서 모델은 앱 안에서 실제로 눌러봐야 한다. 뷰포트, 정적 스크린샷, geometry 통계가 모두 좋아도 마지막 기준은 앱 안에서의 조작이다.

기준표

새 볼을 만들 때 보는 기준은 이렇게 정리됐다.

층위 기준 실패 예
형태 최소 축 / 최대 축 비율 너무 빨리 완파
mesh 삼각형 면적 분포 눌림 자국 뭉침
UV/texture 같은 UV 위의 texture set crack과 속살 위치 불일치
displacement 형태별 진폭 상한 평면 줄무늬, 과한 벌어짐
runtime 앱 안에서 완파 횟수 반복성 부족
visual 실제 렌더 화면 숫자가 세지 않는 음영 문제

이 표는 처음부터 있었던 설계 문서가 아니다. 실패한 모델을 하나씩 통과시키면서 생긴 체크리스트다.

Blender MCP의 실제 가치

Blender MCP가 줄여준 것은 조작 비용이다.

메뉴를 찾는다
노드를 연결한다
텍스처를 굽는다
GLB를 export한다

이런 손작업은 Claude Code와 Blender MCP 조합으로 빠르게 넘길 수 있었다. 반대로 줄어들지 않은 일도 있었다.

이 모델이 앱에서 실패하는 조건을 정의한다
실패를 재는 지표를 만든다
지표와 화면을 교차 확인한다
통과 기준을 다음 프롬프트에 반영한다

AI가 만들어준 결과물을 그대로 쓰는 구조가 아니다. 생성 루프 바깥에 검수 기준이 있어야 한다. 기준이 없으면 프롬프트는 “더 예쁘게”, “더 자연스럽게” 같은 말로 흐르고, 앱에서 실제로 깨지는 문제는 계속 남는다.

정리

Blender MCP는 Blender를 다루지 못하는 상태에서도 3D 에셋 제작을 시작할 수 있게 해줬다. 하지만 앱에 들어갈 수 있는 에셋인지 판단하는 기준은 별도로 만들어야 했다. 왁뿌볼 에셋 검수에서 중요했던 기준은 네 가지였다.

  1. 정지 화면의 실루엣보다 앱 안에서의 완파 횟수.
  2. 전체 정점 수보다 표면별 삼각형 밀도.
  3. 공통 displacement 상수보다 형태별 진폭 상한.
  4. 단일 지표보다 렌더 화면과의 교차 확인.

AI가 도구 조작을 대신할수록 개발자가 더 명확히 가져가야 하는 일은 합격과 탈락의 기준이다. 이 기준이 있어야 생성된 에셋을 앱의 인터랙션 안으로 가져올 수 있다.

관련 글