Computer Graphics 110

HumanGL - 3. 사람 그리기

이제 상자의 스케일을 조정하고, 몸의 각 파트를 계층적으로 나누어 사람을 그려주었다. 하위 단계의 값들은 상위 단계의 값을 계승하며, 각 파트는 부모의 상대 좌표를 기반으로 계산된다. 이렇게 계층 구조로 설정된 방식은 게임 엔진의 트리 구조와 비슷하게 동작한다.Human 초기화먼저 사람의 각 신체 부위를 초기화하는 작업부터 시작했다. 몸통을 중심으로 머리, 팔, 다리 등 모든 부위를 트리 구조로 정리해주었다. 각 파트는 위치(translate), 회전(rotate), 크기(scale), 색상(color) 정보를 가지며, 이 값들은 계층적으로 상위 값을 계승한다.void Human::Init() { m_body = {sglm::vec3(0.0f, 0.0f, 0.0f), sglm::vec3(0.0f, ..

HumanGL - 2. Scale 적용 해보기

사람을 그리기 전에 먼저 해야 할 일이 있다. 바로 상자를 늘리고 줄이는 작업이다! 이를 위해 sglm에 scale 함수를 추가하고, 이를 적용해 보았다.sglm::mat4 scale(const sglm::mat4& m, const sglm::vec3& v) { sglm::mat4 result(1.0f); result[0][0] = v.x; result[1][1] = v.y; result[2][2] = v.z; return result * m;}위와 같은 방식으로 scale 함수를 구현했고, 이를 적용해 모델의 크기를 조정했다.model = sglm::scale(model, sglm::vec3(1.0f, 1.2f, 0.5f));   아주 잘 동작한다. 이 상자는 이제 바디가 될..

HumanGL - 1. 초기 설정, 상자 띄우기

https://github.com/ksro0128/OpenglTuto GitHub - ksro0128/OpenglTutoContribute to ksro0128/OpenglTuto development by creating an account on GitHub.github.com기존에 OpenGL을 공부하던 코드를 가져와 과제에 맞게 초기 설정을 해주었다. 이번 과제에서는 텍스처 적용을 하지 않을 계획이라 불필요한 라이브러리들을 제거했다. assimp, stb, glm과 같은 라이브러리를 모두 날리고, 상자만 띄우는 데 집중했다.필요 없는 요소들을 정리하고 상자만 띄운 모습은 다음과 같다.  SCOP 과제에서 사용하던 sglm 라이브러리를 그대로 썼는데, 여기서 문제가 생겼다. 바로 lookat 계산식에..

HumanGL - 0. 과제 해석

이번 HumanGL 과제는 OpenGL을 사용하여 계층적 모델링과 매트릭스 스택 조작을 학습하기 위한 중요한 프로젝트이다. 특히, 이 과제는 OpenGL 4.0 이상의 버전을 사용하여 자체 매트릭스 연산을 구현하는 것을 요구하며, 기본적인 GPU 렌더링과 모델 애니메이션의 개념을 깊이 있게 탐구하도록 설계되었다. 과제의 주요 내용과 세부 사항은 다음과 같다.프로젝트 개요목적:이 프로젝트의 궁극적인 목표는 OpenGL을 사용하여 각기 다른 신체 부위들이 논리적으로 연결되고, 매트릭스 스택을 통해 함께 움직이도록 구현하는 것이다. 이를 통해 각각의 부위는 독립적으로 조작될 수 있으며, 상호 간에 적절히 연결된 애니메이션을 만들어 낼 수 있다. 각 부위의 크기나 위치를 수정할 때 관련된 다른 부위들도 자동으로..

SCOP - 7. 평가 피드백

첫 3번의 평가를 마쳤다. 결과는 아쉽게도 Fail이다. 구현 자체는 잘 되었으나, obj 파일 파싱 부분에서 기본적인 실수를 범했다 ㅠㅠ. 그로 인해 중요한 오류들이 발생했다.1. f 인덱스 에러 처리 문제첫 번째 문제는 obj 파일의 f 인덱스가 정상적인 범위를 벗어나는 경우에 대한 에러 처리를 하지 않았다는 점이다. 인덱스가 v(버텍스 개수)를 초과하거나 음수값이 들어올 때 에러를 처리해주지 않아서, 나중에 벡터에서 해당 인덱스를 참조하려 할 때 segmentation fault가 발생했다.이것은 아주 치명적인 실수였다. 분명 인덱싱하는 과정에서 한 번쯤 고려했어야 했는데 깜빡하고 처리하지 않았다.2. 파일 확장자 확인 오류두 번째 실수는 완전히 놓친 부분이었다. 아래와 같은 코드로 .obj 파일 ..

SCOP - 6. glm 대체하는 sglm 만들기

드디어 glm 라이브러리를 완전히 대체할 sglm 라이브러리를 개발하고 적용했다. 이로써 SCOP 프로젝트에서 사용하던 모든 외부 라이브러리가 대체되어 직접 구현한 코드로만 구성되었다.하지만 이를 구현하는 과정에서 몇 가지 문제가 있었다. 특히, 행렬 변환 시 OpenGL의 열 우선 저장 방식과 3D 그래픽에서의 다양한 변환들이 어려움을 줬다. 이 포스트에서는 이러한 문제를 해결한 경험과 함께 sglm 의 주요 변환 함수인 translate, lookAt, perspective의 의미와 역할에 대해 서술하려 한다.  행렬 저장 방식에서의 문제행렬 변환을 구현하는 과정에서 가장 어려웠던 부분은 행렬이 OpenGL에서는 열 우선(column-major) 방식으로 저장된다는 것이었다. 처음에는 일반적인 수학적..

SCOP - 5. stb 대체하는 bmp 로더 만들기

이번 포스트에서는 stb 라이브러리를 대체하기 위해 추가한 BMP 로더에 대해 설명한다. stb_image를 사용해 이미지를 로드하는 기능을 직접 구현함으로써 라이브러리 의존성을 제거했다. 여기서 BMP 파일을 로드하고 처리하는 LoadWithBmp() 함수가 이번에 추가된 부분이다.BMP 로더 핵심 로직BMP 파일 로딩은 기존 stb_image를 사용한 로딩 방식과 다르게 직접 바이너리 데이터를 읽어와 이미지의 정보를 추출하고, 이를 m_data 버퍼에 저장하는 과정을 거친다. 자세한 로직은 다음과 같다.bool Image::LoadWithBmp(const std::string& filepath) { std::ifstream file(filepath, std::ios::binary); if ..

SCOP - 4. assimp 대체 라이브러리 만들기 (1)

assimp 라이브러리를 대체하기 위해 개발한 sAssimp 라이브러리의 개선 사항을 포스트하겠다.이전에 언급했던 모델이 흐릿하거나 뭉뜬그려지는 문제는 인덱스 처리 오류로 밝혀졌으며, 이를 수정했다. 또한, 데이터 복사에 대한 우려로 인해 깊은 복사를 사용했었으나, OpenGL 버퍼에 데이터가 이미 저장된 이후에는 C++ 코드에서 데이터 관리를 직접 하지 않아도 된다는 것을 알게 되어 코드 구조를 변경했다. 최대한 기존 코드를 유지하면서 불필요한 복사를 줄이고 인덱싱 과정에서 최적화를 진행했고, 그 핵심 로직은 아래 Indexing() 함수에 있다.void sAssimp::Indexing() { uint32_t index = 0; for (auto& face : m_faces) { ..

SCOP - 3. assimp 대체 라이브러리 만들기 (0)

이번 포스트에서는 기존에 사용하던 assimp 라이브러리를 대체하기 위해 새로운 라이브러리를 만드는 과정을 설명하려 한다. 이름은 내 닉네임을 딴 sAssimp로 정했다.1. assimp 라이브러리란?assimp는 OpenGL 등 다양한 그래픽 API에서 사용하는 3D 모델 데이터를 쉽게 로드하고 처리할 수 있도록 도와주는 라이브러리이다. .obj, .fbx 등의 파일 포맷을 파싱하고, 모델의 버텍스(vertex), 인덱스(indices), 노멀(normal) 및 텍스처 좌표 등을 가져와 렌더링에 사용할 수 있게 한다. 이 라이브러리를 사용하면 다양한 3D 모델 포맷을 다루는 작업을 간단하게 처리할 수 있다. 2. 과제에 맞는 sAssimp 라이브러리bool sAssimp::LoadBysAssimp(co..

SCOP - 2. 랜덤한 vertex 색 적용 및 texture 적용

기본적으로 과제에서 요구하는 외부 라이브러리 제한을 무시하고, 먼저 완전한 프로그램을 만든 후 나중에 라이브러리를 직접 구현하는 방식으로 접근하고 있다. 이번 포스트에서는 랜덤한 버텍스 색상과 텍스처 적용 기능을 설명하겠다.1. 랜덤한 Vertex 색 적용버텍스의 색상을 랜덤하게 지정하는 기능을 구현했다. 3D 모델의 각 버텍스마다 고유한 색을 부여하여, 화면에 표시될 때 다양한 색상의 면이 나타나도록 했다. rand() 함수를 사용해 0.0부터 1.0 사이의 난수를 생성하고, 이를 RGB 값으로 변환하여 각 버텍스에 할당했다.if (mesh->HasVertexColors(0)) { v.rgb = glm::vec3(mesh->mColors[0][i].r, mesh->mColors[0][i].g, m..