Assimp
지금까지 우리는 작은 컨테이너 객체를 많이 활용해 왔지만, 아무리 친한 친구라도 시간이 지나면 조금 지루해질 수 있습니다. 대형 그래픽 애플리케이션에는 정적인 컨테이너보다 훨씬 보기 좋은 복잡하고 흥미로운 모델들이 많이 있습니다. 하지만 컨테이너 객체와는 달리, 집, 차량, 사람과 같은 캐릭터와 같은 복잡한 형태의 객체는 모든 정점, 법선, 텍스처 좌표를 수동으로 정의할 수 없습니다. 따라서 우리는 Blender, 3DS Max, Maya와 같은 도구를 사용하여 3D 아티스트가 세심하게 디자인한 이러한 모델들을 애플리케이션으로 불러오고 싶어합니다.
이른바 3D 모델링 도구는 아티스트가 복잡한 형태를 만들고 UV 매핑이라는 과정을 통해 텍스처를 적용할 수 있도록 해줍니다. 이러한 도구는 모든 정점 좌표, 정점 법선, 텍스처 좌표를 자동으로 생성하고 우리가 사용할 수 있는 모델 파일 형식으로 내보냅니다. 따라서 아티스트는 기술적인 세부 사항에 크게 신경 쓰지 않고도 고품질 모델을 제작할 수 있는 광범위한 도구를 갖게 됩니다. 모든 기술적인 측면은 내보낸 모델 파일에 숨겨져 있습니다. 하지만 그래픽 프로그래머인 우리는 이러한 기술적인 세부 사항에 신경 써야 합니다.
우리의 임무는 이렇게 내보낸 모델 파일을 분석하여 모든 관련 정보를 추출하고 OpenGL이 이해할 수 있는 형식으로 저장하는 것입니다. 흔히 발생하는 문제는 수십 가지의 서로 다른 파일 형식이 존재하며 각 형식이 고유한 방식으로 모델 데이터를 내보낸다는 점입니다. Wavefront의 .obj와 같은 모델 형식은 모델 색상, 디퓨즈/스페큘러 맵과 같은 기본적인 재질 정보만 포함하는 반면, XML 기반의 Collada 파일 형식은 모델, 조명, 다양한 재질, 애니메이션 데이터, 카메라, 전체 장면 정보 등 매우 광범위한 데이터를 포함합니다. Wavefront 객체 형식은 일반적으로 분석하기 쉬운 모델 형식으로 여겨집니다. Wavefront 위키 페이지를 방문하여 이러한 파일 형식의 데이터 구조를 살펴보는 것이 좋습니다. 이를 통해 모델 파일 형식의 일반적인 구조를 이해하는 데 도움이 될 것입니다.
결론적으로, 파일 형식은 매우 다양하며, 이들 간에는 일반적으로 공통된 구조가 존재하지 않습니다. 따라서 이러한 파일 형식에서 모델을 가져오려면 각 파일 형식에 대한 임포터를 직접 작성해야 합니다. 다행히도 이를 위한 라이브러리가 존재합니다.
모델 로딩 라이브러리
Assimp는 Open Asset Import Library의 약자로, 매우 인기 있는 모델 임포트 라이브러리입니다. Assimp는 다양한 모델 파일 형식을 가져올 수 있으며(일부 형식으로는 내보내기도 가능), 모델의 모든 데이터를 Assimp의 일반화된 데이터 구조에 로드합니다. Assimp가 모델을 로드하면 필요한 모든 데이터를 Assimp의 데이터 구조에서 가져올 수 있습니다. Assimp의 데이터 구조는 가져온 파일 형식에 관계없이 동일하게 유지되므로, 다양한 파일 형식에 대한 제약 없이 데이터를 추상화하여 사용할 수 있습니다.
Assimp를 통해 모델을 불러오면 전체 모델이 장면 객체로 로드됩니다. 이 장면 객체에는 불러온 모델/장면의 모든 데이터가 포함됩니다. Assimp는 노드들의 모음을 가지고 있는데, 각 노드는 장면 객체에 저장된 데이터에 대한 인덱스를 가지며, 각 노드는 원하는 만큼 자식 노드를 가질 수 있습니다. Assimp의 구조를 (단순화하여) 나타낸 그림은 아래와 같습니다.

- 장면(Scene)의 모든 데이터는 모든 재질(Materials)과 메쉬(Meshes)와 같이 장면 객체(Scene object)에 포함되어 있습니다. 또한 이는 장면의 루트 노드(Root node)에 대한 참조를 포함합니다.
- 장면의 루트 노드는 (다른 모든 노드들과 마찬가지로) 자식 노드들을 포함할 수 있으며, 장면 객체의 mMeshes 배열에 있는 메쉬 데이터를 가리키는 인덱스 세트를 가질 수 있습니다. 장면의 mMeshes 배열은 실제 메쉬 객체들을 포함하며, 노드의 mMeshes 배열에 있는 값들은 장면의 메쉬 배열을 위한 인덱스일 뿐입니다.
- 메쉬 객체 자체는 렌더링에 필요한 모든 관련 데이터, 즉 정점 위치, 법선 벡터, 텍스처 좌표, 면(Faces), 그리고 객체의 재질을 포함합니다.
- 메쉬는 여러 개의 면(Faces)을 포함합니다. 면은 객체의 렌더링 프리미티브(삼각형, 사각형, 점)를 나타냅니다. 면은 프리미티브를 형성하는 정점들의 인덱스를 포함합니다. 정점과 인덱스가 분리되어 있기 때문에, 인덱스 버퍼를 통해 렌더링하기가 쉽습니다 (안녕 삼각형 챕터 참고).
- 마지막으로 메쉬는 객체의 재질 속성을 검색하는 여러 기능을 호스팅하는 재질 객체(Material object)와도 연결됩니다. 색상 및/또는 텍스처 맵(Diffuse 및 Specular 맵 등)을 생각하면 됩니다.
우리가 하려는 작업은 다음과 같습니다. 먼저 객체를 Scene 객체에 로드하고, 각 노드에서 해당 Mesh 객체를 재귀적으로 검색합니다(각 노드의 자식 노드를 재귀적으로 검색). 그런 다음 각 Mesh 객체를 처리하여 정점 데이터, 인덱스 및 재질 속성을 추출합니다. 이렇게 얻은 Mesh 데이터를 하나의 Model 객체에 담습니다.
Mash
모델링 툴킷을 사용하여 객체를 모델링할 때, 아티스트는 일반적으로 하나의 형태로 전체 모델을 만들지 않습니다. 보통 각 모델은 여러 개의 하위 모델/형태로 구성됩니다. 이러한 각각의 형태를 메시라고 합니다. 사람 모양의 캐릭터를 예로 들면, 아티스트는 일반적으로 머리, 팔다리, 옷, 무기 등을 각각 별개의 구성 요소로 모델링하고, 이러한 메시들을 모두 합쳐 최종 모델을 만듭니다. 하나의 메시는 OpenGL에서 객체를 렌더링하는 데 필요한 최소한의 정보(정점 데이터, 인덱스, 재질 속성)를 담고 있습니다. 모델은 (일반적으로) 여러 개의 메시로 구성됩니다.
다음 장에서는 방금 설명한 구조를 사용하여 가져온 모델을 로드하고 저장하는 자체 Model 및 Mesh 클래스를 만들 것입니다. 그런 다음 모델을 그리려면 모델 전체를 렌더링하는 것이 아니라 모델을 구성하는 모든 개별 메시를 렌더링합니다. 하지만 모델을 가져오기 전에 먼저 Assimp를 프로젝트에 포함해야 합니다.
Assimp 빌딩
이 가이드는 오래되었으며, 현재는 아래 명령어로 더 간단하게 설치할 수 있습니다.
vcpkg install assimp:x64-windows
리눅스에서는
sudo apt-get update
sudo apt-get install libassimp-dev
자세한 내용은 공식 빌드, 설치 가이드를 참고하세요.
Assimp는 GitHub 페이지에서 다운로드할 수 있으며, 원하는 버전을 선택하세요. 이 글에서는 Assimp 3.1.1 버전을 사용했습니다. 제공되는 사전 컴파일된 라이브러리가 모든 시스템에서 제대로 작동하지 않을 수 있으므로 직접 컴파일하는 것이 좋습니다. CMake를 사용하여 라이브러리를 직접 컴파일하는 방법을 잊어버린 경우, "안녕 창" 장을 참고하세요.
Assimp를 빌드하는 동안 몇 가지 문제가 발생할 수 있으므로, 혹시 같은 오류를 겪는 분들이 있을까 봐 문제와 해결 방법을 여기에 적어 두겠습니다.
- CMake가 구성을 가져오는 동안 DirectX 라이브러리가 누락되었다는 오류를 계속해서 발생시킵니다.
이 문제를 해결하려면 DirectX SDK를 설치해야 합니다. 이전에 설치하지 않았다면 여기에서 SDK를 다운로드할 수 있습니다.Could not locate DirectX CMake Error at cmake-modules/FindPkgMacros.cmake:110 (message): Required library DirectX not found! Install the library (including dev packages) and try again. If the library is already installed, set the missing variables manually in cmake. - DirectX SDK를 설치하는 동안 s1023 오류 코드가 발생할 수 있습니다. 이 경우 SDK를 설치하기 전에 먼저 C++ 재배포 가능 패키지를 제거해야 합니다.
이 팁들은 최근을 기준으로 하지 않았으며, 현재에는 해결되었을수도 있습니다.
설정이 완료되면 솔루션 파일을 생성하고 열어서 라이브러리를 컴파일할 수 있습니다(릴리스 버전 또는 디버그 버전 중 원하는 버전을 선택하세요). LearnOpenGL의 모든 코드는 64비트이므로 64비트용으로 컴파일해야 합니다.
기본 설정에서는 Assimp를 동적 라이브러리로 빌드하므로, 생성된 DLL 파일(assimp.dll 또는 접미사가 붙은 파일)을 애플리케이션 실행 파일과 함께 포함해야 합니다. 해당 DLL 파일을 애플리케이션 실행 파일이 있는 폴더에 복사하면 됩니다.
생성된 솔루션을 컴파일하면 결과 라이브러리 및 DLL 파일이 code/Debug 또는 code/Release 폴더에 저장됩니다. 해당 라이브러리 및 DLL 파일을 적절한 위치로 이동하고 솔루션에서 링크한 다음, Assimp의 헤더 파일을 include 디렉터리에 복사해야 합니다(헤더 파일은 Assimp에서 다운로드한 파일의 include 폴더에 있습니다).
이제 Assimp를 컴파일하고 애플리케이션에 연결했어야 합니다. 만약 여전히 보고되지 않은 오류가 발생한다면 댓글로 도움을 요청하세요.