상세 컨텐츠

본문 제목

SCOP : GLM을 대체하는 GLMath 라이브러리 구현 - (4)

Computer Graphics/SCOP

by Banjosh 2024. 9. 20. 16:05

본문

과제에서 사용하지 말라는 GLM을 대체할 나만의 GLMath 라이브러리를 만들었다.

구현 내용:

  • Class: vec2, vec3, vec4, mat4
  • Function: value_ptr(), dot(), cross(), normalize(), radians(), scale(), translate(), rotate(), perspective(), lookAt()
  • Variable: pi

OpenGL을 배울 때 사용했던 코드들을 참고하면서 자주 쓰였고, 필요해 보이는 함수들로 구성했다. 이 안에서 대부분 해결할 수 있을 것 같지만, 프로젝트를 진행하면서 추가로 필요한 함수가 있으면 그때그때 새로 추가할 예정이다.

각각의 역할

Class

  • vec2: 2차원 벡터
  • vec3: 3차원 벡터
  • vec4: 4차원 벡터
  • mat4: 4x4 행렬

위 클래스들은 기본적으로 float 값을 사용한다. 기본적인 생성자, 복사 생성자, 복사 대입 연산자, +, -, *, [] 연산자 등을 구현해두었다. 추가로 상수 곱 연산과 mat4 * vec4 연산도 구현했다.

Function

  • value_ptr(): Uniform 변수를 등록할 때 첫 번째 원소의 포인터를 반환하는 함수
  • dot(): 벡터의 내적 함수
  • cross(): 벡터의 외적 함수
  • normalize(): 벡터를 정규화하는 함수
  • radians(): degree를 radian으로 변환하는 함수
  • scale(): 행렬에 스케일 변환을 적용하는 함수
  • translate(): 행렬에 이동 변환을 적용하는 함수
  • rotate(): 행렬에 축 회전 변환을 적용하는 함수
  • perspective(): 원근법 변환 행렬을 반환하는 함수
  • lookAt(): 카메라의 위치, 바라보는 대상, 카메라의 위쪽 벡터를 이용해 카메라 좌표계로 변환하는 행렬을 만들어주는 함수

Variable

  • pi: 우리가 잘 아는 3.141592... 를 정의한 상수

몇 번 써본 익숙한 함수들이라 구현 자체는 어렵지 않았다. 하지만 몇 가지 헷갈리는 부분도 있었다.

 

그 중 하나는 scale, translate, rotate는 변환 행렬을 반환하는지, 아니면 매개변수로 받은 행렬에 변환을 적용해 반환하는지에 대한 의문이었다. 이 의문을 해결하기 위해 실제 glm 함수를 실행해봤다. 그 결과 glm 함수들은 첫 번째 매개변수로 준 행렬 뒤에 변환 행렬을 곱해 반환해줬고, 이를 그대로 따라 구현했다.

 

 rotate 함수의 변환 방식에 대해서도 한 번 찾아보았다. 내가 42 서울 과제 FDF에서 사용했던 오일러 변환이 아니라, 특정 축에 대해 theta만큼 회전하는 축-각 변환을 사용한다는 것을 알게 되었다. 오일러 변환은 짐벌락(Gimbal Lock) 문제가 발생할 수 있다는 점에서 잘 안 쓰이는 게 맞는 듯하다.

 

 이렇게 나만의 GLM인 glmath 라이브러리를 만들어 보았다. 함수 구현을 하나 마치면 실제 GLM과 비교해 테스트해보고 다음 함수의 구현으로 넘어가는 과정을 거치며 차근 차근 라이브러리를 구현하였다. 지금 문제를 발견하지 않으면 나중에 더 큰 고생을 하게 될 수 있기 때문에, 귀찮지만 꼭 해야 하는 과정이었다.

 강의를 들으며 glm 라이브러리를 사용할 때는 다 이해하며 사용한다 생각했는데, 직접 구현해보니 완전히 이해하지 못한 부분도 있었다. 확실히 직접 구현하면서 배우는 점이 많은 것 같다.

 다음에는 텍스처를 어떻게 가져올 것인지에 대해 생각해보는 시간을 가져볼 것이다.

 

#ifndef GLMATH_H
# define GLMATH_H

# include <stdexcept>
# include <cmath>

namespace glmath{

constexpr float pi = 3.14159f;

class vec2 {
private:

public:
	float x;
	float y;

	vec2();
	vec2(float x);
	vec2(float x, float y);
	vec2(const vec2& copy);
	vec2& operator=(const vec2& copy);
	vec2 operator+(const vec2& rhs) const;
	vec2 operator-(const vec2& rhs) const;
	vec2 operator*(const vec2& rhs) const;
	float& operator[](int idx);
	float operator[](int idx) const;
};

class vec3 {
private:

public:
	float x;
	float y;
	float z;

	vec3();
	vec3(float x);
	vec3(float x, float y, float z);
	vec3(const vec3& copy);
	vec3& operator=(const vec3& copy);
	vec3 operator+(const vec3& rhs) const;
	vec3 operator-(const vec3& rhs) const;
	vec3 operator*(const vec3& rhs) const;
	float& operator[](int idx);
	float operator[](int idx) const;
};

class vec4 {
private:

public:
	float x;
	float y;
	float z;
	float w;

	vec4();
	vec4(float x);
	vec4(float x, float y, float z, float w);
	vec4(const vec4& copy);
	vec4& operator=(const vec4& copy);
	vec4 operator+(const vec4& rhs) const;
	vec4 operator-(const vec4& rhs) const;
	vec4 operator*(const vec4& rhs) const;
	float& operator[](int idx);
	float operator[](int idx) const;
};

class mat4 {
private:

public:
	vec4 data[4];

	mat4();
	mat4(float x);
	mat4(const vec4& c1, const vec4& c2, const vec4& c3, const vec4& c4);
	mat4(const mat4& copy);
	mat4& operator=(const mat4& copy);
	mat4 operator+(const mat4& rhs) const;
	mat4 operator-(const mat4& rhs) const;
	mat4 operator*(const mat4& rhs) const;
	vec4& operator[](int idx);
	vec4 operator[](int idx) const;
};

vec2 operator*(float scalar, const vec2& vector);
vec2 operator*(const vec2& vector, float scalar);

vec3 operator*(float scalar, const vec3& vector);
vec3 operator*(const vec3& vector, float scalar);

vec4 operator*(float scalar, const vec4& vector);
vec4 operator*(const vec4& vector, float scalar);
vec4 operator*(const mat4& matrix, const vec4& vector);

mat4 operator*(float scalar, const mat4& matrix);
mat4 operator*(const mat4& matrix, float scalar);

float* value_ptr(vec2& vector);
float* value_ptr(vec3& vector);
float* value_ptr(vec4& vector);
float* value_ptr(mat4& matrix);

float dot(const vec2& vector1, const vec2& vector2);
float dot(const vec3& vector1, const vec3& vector2);
float dot(const vec4& vector1, const vec4& vector2);
vec3 cross(const vec3& vector1, const vec3& vector2);

vec2 normalize(const vec2& vector);
vec3 normalize(const vec3& vector);
vec4 normalize(const vec4& vector);

float radians(float degree);

mat4 scale(const mat4& matrix, const vec3& vector);
mat4 translate(const mat4& matrix, const vec3& vector);
mat4 rotate(const mat4& matrix, float theta, const vec3& vector);
mat4 perspective(float fovy, float aspect, float zNear, float zFar);
mat4 lookAt(vec3 cameraPos, vec3 cameraTarget, vec3 cameraUp);

}

#endif



관련글 더보기