본문 바로가기
공부

VRM과 Duplicated bone 이슈에 대한 고찰

by Myong_ 2025. 5. 16.

 

??? : VRM 미친거 또 터졌네

 

 

 요약 = 본 삭제 시 인덱스 동기화 필수

 

 

Unity로 버추얼 캐릭터를 만들다 보면 언젠가는 만나게 되는 적.

바로 VRM 익스포트 시의 "Duplicated Bone" 오류다.

 

나도 처음엔 대충 이름 바꿔보거나, 본 하나 하나 삭제할 때 마다 오류 뜨는지 안뜨는지 체크 해보면서 넘기려 했는데...

이게 한번 잘못 엮이면 답이 없다.

 

특히 삭제한 메쉬의 본을 정리 하다가 이슈가 터지는 경우가 많다.

그냥 이유 없이 VRM이 나 기분이 안좋아.. 하고 터지는 경우도 있어서 더 얼척이 없는 오류..

 

아플라님이랑 이거 대체 어떻게 해결해야 하는가를 한참 머리 싸매고

VRM Avatar를 아예 뜯어서 index 수동 매칭도 해봤는데...

수동으로 매칭하면 너무 오래걸리고 완벽한 방법도 아니라서 이걸 어떻게 해야할지 한참 고민하다가 결국.. "내가 해냄"

 


 

 

1. 오류 메시지 정체: Duplicated Bone Error

눈 마주치면 VRM이 죽는 짤

 

제발요 제가 이렇게 싹싹 빌잖아요 제발 VRM좀 뽑게 해주세요

 

 

VRM을 뽑거나, VSF를 뽑았는데 VRM 메타가 없어 뿌엥! 하고 애가 터져버렸을 때

원인을 찾고찾다가 이 녀석들과 마주하게 되면 너무 속상해서 울고 싶어진다..

처음에는 이게 대체 왜 이럴까 한참을 고민했었는데 하도 많이 겪다 보니까 케이스가 좁혀졌다.

 

보통 다음과 같은 조건에서 터진다:

  • 제로 웨이트 버텍스를 삭제했다
  • 안 쓰이는 본을 제거했다
  • Unity 상에서 본 리스트를 수동 정리했다
  • SkinnedMeshRenderer 내부 구조를 자동화 코드로 정리했다

VRM 익스포터는 Mesh와 Avatar 간의 본 정보가 일치하지 않으면, 이를 탐지하고 에러를 낸다.

 


 

2. VRM의 본 구조는 왜 이렇게 민감한가?

Unity에서 SkinnedMeshRenderer는 다음 세 가지 정보를 기반으로 작동한다:

bones[] 본 Transform 배열 (렌더러가 참조함)
bindposes[] 각 본의 바인드 포즈 행렬 (Mesh에 포함)
boneWeights[] 각 버텍스가 어떤 본에 영향을 받는지 정의

 

이 세 가지는 인덱스 기준으로 완벽하게 정렬돼 있어야 하며, 하나라도 틀어지면 Mesh가 깨지거나 오류가 발생한다.

 

 

VRM의 경우 여기에 Avatar 구조까지 포함된다.

즉, 익스포터는 다음을 조건을 만족해야만 정상적으로 VRM을 출력한다:

  • SkinnedMeshRenderer.bones[]에 있는 본들이 Avatar에도 있어야 함
  • 해당 본들이 bindposes[], boneWeights[]에서 정확히 매핑되어야 함

이렇게 매핑이 깨지면 "Duplicated Bone" 혹은 "Index Out of Range" 같은 문제가 발생한다.


 

3. 문제가 발생하는 일반적인 시나리오

A. 제로 웨이트 버텍스 삭제 후 본 삭제

  1. Zero-weight 버텍스들을 자동화 스크립트로 제거
  2. 영향 받지 않는 본도 함께 bones[]에서 제거함
  3. 하지만 일부 boneWeights 또는 bindposes는 여전히 해당 본을 참조함
  4. VRM 익스포터는 이 상태를 "본 중복" 또는 "불일치"로 판단함

B. Avatar에는 있지만 Mesh에는 없는 본 삭제

  1. Avatar 구조 상엔 필요하지만 Mesh엔 쓰이지 않는 본이 존재
  2. 정리 목적으로 해당 본을 제거
  3. 익스포터에서 "필수 본이 없다"는 오류가 발생

C. 동일 본 이름으로 중복 트랜스폼 생성

  1. 자동화 또는 수동 조작으로 동일 이름의 본이 둘 이상 생성됨
  2. Transform.name은 같지만 Transform 자체는 다름
  3. 익스포터는 중복 본으로 인식하여 실패함

 

4. VRM 익스포터는 정확히 무엇을 검사하는가?

VRM 익스포터는 다음 항목들을 체크한다:

  • Avatar 구조 상의 Humanoid 본 트리 정합성
  • SkinnedMeshRenderer.bones[]의 본이 실제 메시에 매핑되는지 여부
  • 각 본의 인덱스가 bindposes[]boneWeights[]에서 일치하는지
  • 중복된 이름 혹은 오브젝트가 혼재되지 않는지

이 중 하나라도 어긋나면 VRM 익스포트가 실패한다.


5. 실전 해결 전략

본을 제거할 경우, 반드시 다음 3개를 함께 정리해야 한다:

  • SkinnedMeshRenderer.bones[]
  • Mesh.bindposes[]
  • Mesh.boneWeights[]

Unity에서는 해당 본 인덱스가 참조되는 버텍스가 없어야만 안전하게 삭제 가능하다.

 

5-1. Zero Weight Bone 제거

SkinnedMeshRenderer에 설정된 모든 본에 대해:

  • 해당 본이 실제 어떤 버텍스에도 영향을 주지 않는 경우 (weight가 0인 경우)
  • SkinnedMeshRenderer.bones 배열에서 제거
  • 동시에 Mesh.bindposes, Mesh.boneWeights를 안전하게 재정렬하여 인덱스 오류 방지

5-2. Duplicated Bone 제거

  • SkinnedMeshRenderer.bones 배열에서 중복된 Transform을 제거
  • 해당 Transform이 사용된 boneWeight 인덱스를 안전하게 치환 (리매핑)

5-3. 본 재매핑 처리

  • 기존 boneWeights 정보를 기반으로 새로운 bone 인덱스 매핑 딕셔너리를 생성
  • bindpose 배열, bones 배열, boneWeight 배열을 모두 동일한 기준으로 정렬/재정렬
  • 내부적으로 Mesh를 복제하고 새 bone 정보로 갱신

 

 

어찌저찌 원인을 알았으니 자동화 코드를 짰다.

요 건은 일단 디스코드에서만 배포하고 있는데 필요한 사람이 뭐 더 많은지를 모르겠어서..

Booth 운영을 일시적으로 놓은 상태기도 하고 밀린 배포물이 너무 많아서 언제 올릴지는 모르겠음..

원리 올려놨으니까 필요한 사람은 긁어다가 GPT 돌리기라도 해서 코드 만들겠지...?

 

VRM 뽑히는 것 까지 확인 완료했으니🥺

우리 함께 고통을 덜어내요...

 

 

댓글