OpenGL 쉐이더 프로그래밍 - 2차원 변환

타입·2025년 7월 24일

컴퓨터 그래픽스

목록 보기
14/24

2차원 변환

Transformation (변환)

좌표/벡터를 다른 좌표/벡터로 매핑

어파인 변환

1차 함수(Linear Functions)로 제한
평행 이동도 포함되어야 하기에 호모지니어스 좌표 표현 도입
물리 시뮬레이션의 기초

  • 직선을 유지하는 성질
    변환 전에 선분이라면 변환 후에도 선분

  • 선분 전체의 모든 점을 변환할 필요가 없음
    선분은 두 꼭짓점을 이은 것, 선분의 꼭짓점만 변환
    변환한 꼭짓점을 다시 연결하면 선분 전체가 변환된 것과 동일함

  • Rigid Body (강체)
    형태가 고정된 물체
    회전/평행이동 가능

  • Non-Rigid Body
    물체의 크기/모양에 변화 가능
    스케일링/기울임

2D 기본 변환

2D 스케일링

물체의 크기를 확대하거나 축소하는 연산

모든 점들에 동일한 scaling matrix 적용

2D 쉬어링

물체를 기울이는 연산

  • 2D Horizontal Shear
    주어진 x좌표에 y좌표와 비례하는 값을 더하면, 원점에서 멀어질 수록 x축 방향으로 기울어짐

  • 2D Vertical Shear
    y축 방향으로 기울어짐

2D 회전

원점을 기준으로 좌표를 회전하는 연산

CCW(반시계방향)으로 회전
시계방향으로 θ만큼 회전 시, 반시계방향으로 -θ만큼 회전 (= 2π-θ)

2D 평행이동

주어진 좌표를 벡터만큼 이동

행렬로 표현하기 위해 호모지니어스 좌표 도입

3D 호모지니어스 좌표

  • 3D 좌표
    = 4D 호모지니어스 좌표
    (x,y,z) -> (x,y,z,1) = (wx,wy,wz,w)
  • 4D 좌표
    = 3D 호모지니어스 좌표
    (x,y) -> (x,y,1) = (wx,wy,w)

2D 어파인 변환 = 3D 행렬(3x3) 연산

2D 변환의 합성

회전 후 평행이동 연산의 행렬식
여러 연산을 미리 계산하여 합성하면 순서대로 연산한 것과 같은 결과가 나옴

행렬 곱셈의 순서

변환 행렬은 매핑 과정이라 곱셈 순서에 따라 다른 결과가 나옴

회전 후 평행이동과 평행이동 후 회전은 전혀 다른 연산 결과가 나타남

Pivot Point 기준의 회전

2D 회전은 원점 중심으로 회전해버림
Pivot: 회전 중심이 되는 고정점

  1. Pivot Point를 원점으로 평행이동
  2. 원점을 기준으로 회전
  3. 원점을 다시 Pivot Point로 평행이동

orbit 프로그램

원형 궤도를 도는 우주선을 그리는 프로그램
우주선의 방향은 바뀌어야 함

  • vertex shader 프로그램
    uMat 행렬에 회전 후 평행이동 행렬식 적용 (OpenGL은 3D이므로 4x4 행렬 사용)
#version 330 core

in vec4 aPos; // vertex position: attribute
in vec4 aColor; // vertex color: attribute
out vec4 vColor; // varying color: varying
uniform mat4 uMat; // matrix: uniform

void main(void) {
	gl_Position = uMat * aPos; // transformation
	gl_Position.z *= -1.0F; // negation
	vColor = aColor;
}
  • vertex 배열
    우주선은 삼각형 하나로 표현
glm::vec4 vertPos[] = { // small triangle
	{ 0.0F, 0.1F, 0.0F, 1.0F }, // v0
	{ -0.1F, -0.1F, 0.0F, 1.0F }, // v1
	{ 0.1F, -0.1F, 0.0F, 1.0F }, // v2
};

glm::vec4 vertColor[] = { // all red
	{ 1.0F, 0.3F, 0.3F, 1.0F, },
	{ 1.0F, 0.3F, 0.3F, 1.0F, },
	{ 1.0F, 0.3F, 0.3F, 1.0F, },
};
  • updateFunc()
    mat행렬에 회전 후 평행이동 행렬식 저장
// 단위행렬
GLfloat mat[16] = {
	1.0F, 0.0F, 0.0F, 0.0F,
	0.0F, 1.0F, 0.0F, 0.0F,
	0.0F, 0.0F, 1.0F, 0.0F,
	0.0F, 0.0F, 0.0F, 1.0F,
};

const float radius = 0.6F;
float theta = 0.0F;
system_clock::time_point lastTime = system_clock::now();

void updateFunc(void) {
	// update the rotation angle
	system_clock::time_point curTime = system_clock::now();
	milliseconds elapsedTimeMSEC = duration_cast<milliseconds>(curTime - lastTime); // in millisecond
	theta = (elapsedTimeMSEC.count() / 1000.0F) * (float)M_PI; // 2초당 1회전
    
	// calculate the matrix
	mat[0] = cosf(theta); mat[4] = -sinf(theta);
	mat[1] = sinf(theta); mat[5] = cosf(theta);
	mat[12] = radius * cosf(theta);
	mat[13] = radius * sinf(theta);
}
  • drawFunc()
    uniform register의 uMat에 mat 행렬값 대입
void drawFunc(void) {
	...
	GLuint locMat = glGetUniformLocation(prog, "uMat");
	glUniformMatrix4fv(locMat, 1, GL_FALSE, mat); // false면 열 우선방식으로 저장
    
	glDrawArrays(GL_TRIANGLES, 0, 3);
    ...
}

원 궤도를 그리며 움직이는 삼각형이 출력

profile
언리얼 프로그래머

0개의 댓글