Computer Graphics/OpenGL

OpenGL 정리 - 10. GLM을 이용한 선형 변환

surkim 2024. 9. 13. 15:42

GLM을 이용한 선형 변환

GLM(OpenGL Mathematics)을 사용해 선형 변환을 처리하는 방법을 다뤄보겠다. OpenGL에서 물체의 위치, 크기, 방향을 조정하는 데 필수적인 수학적 연산을 GLM을 통해 쉽게 구현할 수 있다. 이번 예제는 점을 변환하는 과정을 통해 GLM의 기본 기능을 살펴볼 것이다.


GLM을 사용한 벡터 및 행렬 연산

OpenGL에서 물체의 위치나 방향을 변경하려면 벡터와 행렬을 이용한 선형 변환을 사용해야 한다. GLM은 이를 쉽게 처리할 수 있도록 다양한 연산 함수를 제공한다.

다음 코드는 GLM을 사용하여 평행이동, 회전, 확대 등의 변환을 적용한 예시이다.

// 위치 (1, 0, 0)의 점. 동차 좌표계 사용
glm::vec4 vec(1.0f, 0.0f, 0.0f, 1.0f);

// 단위행렬 기준 (1, 1, 0)만큼 평행이동하는 행렬
auto trans = glm::translate(glm::mat4(1.0f), glm::vec3(1.0f, 1.0f, 0.0f));

// 단위행렬 기준 z축으로 90도만큼 회전하는 행렬
auto rot = glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));

// 단위행렬 기준 모든 축에 대해 3배율 확대하는 행렬
auto scale = glm::scale(glm::mat4(1.0f), glm::vec3(3.0f));

// 확대 -> 회전 -> 평행이동 순으로 선형 변환 적용
vec = trans * rot * scale * vec;

SPDLOG_INFO("transformed vec: [{}, {}, {}]", vec.x, vec.y, vec.z);

위의 코드에서는 세 가지 변환이 적용되었다:

  1. 평행이동: (1, 1, 0)만큼 물체를 이동
  2. 회전: z축을 기준으로 90도 회전
  3. 확대: 각 축에 대해 3배로 크기 확대

이러한 변환을 순차적으로 적용한 후, 변환된 좌표를 출력한다. trans * rot * scale의 순서대로 행렬이 적용되며, 그 결과는 (0.9999999, 4, 0)이 된다.


정점 변환 (Vertex Transformation)

정점에 대한 변환은 OpenGL의 vertex shader에서 처리된다. 물체의 정점은 VBO(Vertex Buffer Object)에 저장되어 있으며, 변환은 vertex shader를 통해 이루어진다. 변환 행렬을 uniform 변수로 셰이더에 전달하고, 그 행렬을 사용하여 정점에 변환을 적용한다.

다음은 vertex shader에서 변환 행렬을 적용하는 방법이다:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;

uniform mat4 transform;

out vec4 vertexColor;
out vec2 texCoord;

void main() {
    gl_Position = transform * vec4(aPos, 1.0);
    vertexColor = vec4(aColor, 1.0);
    texCoord = aTexCoord;
}

위 셰이더에서 uniform mat4 transform은 변환 행렬을 받아서 정점의 위치에 적용하는데, 이 행렬은 OpenGL 프로그램에서 glUniformMatrix4fv 함수를 통해 전달된다.


변환 행렬 전달하기

Context::Init() 함수에서 변환 행렬을 생성하고, 이를 셰이더에 전달하는 코드이다. 이 예시에서는 물체를 0.5배 축소한 후, z축을 기준으로 90도 회전하는 변환을 적용했다.

auto transform = glm::rotate(
    glm::scale(glm::mat4(1.0f), glm::vec3(0.5f)),
    glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f)
);
auto transformLoc = glGetUniformLocation(m_program->Get(), "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));

이 코드는 GLM을 이용하여 변환 행렬을 만든 후, 그 값을 셰이더의 transform uniform 변수에 전달한다.