FBX 텍스처가 안 보일 때 33장을 다시 연결한 순서

Character_0726.fbx를 처음 불러왔을 때 메시와 뼈대는 멀쩡했지만 텍스처 33장이 하나도 붙지 않아 옷과 머리카락이 단색으로 나왔습니다. 형태가 아니라 재질이 가리키는 이미지 파일을 로더가 찾지 못한 상태였습니다. 이런 증상은 이미지가 FBX 안에 들어 있는지 밖에 있는지부터 확인하고, 밖에 있다면 파일 이름과 형식을 보고, 마지막으로 재질 이름과 파일 이름이 서로 맞는지 대조하는 순서로 점검합니다.

시험 모델 Character_0726은 3ds Max에서 리깅한 바이너리 FBX로 크기는 2.4MB, 메시 6개에 정점 87,210개, 삼각형 29,070개입니다. 텍스처는 파일 안이 아니라 모델 옆 폴더에 이미지 33장으로 따로 놓여 있었습니다.

같은 Character_0726 모델의 좌우 비교. 왼쪽은 텍스처 없이 열어 재킷이 보라, 머리카락이 분홍, 손과 신발이 초록이고, 오른쪽은 텍스처 33장을 함께 넣어 남색 재킷, 갈색 머리, 흰 운동화로 보인다
같은 Character_0726을 텍스처 없이 연 모습(왼쪽)과 모델 옆 폴더의 이미지 33장을 함께 넣은 모습(오른쪽). 왼쪽의 보라·분홍·초록은 원래 옷 색과 관계가 없습니다.

형태는 그대로이고 표면 이미지만 빠진 상태입니다

three.js의 FBXLoader(이 사이트의 변환기는 r160을 씁니다)는 재질을 만들 때 두 가지를 따로 읽습니다. 하나는 재질 노드에 숫자로 적힌 확산색(Diffuse) 값이고, 다른 하나는 그 재질의 DiffuseColor 자리에 연결된 텍스처입니다. 메시와 뼈대는 이와 별개라서 이미지가 빠져도 형태는 남고 무늬만 사라집니다.

이미지가 빠진 재질의 색은 재질에 적힌 색 값과 도구의 처리에 따라 달라집니다. 예를 들어 three.js 렌더러는 이미지가 아직 없는 텍스처 자리에 값이 모두 0인 1×1 빈 텍스처를 대신 묶으므로, 텍스처는 연결됐는데 이미지를 못 불러온 재질은 검게 보일 수 있습니다. 어느 경우든 그 색으로 원래 옷 색을 짐작할 수는 없습니다.

위 비교 이미지의 왼쪽은 텍스처 없이 연 Character_0726으로 재킷이 보라, 손과 신발이 초록입니다. 이미지 33장을 넣은 오른쪽은 남색 재킷에 흰 운동화입니다. 이런 증상이면 모델링이나 리깅보다 이미지 연결부터 의심하면 됩니다.

FBX가 이미지를 담는 두 방식: 참조와 내장

FBX는 이미지 파일의 경로만 적어 두는 참조 방식과, 이미지 데이터를 파일 안에 통째로 넣는 내장 방식 중 하나로 텍스처를 다룹니다. Autodesk의 3ds Max FBX 플러그인 도움말에 따르면 내보내기 옵션 Embed Media를 켜면 텍스처 같은 관련 미디어가 FBX 안에 포함되고, 이런 파일을 가져올 때는 FBX와 같은 위치의 파일이름.fbm 폴더로 미디어가 복사됩니다. 도움말은 이 옵션이 파일 크기를 키우므로 받는 쪽이 원본 미디어에 접근할 수 없을 때만 쓰라고 권합니다. 옵션을 끄면 플러그인은 내보내는 순간의 상대 경로와 절대 경로를 기록하고, 나중에 그 경로에 접근할 수 없으면 문제가 생긴다고 적혀 있습니다.

Blender의 FBX 내보내기에서는 Path Mode가 같은 문제를 다룹니다. Blender 매뉴얼(2.80)은 절대경로가 만든 사람의 시스템에서만 맞을 수 있다고 설명하고, Strip Path를 고르면 경로 없이 파일 이름만 적습니다. 이미지를 파일 안에 넣는 Embed Textures는 Blender 3.1 API 문서에 Copy 경로 모드에서만 동작한다고 적혀 있습니다.

FBXLoader 쪽에서 보면 차이가 더 단순합니다. FBX의 이미지(Video) 노드에 실제 이미지 데이터(Content)가 들어 있으면 로더는 그 데이터로 바이너리 FBX에서는 blob 주소를, ASCII FBX에서는 data 주소를 만들어 바로 씁니다. 데이터가 없으면 기록된 경로에서 역슬래시(\) 뒤의 파일 이름만 남기고, FBX가 있는 위치를 기준으로 그 이름의 이미지를 따로 불러옵니다. Character_0726은 이미지 33장이 모두 FBX 밖에 있는 참조 방식 파일이었습니다.

텍스처가 빠지는 대표 원인 네 가지

1. 파일이 만든 사람의 컴퓨터에만 있다

Character_0726은 눈 재질에 eye_hazel_d.tga, eye_bm.tga, eye_a.tga 세 파일을 참조하는데, 경로가 D:\ref\Marmoset\RealtimeEye\...로 시작하는 절대경로였습니다. 원본 캐릭터팩 제작자의 D 드라이브에 있던 파일이라 모델 옆 33장에도 없었습니다. 앞에서 본 대로 FBXLoader는 폴더 경로를 버리고 파일 이름으로 찾기 때문에, 경로를 고쳐도 그 이름의 파일이 없으면 소용이 없습니다. 변환기에서는 대신 Eyes_Black.tga가 눈 재질에 붙습니다.

2. 브라우저는 폴더를 뒤질 수 없다

데스크톱 프로그램은 FBX 옆 폴더를 직접 찾아볼 수 있지만 웹 페이지는 그렇지 않습니다. MDN의 File API 문서가 설명하는 방법도 사용자가 파일 선택 창이나 끌어다 놓기로 고른 파일을 읽는 것입니다. 그래서 FBX 한 개만 넣으면 텍스처는 비어 있고, 이미지 파일을 함께 넣어야 연결됩니다. 이 사이트의 FBX → VRM 변환기는 넣은 파일을 서버로 올리지 않습니다.

3. 브라우저가 기본으로 못 읽는 이미지 형식

Character_0726의 33장에는 Eyes_Black.tga, teeth_teeth_Height.tga 같은 TGA 파일이 섞여 있습니다. MDN의 웹 이미지 형식 안내에는 웹에서 흔히 쓰는 형식으로 PNG, JPEG, WebP, GIF, BMP 등이 올라 있고 TGA는 없습니다. r160 FBXLoader는 확장자가 tga인 텍스처를 만나면 LoadingManager에 등록된 TGA 전용 로더를 찾고, 없으면 경고를 남긴 뒤 이미지가 없는 빈 텍스처를 만들어 둡니다. three.js 문서가 manager.addHandler( /\.tga$/i, new TGALoader() )를 예시로 드는 것도 이 때문입니다. DDS도 같은 방식이고, PSD는 지원하지 않는다는 경고와 함께 빈 텍스처가 됩니다.

이 사이트의 3D 모델 뷰어는 이미지로 png, jpg, jpeg, webp, bmp, gif만 받아 .tga를 고를 수 없으니, TGA 텍스처가 딸린 FBX는 변환기에서 연결하는 편이 빠릅니다.

4. 텍스처 노드가 연결 표에서 빠져 있다

FBX는 오브젝트 목록과, 무엇이 무엇에 붙는지 적은 연결 표를 따로 둡니다. 텍스처 노드가 연결 표에 없으면 증상이 색이 아니라 오류로 나타납니다. 2026년 9월 모캡 FBX(S1_t01, S244_t01)는 three.js r160 FBXLoader에서 “Cannot read properties of undefined (reading ‘children’)”로 멈췄고, 원인은 이름 없이 숫자 ID만 있는 텍스처 노드 하나였습니다. FBXLoader의 텍스처 불러오기 함수가 첫머리에서 연결 정보의 children을 읽기 때문에, 연결 표에 없는 노드면 바로 이 오류가 납니다. 이 한 줄만 너그럽게 처리하도록 고치자 정상 로드됐습니다. ASCII로 내보낸 cha_0710_01.fbx는 이런 노드가 5개였고, 그걸 넘겨도 스켈레톤 단계에서 실패했습니다. 원인을 ASCII 형식과 연결 정보 중 어느 쪽으로도 가려내지 못했으니, 웹 도구에 넣을 파일이면 바이너리로 내보내는 편이 안전합니다.

이름 규칙으로 자동 연결되는 원리

이미지를 함께 넣어도 경로가 깨진 FBX라면 파일과 재질을 다시 짝지어야 합니다. 변환기는 재질 이름과 파일 이름을 비교해 겹치는 단어가 있는 이미지를 그 재질에 붙입니다. 이 팩의 파일 이름에는 부위를 나타내는 단어(Jacket, teeth, fiber, Eyes)와 맵 종류(Height, ID, depth)가 들어 있어서, 재질 이름에 같은 부위 단어가 있으면 쉽게 맞아떨어집니다.

Character_0726의 재질 9개 가운데 6개는 파일 이름으로 자동 연결됐고 3개는 수동 지정이 필요했습니다. 걸린 것은 재킷의 “19 – Default”와 머리카락·눈썹의 “Hair_Eyeslash” 쪽 재질입니다. 3ds Max 도움말(2012판)에 따르면 재질 편집기는 새 재질에 “01 – Default”처럼 샘플 슬롯 번호가 붙은 기본 이름을 주는데, 이 모델의 재킷 재질 이름이 바로 그 형식입니다. 재킷 텍스처 파일은 subs_Jacket_*으로 시작하니 두 이름 사이에 겹치는 단어가 하나도 없습니다. Hair_Eyeslash 재질도 파일 쪽이 fiber_*라 Hair라는 단어로는 찾을 수 없었습니다. 직접 내보내는 모델이라면 재질 이름에 파일 이름과 같은 부위 단어를 넣어 두는 것만으로 수동 지정이 줄어듭니다.

텍스처 연결 기능을 만들면서 두 번 넘어졌습니다. 첫째, 수동으로 붙인 텍스처에 flipY=false를 강제했더니 이미지가 위아래로 뒤집혔습니다. FBXLoader가 불러오는 텍스처는 기본이 flipY=true라서 자동 연결분과 방향이 달라졌던 것입니다. 둘째, 이미지 데이터가 비어 있는 1×1 텍스처가 섞이자 glTF 내보내기(GLTFExporter)가 멈췄습니다. 두 문제 모두 변환기에서 고쳤습니다.

glTF로 옮길 때 생기는 변화

FBX에서 텍스처를 다 찾았다고 모든 이미지가 VRM으로 넘어가지는 않습니다. VRM 1.0 규격은 glTF 2.0을 바탕으로 쓰였고 파일은 .glb 형식에 .vrm 확장자를 붙여 저장합니다. 이 변환기는 VRMC_vrm 확장만 쓰고 MToon 셰이더 확장(VRMC_materials_mtoon)은 쓰지 않으므로 재질이 glTF 표준 PBR(metallic-roughness)로 나갑니다. glTF 2.0 핵심 규격의 재질 텍스처 칸은 기본색, 금속도·거칠기, 노멀, 오클루전, 이미시브 다섯 가지뿐입니다.

  • 불투명도: glTF에는 불투명도 전용 칸이 없습니다. 투명도는 기본색 텍스처의 알파 채널과 재질의 alphaMode로 정해지므로, 변환기는 불투명도 맵을 기본색 이미지의 알파에 구워 넣습니다.
  • 금속도와 거칠기: glTF는 한 장의 metallicRoughnessTexture에서 파랑(B) 채널을 금속도로, 초록(G) 채널을 거칠기로 읽습니다. 따로 있던 두 맵은 한 장으로 합쳐집니다.
  • 자리가 없는 맵: fiber_ID·depth·direction·root 계열은 Substance 작업용 보조 맵이고 teeth_teeth_Height.tga는 높이맵입니다. 어느 쪽도 glTF 핵심 규격에 대응하는 칸이 없어 결과 파일에 실리지 않습니다.
  • 이미지 형식: glTF 핵심 규격이 이미지 형식으로 정한 것은 PNG와 JPEG입니다. TGA 원본은 그대로 실을 수 없고 둘 중 하나로 다시 인코딩돼야 합니다.

용량도 달라집니다. 텍스처를 원본 크기 그대로 넣으면 결과가 100MB를 넘길 수 있고, 변환기의 크기 제한을 1024px로 두면 약 35MB가 됩니다.

Character_0726 텍스처 점검 결과 표: 재질 9개 중 6개 자동 연결, 3개 수동 지정, 절대경로 눈 텍스처 3개 없음, glTF에 칸이 없는 fiber 보조 맵과 높이맵, 합쳐지는 불투명도·금속도·거칠기
Character_0726의 텍스처가 연결되고, 빠지고, glTF로 가면서 합쳐지거나 빠지는 경우를 한 표로 정리했습니다.

텍스처가 빠진 FBX를 고치는 순서

  1. 형태는 멀쩡하고 무늬만 없으면 이미지 연결 문제, 로드 자체가 멈추면 연결 표에서 빠진 노드를 의심합니다.
  2. FBX만 넣었을 때 붙는 텍스처가 있는지 봅니다. 하나도 없다면 대개 참조 방식이니 원본 폴더나 .fbm 폴더의 이미지를 FBX와 함께 넣습니다.
  3. 연결되지 않은 파일 이름을 확인합니다. D:\ 같은 절대경로라면 만든 사람의 컴퓨터에만 있던 파일일 가능성이 크니 원본 팩에서 찾거나 비슷한 이미지로 대신합니다.
  4. TGA·DDS는 전용 로더가 필요하고 PSD는 FBXLoader가 읽지 못합니다. 도구가 받지 않는 형식은 PNG로 바꿉니다.
  5. 자동 연결되지 않은 재질을 수동으로 지정합니다. “19 – Default” 같은 기본 이름이 남은 재질이 주로 걸립니다.
  6. glTF·VRM으로 내보낼 때는 합쳐지거나 빠지는 맵을 감안하고 텍스처 크기 제한을 겁니다.

텍스처를 다 붙였는데도 몸이 찢어지거나 사람 두께가 1.8m로 늘어나 보인다면 이미지가 아니라 뼈대 쪽 문제입니다. 바인드 행렬이 어긋난 모캡 FBX 사례는 찢어진 스킨드 메시 글에, 본 이름을 VRM 휴머노이드 칸에 맞추는 과정은 Mixamo FBX 본 매핑 글에 따로 적었습니다.

참고한 자료

아래 문서는 2026년 9월 확인 기준입니다.

위로 스크롤