OpenGL

[OpenGL] Transformation(Scaling, rotation, translation)의 결합 순서

usingsystem 2024. 4. 18. 10:28
728x90

※Scaling -> Rotation -> Translation 순서로 오브젝트를 변화하는 것이 가장 좋은 방법이다.

 

Scaling(확대/축소), Rotation(회전), Translation(이동)의 순서는 변환들이 적용되는 순서를 나타냅니다. 일반적으로 변환 순서는 중요한 역할을 합니다. 이 세 가지 변환을 순서대로 적용하는 이유는 다음과 같습니다:

  1. Scaling(확대/축소):
    • 먼저 Scaling을 적용하는 것은 객체의 크기를 조절하기 위해 기준을 설정하는 단계입니다. Scaling을 적용하기 전에 객체의 크기를 결정하고, 그 크기를 기준으로 나머지 변환을 적용할 수 있습니다.
  2. Rotation(회전):
    • Scaling 이후에 Rotation을 적용하는 것은 객체의 크기를 변경하지 않고도 회전할 수 있도록 하기 위함입니다. Scaling을 적용한 후에 회전을 적용하면 회전 중심이 Scaling된 객체의 중심으로 설정됩니다. 이는 보다 자연스러운 회전을 가능하게 합니다.
  3. Translation(이동):
    • 마지막으로 Translation을 적용하는 것은 객체의 위치를 조정하는 단계입니다. Translation은 객체의 위치를 이동시키므로, 이동 후에 다른 변환을 적용하면 이동된 위치에서 해당 변환을 수행하게 됩니다.

※ 앞서말한 오브젝트 변환 순서는 OpenGL에서 함수를 호출 할 때는 적용된 순서의 역순으로 불러야 한다.

OpenGL에서 변환 순서를 Translation, Rotation, Scaling 순으로 적용하는 이유는 주로 수학적인 이유와 OpenGL의 내부 동작 방식 때문입니다.

  1. 수학적 이유:
    • OpenGL에서의 변환은 행렬 연산을 사용합니다. 행렬 곱셈은 순서에 따라 결과가 달라지므로 변환 순서도 중요합니다.
    • OpenGL에서는 변환 행렬을 곱하는데, 행렬 곱셈에서는 우측에 있는 행렬이 좌측에 있는 행렬보다 먼저 적용됩니다.
    • 이러한 행렬 곱셈의 특성 상, 변환을 적용할 때는 오른쪽에서 왼쪽으로 읽는 것과 반대로 변환을 적용해야 합니다.
  2. OpenGL의 내부 동작 방식:
    • OpenGL에서는 변환을 지정한 순서의 역순으로 적용합니다. 즉, 마지막에 지정한 변환이 먼저 적용되고, 처음에 지정한 변환이 마지막에 적용됩니다.
    • 이것은 OpenGL의 변환 스택(stack) 동작 방식에 따라 결정됩니다. OpenGL은 변환 명령을 호출할 때마다 현재 변환 상태를 변환 스택에 저장하고, 그 상태를 곱셈하여 새로운 변환 행렬을 계산합니다. 이때 가장 마지막에 지정한 변환이 먼저 적용됩니다.
glm::mat4 matPyramid = glm::mat4(1.0F);
glm::mat4 matCube = glm::mat4(1.0F);

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

void updateFunc(void) {
	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; // in <math.h>, M_PI_2 = pi/2
	// model transform for the pyramid
	matPyramid = glm::mat4(1.0F);
	matPyramid = glm::translate(matPyramid, glm::vec3(-0.4F, 0.0F, 0.0F));
	matPyramid = glm::rotate(matPyramid, theta, glm::vec3(0.0F, 1.0F, 0.0F));
	matPyramid = glm::scale(matPyramid, glm::vec3(0.5F, 0.5F, 0.5F));
	// model transform for the cube
	matCube = glm::mat4(1.0F);
	matCube = glm::translate(matCube, glm::vec3(0.4F, 0.0F, 0.0F));
	matCube = glm::rotate(matCube, theta, glm::vec3(1.0F, 0.0F, 0.0F));
	matCube = glm::scale(matCube, glm::vec3(0.3F, 0.3F, 0.3F));
}
728x90