이번 포스트에서는 기존에 사용하던 assimp 라이브러리를 대체하기 위해 새로운 라이브러리를 만드는 과정을 설명하려 한다. 이름은 내 닉네임을 딴 sAssimp로 정했다.
1. assimp 라이브러리란?
assimp는 OpenGL 등 다양한 그래픽 API에서 사용하는 3D 모델 데이터를 쉽게 로드하고 처리할 수 있도록 도와주는 라이브러리이다. .obj, .fbx 등의 파일 포맷을 파싱하고, 모델의 버텍스(vertex), 인덱스(indices), 노멀(normal) 및 텍스처 좌표 등을 가져와 렌더링에 사용할 수 있게 한다. 이 라이브러리를 사용하면 다양한 3D 모델 포맷을 다루는 작업을 간단하게 처리할 수 있다.
2. 과제에 맞는 sAssimp 라이브러리
bool sAssimp::LoadBysAssimp(const std::string& filename) {
auto result = LoadTextFile(filename);
if (!result.has_value())
return false;
std::stringstream text(result.value());
std::string line;
while (std::getline(text, line)) {
std::stringstream ss(line);
std::string type;
ss >> type;
if (type == "v") { // 버텍스 파싱
if (!ParseVertex(ss))
return false;
}
else if (type == "vt") { // 텍스처 좌표 파싱
if (!ParseTexCoord(ss))
return false;
}
else if (type == "vn") { // 노멀 벡터 파싱
if (!ParseNormal(ss))
return false;
}
else if (type == "f") { // 페이스 정보 파싱
if (!ParseFace(ss))
return false;
}
else if (type == "mtllib") { // mtl 정보 파일 파싱
if (!ParseMtl(ss, filename))
return false;
}
}
return true;
}
bool sAssimp::ParseVertex(std::stringstream& ss) {
glm::vec3 vertex;
std::string token;
if (!(ss >> token))
return false;
auto x = ParseFloat(token);
if (!x.has_value())
return false;
vertex.x = x.value();
if (!(ss >> token))
return false;
auto y = ParseFloat(token);
if (!y.has_value())
return false;
vertex.y = y.value();
if (!(ss >> token))
return false;
auto z = ParseFloat(token);
if (!z.has_value())
return false;
vertex.z = z.value();
if (ss >> token)
return false;
m_vertices.push_back(vertex);
return true;
}
과제에서는 이러한 외부 라이브러리를 사용할 수 없기 때문에, assimp의 기능을 직접 구현해 대체해야 한다.
내가 만드는 sAssimp 라이브러리는 3D 모델 데이터를 파싱하고, 필요한 정보를 추출해 OpenGL로 렌더링할 수 있도록 하는 기능을 제공하게 된다.
.obj 파일을 파싱할 때 o, g와 같은 키워드들은 객체나 그룹을 정의하는데 사용되지만, 실제 렌더링에는 큰 영향을 주지 않는다고 판단했다. 물론 이 부분이 텍스처 적용이나 다른 세부적인 렌더링 요소에 영향을 줄 수 있다는 점은 알고 있지만, 파싱 과정에서 복잡성을 줄이기 위해 이러한 키워드들은 무시하기로 했다. 이를 통해 파싱 로직을 간소화하고 중요한 데이터인 버텍스, 텍스처, 노멀, 페이스에 집중하는 데 주력했다.
기본적으로 sAssimp는 .obj 파일의 구조를 파싱하며, 각 버텍스의 위치, 텍스처 좌표, 그리고 인덱스 정보를 가져와 버텍스 버퍼에 넣어준다. 하지만 기존에 사용하는 assimp와 다르게, 현재 내 라이브러리에는 몇 가지 문제가 있다.
3. 인덱싱 문제와 해결 방안
현재 sAssimp 라이브러리로 모델을 렌더링하면 기존 assimp 라이브러리로 렌더링할 때보다 이미지가 흐릿하거나 뭉뜬 느낌이 드는 문제가 있다.
같이 과제를 진행하는 동료와 함께 이 문제를 해결하기 위해 여러 가지 실험을 진행했다. 특히 .obj 파일의 f (face) 요소를 인덱싱하여 버텍스를 재구성하는 과정이 차이를 만들 수 있다는 점에 집중했다.
기존 assimp 라이브러리는 f 요소를 적절히 인덱싱하여 버텍스 버퍼에 정렬된 형태로 넣는데, 예를 들어 f 16 2 3이라는 데이터가 있다면 이를 재구성하여 인덱스 0부터 시작하는 정렬된 데이터로 변환한 후 버퍼에 넣는다.
반면, sAssimp는 .obj 파일의 f 요소를 있는 그대로 버텍스 버퍼에 넣고 있어 무질서한 인덱스가 저장되고, 이로 인해 렌더링 시 올바른 결과를 내지 못하는 것 같다. 하지만 이는 여전히 가정에 불과하며, 실제로 인덱싱 정렬과 재구성 로직을 추가함으로써 문제가 해결되는지 확인해봐야 한다.
4. 성능 최적화와 코드 리팩토링
현재 sAssimp의 구조에서는 클래스 내부에 모든 데이터를 보관하고 있다. 이 때문에 스코프가 닫히면 데이터가 손실될 위험이 있어, 깊은 복사를 통해 데이터를 보내고 있다. 하지만 이러한 깊은 복사는 불필요한 메모리 사용과 성능 저하를 유발한다. 이를 개선하기 위해 std::unique_ptr와 같은 스마트 포인터를 적절하게 활용해 데이터 소유권을 효율적으로 관리하고자 한다.
향후 코드 리팩토링을 통해 성능 최적화를 진행할 예정이며, 중간 결산으로 이 부분에 대한 계획을 공유하려 한다.
다음 포스트에서는 인덱싱 문제를 해결하고 성능을 향상시키는 과정을 다룰 예정이다.
'Computer Graphics > SCOP' 카테고리의 다른 글
SCOP - 5. stb 대체하는 bmp 로더 만들기 (0) | 2024.09.29 |
---|---|
SCOP - 4. assimp 대체 라이브러리 만들기 (1) (0) | 2024.09.29 |
SCOP - 2. 랜덤한 vertex 색 적용 및 texture 적용 (0) | 2024.09.25 |
SCOP - 1. 오브젝트 이동, 회전 구현 (1) | 2024.09.25 |
SCOP - 0. 과제해석 (1) | 2024.09.24 |