벡터, 내적, 외적, 행렬은 생략
그래픽스 변환
강체 변환(rigifbody transformation)
이동변환 + 회전변환
모습은 불변
유사변환(similarity transformation)
강체변환 + 균등크기조절변환 + 반사변환
물체사이의 각이 유지
물체내부 정점간의 거리가 일정한 비율로 유지
어파인 변환(affine transformation)
- 유사변환 + 차등 크기조절 + 전단 : 물체의 타입이 유지, 변환행렬의 마지막 행이 (0, 0, 0, 1)
원근 변환(perspective transformation)
- 평행선이 만남, 소실점에서 만남, 마지막행이 (0, 0, 0, 1) 이 아님
선형 변환(linear transformation)
- 어파인 + 원근 : 선형조합으로 표시되는 변환
비선형변환
Scaling matrix
- 비균일 스케일, 차등 크기조절(non-uniform)의 예시인 위 사진은 x축으로 0.5, y축으로 2 스케일링한것
균일 스케일, 균등 크기조절(uniform) 은 모든 축이 동일한 스케일링
스케일 변환 행렬은 단위 행렬에 각 대각 요소가 대응하는 벡터 요소와 곱해진 것과 같다.
Translation
벡터를 이동하는 행렬
단위 벡터에 이동할만큼 맨 끝 열에 추가
동차좌표계의 장점이 돋보임
Rotation
https://www.youtube.com/watch?v=gxUcgc88tD4&list=PL8327DO66nu9qYVKLDmdLW_84-yE4auCR&index=12
1
2
3
4
Most rotation functions require an angle in radians, but luckily degrees are easily converted to radians:
angle in degrees = angle in radians * (180 / PI)
angle in radians = angle in degrees * (PI / 180)
Where PI equals (rounded) 3.14159265359.
3d 공간에서의 회전은 각 그리고 회전축을 사용한다.
주어진 회전축에 대해 회전시키는것
삼각법을 사용하여 주어진 각에 대해 벡터를 회전하여 새로운 벡터로 변환하는것
sin , cos 의 조합 (싸코 공식)
회전행렬을 사용하면 위치 벡터를 세가지 축 중 하나에 대해 변환시킬 수 있다.
여러 회전을 조합할 수 있음 (하지만 Gimbal lock 문제가 일어날 수 있음)
회전 행렬을 조합하는 것 대신 임의의 단위 축을 중심으로 즉시 회전하는것이 더 바람직함
밑은 회전축이 (Rx, Ry, Rz) 일 경우의 회전행렬(완벽히 gimbal lack을 예방하지 못함)
완전히 안전한것은 사원수(quaternions)를 사용하여 회전하는것
Combining Matrices
여러 변환 행렬을 조합해서 사용할 수 있다는것은 행렬의 장점중 하나이다.
곱의 교환법칙이 성립하지 않으므로 곱하는 순서를 정하는것이 중요하다.
가장 오른쪽에 있는 행렬이 벡터와 처음 곱해짐.
GLM 사용
1
2
3
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
0.9.9 버전 부터 초기화된 기본행렬이 단위행렬이 아니고 0으로 초기화됨
다음 함수를 사용하여 단위행렬로 초기화해야함.
1
glm::mat4 mat = glm::mat4(1.0f)
translate
동차좌표계를 사용하고 있다는것을 주의해야한다.
(1, 1, 0) 만큼 이동시키는 예
1
2
3
4
5
glm::vec4 vec(1.0f, 0.0f, 0.0f, 1.0f);
glm::mat4 trans;
trans = glm::translate(trans, glm::vec3(1.0f, 1.0f, 0.0f));
vec = trans * vec;
std::cout << vec.x << vec.y << vec.z << std::endl;
rotate, scale
1
2
3
glm::mat4 trans = glm::mat4(1.0f);
trans = glm::rotate(trans, glm::radians(90.0f), glm::vec3(0.0, 0.0, 1.0));
trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5));
rotate = (0.0, 0.0, 1.0)
: z축을 기준으로 회전 (x, y평면이기 때문)- 중심으로 돌리기 위한 축은 반드시 단위벡터여야함. 정규화 필수.
scale = (0.5, 0.5, 0.5)
: 균등 크기조절, 2배 작개- GLM 함수에 행렬을 전달하기 때문에, 서로곱한 결과로 모든 변환이 조합된 행렬이 리턴
shader에서 변환행렬 가져오기
1
2
3
4
5
6
7
8
9
10
11
12
13
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
uniform mat4 transform;
void main()
{
gl_Position = transform * vec4(aPos, 1.0f);
TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}
glsl mat4 타입으로 uniform으로 선언한다음, 각 연산에 vertex pos에 곱해줌
스칼라-행렬 곱, 행렬-벡터 곱, 행렬-행렬 곱 같은 연산 지원해줌
uniform 설정
1
2
unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
glUniformMatrix4fv
파라미터 1 : location
파라미터 2 : 행렬의 개수
파라미터 3 : column-major ordering : GLM의 기본행렬 레이아웃인 내부행렬 레이아웃을 사용,
- 행과 열을 바꿀 필요가 없음, false로 지정
파라미터 4 : 실제 행렬 데이터, value_ptr함수를 사용하여 행렬을 변환해서 타입을 맞춤.
1
reinterpret_cast<float*>(&trans) == glm::value_ptr(trans) == &trans[0][0]
reinterpret_cast: 모든 포인터 타입간의 형변환을 허용.(static_cast는 오직 상속관계의 포인터 끼리만, 컴파일 시간에 캐스팅 완료), 이전 값에 대한 바이너리를 유지(타입에 따라 출력되는 값이 다를 수 있음, 값만 달라질 뿐)
제자리 회전, 이동
1
2
3
glm::mat4 trans;
trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f));
trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));
- 실제 변환순서는 거꾸로 읽어야한다. (정점을 기준으로 제일먼저 곱해져 변환이 행해지는것은 rotate)