이전 포스팅에서 이야기했듯, 프로그래머가 일일히 버텍스를 찍어 오브젝트를 만드는것은 불편한 일이다. 이를 위해 모델링 프로그램을 활용한다. blender, maya와 같은 프로그램으로 오브젝트를 만들 수 있는데, 수 많은 모델링 프로그램들이 각기 다른 폼의 모델링 파일을 만들어낸다.
만들어진 파일을 사용하기 위해서는 각 파일에 맞는 파서(parser)를 제작하여 읽어들여야하지만 수 많은 형태의 파서를 제작하기란 쉬운 일이 아니다.
이를 위해 외부 라이브러리를 링크하여 모델링 파일을 읽어들여서 물체를 로딩해보도록 하자
Assimp사용해볼 라이브러리는 assimp 라는 asset importer.
assimp)이 assimp라는 라이브러리를 통해 모델링 파일을 읽어들여서 렌더해보도록 하자.
3D 그래픽스에서 Scene Tree(씬 트리)는 복잡한 3D 장면을 효율적으로 관리하고 조직하기 위해 계층 구조로 구성된 데이터 구조이다. 이 구조를 통해 장면(Scene) 내의 오브젝트, 빛, 카메라, 애니메이션 등을 직관적이고 효율적으로 관리할 수 있다.
Scene Tree는 주로 노드들로 이루어지며, 각 노드는 특정 3D 객체를 나타내거나 그룹화된 하위 객체들을 포함할 수 있다. 이 트리는 부모-자식 관계를 기반으로 한 계층 구조로 구성되어 있으며, 이로 인해 한 객체의 변형(위치, 회전, 스케일)이 해당 객체의 자식 객체들에도 영향을 미치는 변환 전파(Transformation propagation)가 가능하다.
노드(Node): Scene Tree의 기본 단위로, 3D 객체(메시), 빛, 카메라 등 모든 장면의 요소를 표현한다. 노드는 자체 변환(위치, 회전, 크기)과 자식 노드를 가질 수 있다.
부모-자식 관계(Parent-Child Relationship): 노드 간의 계층 구조를 통해 부모 노드의 변환이 자식 노드에 자동으로 적용된다. 예를 들어, 부모 노드가 회전하면 그 자식 노드들도 함께 회전합니다. 이를 통해 복잡한 장면에서 개체 간의 관계를 쉽게 관리할 수 있다. 예를 들어 캐릭터를 모델링한다고 할 때, 팔이 움직이면 손도 같이 움직여지듯, 팔-손이 부모-자식 관계를 가진다.
변환 전파(Transformation Propagation): 부모 노드의 위치, 회전, 스케일과 같은 변환이 자식 노드들에게 전파된다.
월드 좌표계(World Space)와 로컬 좌표계(Local Space):
그룹화(Grouping): 여러 개체를 하나의 부모 노드로 묶어서 관리한다. 예를 들어, 자동차를 구성하는 여러 부품을 하나의 부모 노드로 묶어 자동차 전체를 하나의 객체처럼 다룰 수 있음.
: Scene Tree의 노드를 처리할 때는 일반적으로 트리 순회 알고리즘이 사용됩니다. 보통 깊이 우선 탐색(DFS)을 사용하여 노드를 방문하고 변환을 적용합니다.
: Scene Tree를 사용하면 시야에 보이지 않는 객체들을 빠르게 무시할 수 있습니다. 트리 구조에서 상위 노드가 화면에 보이지 않으면 그 자식 노드들도 모두 무시할 수 있기 때문에 렌더링 성능을 최적화하는 데 도움이 됩니다.
네, Assimp(Open Asset Import Library)도 3D 모델 파일을 읽을 때 씬 트리(Scene Tree) 구조를 사용합니다. Assimp는 다양한 3D 파일 형식을 로드하고 처리할 수 있는 라이브러리로, 3D 모델 데이터뿐만 아니라 장면의 계층적 구조도 제공합니다.
Assimp에서 로드된 모델은 aiScene이라는 구조로 표현되며, 이 구조 안에는 aiNode를 기반으로 한 계층적 트리가 포함됩니다. 이 aiNode들은 부모-자식 관계를 형성하며, 각각의 노드는 메쉬, 변환 정보, 자식 노드 등을 포함할 수 있습니다.
aiScene:
aiNode:
aiMesh:
Transform Propagation:
Assimp가 지원하는 다양한 파일 형식(예: FBX, OBJ)도 이러한 씬 트리 구조를 따르기 때문에, Assimp를 사용하여 다양한 형식의 모델을 로드할 때도 일관된 방식으로 처리하자.
assimp::Importer로 오브젝트 파일 read 하기.
RootNode 부터 읽어들임.
RootNode가 가진 메쉬 정보를 차례로 읽음
읽은 메쉬 정보를 std::vector<mesh> 컨테이너로 묶어 각 요소에 VAO, VBO, EBO 저장
이후 RootNode의 자식 노드에 대해 재귀적으로 위 과정 반복.
모든 노드에 대해 읽었다면, 읽어들인 메쉬 정보들을 차례로 Draw.
텍스쳐의 경우, std::vector<material> 컨테이너로 씬을 구성하는 매쉬들의 재질 정보를 담는다.
각 메쉬에 해당하는 재질 diffuse, specular 텍스처를 불러와 컨테이너에 담기.
매쉬를 구성한 후, 매쉬의 mesh->mMaterialIndex 에 해당하는 텍스처로 재질 값 set.
텍스처는 프로그램의 유니폼으로 바인드하여 쉐이더로 보내야하므로 텍스처를 사용할 프로그램에 세팅
모델 Draw.