※ 본 포스팅은 learnopengl.com을 번역 및 가감한 포스팅이며, learnopengl에서는 번역 작업 참여를 적극 장려하고 있습니다!
아래 링크에서 원문을 확인할 수 있습니다.
Mouse input
요(yaw)와 피치(pitch)값은 마우스를 움직일 때도 나옵니다. 마우스를 수평으로 움직이면 요, 수직으로 움직이는 피치값이 영향받죠. 기본적으로는 이전 프레임 마우스 위치를 저장한 후 현재 프레임 마우스 위치와의 차를 통해 변위를 구하는 겁니다.
우선 GLFW에 커서를 숨기고 캡처(capture)하도록 명령합니다. 커서를 캡처한다는 게 뭐냐면 애플리케이션이 포커싱되면, 마우스 커서가 창의 중심에 유지되는 걸 말합니다. FPS 게임을 해보신 분이라면 이게 어떤 현상을 말하는지 쉽게 이해하실 겁니다. 이걸 설정해줍니다.
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
이렇게 설정하면 마우스를 움직여도 커서가 안보이고 창을 벗어나지도 않습니다. FPS 카메라 시스템이 이렇죠.
이제 피치와 요 값을 계산하기 위해 GLFW에 마우스 움직임 이벤트를 감지하게 합니다. 그러기 위한 콜백 함수를 만듭시다.
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
fly style camera에서 마우스 입력 처리를 할 때 카메라 방향 벡터를 계산하기 위해 아래와 같은 단계를 거칩니다.
1. 이전 프레임 이후 마우스 offset 계산한다
2. offset 값을 카메라의 요와 피치 값에 더한다
3. 피치 값의 최소/최대 값을 제한한다
4. 방향 벡터를 계산한다
첫 단계, 이전 프레임의 마우스 offset을 계산합니다. 애플리케이션에서 마우스 위치 저장을 해야하는데, 처음에는 화면의 중앙으로 설정합시다.(창의 크기는 800x600)
float lastX = 400, lastY = 300;
그 다음 마우스 콜백 함수에서 마우스가 이동한 offset을 계산합니다.
float xoffset = xpos - lastX;
float yoffset = lastY - ypos; // y좌표는 아래에서 위로 향하기 때문에 반대로 계산합니다
lastX = xpos;
lastY = ypos;
const float sensitivity = 0.1f;
xoffset *= sensitivity;
yoffset *= sensitivity;
구한 offset 값에 감도(sensitivity)값을 곱합니다. 감도 값으로 마우스의 움직임 감도를 조정합니다.
그 다음 두 번째 단계, offset 값을 요와 피치에 더해줍니다.
yaw += xoffset;
pitch += yoffset;
세 번째 단계, 카메라의 움직임을 제한합니다. 만약 방향벡터가 world의 up 벡터와 평행하게 되면 LookAt flip이 발생합니다. 그러면 더 위로 혹은 더 아래로 돌리지 못하고 카메라 화면이 반전되며 진동하는 현상이 생기게 됩니다. 그래서 피치는 -89~89도 안쪽으로 제한합니다. 제한한 범위를 넘는 경우는 오일러 값을 사용해서 체크합니다.
if(pitch > 89.0f)
pitch = 89.0f;
if(pitch < -89.0f)
pitch = -89.0f;
수평 회전의 경우는 특별히 요 값의 제한을 하지 않습니다.
네 번째 단계, 이제 실제 방향 벡터를 계산합니다.
glm::vec3 direction;
direction.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
direction.y = sin(glm::radians(pitch));
direction.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
cameraFront = glm::normalize(direction);
이렇게 만든 방향 벡터는 마우스 움직임을 회전으로 바꾼 결과입니다. 이전에는 cameraFront를 사용했지만 이제는 GLM의 lookAt 함수에 포함되어있기 때문에 바로 진행하면 됩니다.
코드를 실행하면 창이 마우스 커서 입력을 처음 받을 때 갑자기 크게 이동하는데요. 이건 커서가 창에 들어올 때 마우스 콜백 함수가 호출되서 현재 마우스의 위치가 바로 전달되면서 중심에서 금방 마우스가 위치 했던 위치까지의 offset만큼 한 번에 이동하게 된 경우입니다. 이 현상을 없애려면 마우스 입력을 처음으로 받는 경우를 체크하면 됩니다. 처음 입력 받으면 초기 마우스 위치는 현재 마우스의 xpos, ypos로 업데이트해줍니다. 그러면 처음 입력 이후 입력된 좌표로 offset을 계산합니다.
if (firstMouse) // 처음에는 true로 설정
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
최종 코드는 이렇습니다.
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
if (firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
float xoffset = xpos - lastX;
float yoffset = lastY - ypos;
lastX = xpos;
lastY = ypos;
float sensitivity = 0.1f;
xoffset *= sensitivity;
yoffset *= sensitivity;
yaw += xoffset;
pitch += yoffset;
if(pitch > 89.0f)
pitch = 89.0f;
if(pitch < -89.0f)
pitch = -89.0f;
glm::vec3 direction;
direction.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
direction.y = sin(glm::radians(pitch));
direction.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
cameraFront = glm::normalize(direction);
}
이제 3D 공간을 자유롭게 이동할 수 있습니다.
'개발 · 컴퓨터공학 > LearnOpenGL' 카테고리의 다른 글
OpenGL Color 색 [Learn OpenGL 쉬운 번역] (6) | 2024.09.07 |
---|---|
OpenGL Camera Zoom 카메라 줌 [Learn OpenGL 쉬운 번역] (21) | 2024.09.06 |
OpenGL Camera Euler Angle 카메라 오일러각 [Learn OpenGL 쉬운 번역] (6) | 2024.09.04 |
OpenGL Camera Movement 카메라 이동 [Learn OpenGL 쉬운 번역] (8) | 2024.09.03 |
OpenGL Camera view 카메라 뷰 LookAt [Learn OpenGL 쉬운 번역] (2) | 2024.09.02 |