โ ์นด๋ฉ๋ผ / ๋ทฐ ๊ณต๊ฐ
์นด๋ฉ๋ผ / ๋ทฐ ๊ณต๊ฐ์ ์ ์ํ๊ธฐ ์ํด์๋ ์๋ ๊ณต๊ฐ์์์ ์นด๋ฉ๋ผ์ ์์น, ์นด๋ฉ๋ผ๊ฐ ๋ฐ๋ผ๋ณด๋ ๋ฐฉํฅ, ์ค๋ฅธ์ชฝ์ ๊ฐ๋ฆฌํค๋ ๋ฒกํฐ, ๊ทธ๋ฆฌ๊ณ ์นด๋ฉ๋ผ์์ ์์ชฝ์ ๊ฐ๋ฆฌํค๋ ๋ฒกํฐ๊ฐ ํ์ํ๋ค.
→ ์นด๋ฉ๋ผ์ ์์น๋ฅผ ์์ ์ผ๋ก ํ๋, ์ธ ๊ฐ์ ์์ง ๋จ์ ์ถ์ผ๋ก ์ขํ๊ณ๋ฅผ ์์ฑํ๋ค.

โ 1. Position (์์น)
์นด๋ฉ๋ผ ์์น๋ ์๋ ๊ณต๊ฐ์์ ์นด๋ฉ๋ผ์ ์์น๋ฅผ ๊ฐ๋ฆฌํค๋ ๋ฒกํฐ์ด๋ค.
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
์์ z์ถ์ด ์ฐ๋ฆฌ ์ชฝ์ ํฅํ๊ณ ์์ผ๋ฏ๋ก ์นด๋ฉ๋ผ๋ฅผ ๋ค๋ก ์ด๋ํ๋ ค๋ฉด ์์ z์ถ์ ๋ฐ๋ผ ์ด๋์ํค๋ฉด ๋๋ค.
โ 2. Direction (๋ฐฉํฅ)
๋ค์์ผ๋ก ํ์ํ ๋ฒกํฐ๋ ์นด๋ฉ๋ผ์ ๋ฐฉํฅ์ด๋ค.
glm::vec3 cameraTarget = glm::vec3(0.0f, 0.0f, 0.0f);
glm::vec3 cameraDirection = glm::normalize(cameraPos - cameraTarget);
์ฌ์ ์์ ๋ฒกํฐ์์ ์นด๋ฉ๋ผ์ ์์น ๋ฒกํฐ๋ฅผ ๋นผ๋ฉด ๋ฐฉํฅ ๋ฒกํฐ๋ฅผ ๊ตฌํ ์ ์๋ค.
ํ์ง๋ง ๋ทฐ ํ๋ ฌ์ ์ขํ๊ณ์์ z์ถ์ด ์์ ๊ฐ์ ๊ฐ์ง๊ฒ ํ๊ธฐ ์ํด, OpenGL์์๋ ์นด๋ฉ๋ผ๋ ์์ z์ถ์ ํฅํ๋ฏ๋ก ๋ฐฉํฅ ๋ฒกํฐ๋ฅผ ๋ฐ์ ์์ผ์ผ ํ๋ค.
๋ฐ๋ผ์ ๋ฒกํฐ๋ฅผ ๋นผ๋ ์์๋ฅผ ๋ฐ๊ฟ ์นด๋ฉ๋ผ์ ์์ z์ถ์ ๊ฐ๋ฆฌํค๋ ๋ฒกํฐ๋ฅผ ๊ตฌํ๋ค.
* ๋ฐฉํฅ ๋ฒกํฐ๋ ์ค์ ๋ก๋ ๋ชฉํ ๋ฐฉํฅ์ ๋ฐ๋๋ฅผ ๊ฐ๋ฆฌํค๊ฒ ๋๋ค.
โ 3. Right Axis (์ค๋ฅธ์ชฝ ๋ฒกํฐ)
glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f);
glm::vec3 cameraRight = glm::normalize(glm::cross(up, cameraDirection));
์ค๋ฅธ์ชฝ ๋ฒกํฐ๋ฅผ ์ป๊ธฐ ์ํด ์๋ ๊ณต๊ฐ์์ ์์ชฝ ๋ฒกํฐ๋ฅผ ๋จผ์ ์ง์ ํ ๋ค์, 2๋จ๊ณ์์ ์ป์ ๋ฐฉํฅ ๋ฒกํฐ์ ์์ชฝ ๋ฒกํฐ์ ์ธ์ (cross product)์ ๊ตฌํ๋ค. ์ธ์ ์ ๊ฒฐ๊ณผ๋ ๋ ๋ฒกํฐ์ ๋ชจ๋ ์์ง์ธ ๋ฒกํฐ๋ก, ์์ x์ถ ๋ฐฉํฅ์ ๊ฐ๋ฆฌํค๋ ๋ฒกํฐ๋ฅผ ์ป์ ์ ์๋ค. (์ธ์ ์์๋ฅผ ๋ฐ๊พธ๋ฉด ์์ x์ถ์ ๊ฐ๋ฆฌํจ๋ค)
โ 4. Up Axis (์์ชฝ ๋ฒกํฐ)
glm::vec3 cameraUp = glm::cross(cameraDirection, cameraRight);
๋ง์ฐฌ๊ฐ์ง๋ก ์ค๋ฅธ์ชฝ ๋ฒกํฐ์ ๋ฐฉํฅ ๋ฒกํฐ๋ฅผ ์ธ์ ํ์ฌ ์นด๋ฉ๋ผ์ ์์ y์ถ์ ๊ฐ๋ฆฌํค๋ ๋ฒกํฐ๋ฅผ ๊ตฌํ๋ค.
์ฌ๊ธฐ๊น์ง ๋ทฐ / ์นด๋ฉ๋ผ ๊ณต๊ฐ์ ๊ตฌ์ฑํ๋ ๋ชจ๋ ๋ฒกํฐ๋ฅผ ์์ฑํ์๋ค. (์ด ๊ณผ์ ์ ์ ํ ๋์ํ์์ ๊ทธ๋-์๋ฏธํธ(Gram-Schmidt) ๊ณผ์ ์ผ๋ก ์๋ ค์ ธ ์๋ค)
์ด๋ฌํ ์นด๋ฉ๋ผ ๋ฒกํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์นด๋ฉ๋ผ๋ฅผ ์์ฑํ๋ ๋ฐ ๋งค์ฐ ์ ์ฉํ LookAt ํ๋ ฌ์ ๋ง๋ค ์ ์๋ค.
โ Look At
ํ๋ ฌ์ ์ข์ ์ ์ 3๊ฐ์ ์์ง(๋๋ ๋น์ ํ) ์ถ์ ์ฌ์ฉํ์ฌ ์ขํ ๊ณต๊ฐ์ ์ ์ํ๋ฉด, ์ด 3๊ฐ์ ์ถ๊ณผ Translation (์ด๋) ๋ฒกํฐ๋ฅผ ์ด์ฉํด ํ๋ ฌ(= Look At ํ๋ ฌ)์ ์์ฑํ ์ ์๋ค๋ ๊ฒ์ด๋ค.
์ด ํ๋ ฌ๊ณผ์ ๊ณฑ์ ์ ํตํด ๋ฒกํฐ๋ฅผ ํด๋น ์ขํ ๊ณต๊ฐ์ผ๋ก ๋ณํํ ์ ์๋ค. ๋ฐ๋ก ์ด๊ฒ์ด LookAt ํ๋ ฌ์ด ํ๋ ์ผ์ด๋ค.

์ฌ๊ธฐ์ 'R'์ ์ค๋ฅธ์ชฝ ๋ฒกํฐ, 'U'๋ ์์ชฝ ๋ฒกํฐ, 'D'๋ ๋ฐฉํฅ ๋ฒกํฐ, 'P'๋ ์นด๋ฉ๋ผ์ ์์น ๋ฒกํฐ๋ฅผ ๋ํ๋ธ๋ค. ํ์ ํ๋ ฌ์ด ์ ์น(Transpose)๋๊ณ ์ด๋ ํ๋ ฌ์ด ๋ถ์ (Negate)๋ ์ด์ ๋ ์ฐ๋ฆฌ๊ฐ ์นด๋ฉ๋ผ๋ฅผ ์ด๋ํ๊ณ ์ ํ๋ ๋ฐฉํฅ์ ๋ฐ๋ ๋ฐฉํฅ์ผ๋ก ์๋๋ฅผ ํ์ ํ๊ณ ๋ณํํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ด๋ค.
์ด LookAt ํ๋ ฌ์ ๋ทฐ ํ๋ ฌ๋ก ์ฌ์ฉํ๋ฉด ๋ชจ๋ ์๋ ์ขํ๋ฅผ ์ฐ๋ฆฌ๊ฐ ์ ์ํ ๋ทฐ ๊ณต๊ฐ์ผ๋ก ๋ณํํ ์ ์๋ค. LookAt ํ๋ ฌ์ ์ฃผ์ด์ง ๋์์ ๋ฐ๋ผ๋ณด๋ ๋ทฐ ํ๋ ฌ์ ์์ฑํ๋ค.
๋คํํ ์ฐ๋ฆฌ๋ ์นด๋ฉ๋ผ ์์น, ํ๊ฒ ์์น, ์๋ ๊ณต๊ฐ์์ ์์ชฝ ๋ฒกํฐ(์ค๋ฅธ์ชฝ ๋ฒกํฐ๋ฅผ ๊ณ์ฐํ ๋ ์ฌ์ฉํ ์์ชฝ ๋ฒกํฐ)๋ฅผ ๋ํ๋ด๋ ๋ฒกํฐ๋ง ์ง์ ํ๋ฉด GLM์ด LookAt ํ๋ ฌ์ ์๋์ผ๋ก ์์ฑํ์ฌ ๋ทฐ ํ๋ ฌ๋ก ์ฌ์ฉํ ์ ์๋ค.
glm::mat4 view;
view = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glm::lookAt ํจ์๋ ๋งค๊ฐ๋ณ์๋ก Position(์์น), Target(ํ๊ฒ), Up Vector(์์ชฝ ๋ฒกํฐ)๋ฅผ ํ์๋ก ํ๋ค.
โ ์นด๋ฉ๋ผ ํ์ ํ๊ธฐ
์ฌ์ ํ๊ฒ์ (0, 0, 0)์ ๊ณ ์ ํ๋ค. ์ฝ๊ฐ์ ์ผ๊ฐ๋ฒ์ ์ฌ์ฉํ์ฌ ์ ์์ ํ ์ ์ ๋ํ๋ด๋ x ๋ฐ z ์ขํ๋ฅผ ๋งค ํ๋ ์๋ง๋ค ์์ฑํ๊ณ , ์ด๋ฅผ ์นด๋ฉ๋ผ ์์น๋ก ์ฌ์ฉํ ๊ฒ์ด๋ค. ์๊ฐ ๊ฒฝ๊ณผ์ ๋ฐ๋ผ x์ z ์ขํ๋ฅผ ๋ค์ ๊ณ์ฐํ๋ฉด ์ ์์ ๋ชจ๋ ์ ์ ์ํํ๊ฒ ๋์ด ์นด๋ฉ๋ผ๊ฐ ์ฌ ์ฃผ์๋ฅผ ํ์ ํ๊ฒ ๋๋ค.
์ด ์์ ํฌ๊ธฐ๋ฅผ ๋ฏธ๋ฆฌ ์ ์๋ ๋ฐ์ง๋ฆ์ผ๋ก ํ์ฅํ๊ณ , GLFW์ glfwGetTime ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๋งค ํ๋ ์๋ง๋ค ์๋ก์ด ๋ทฐ ํ๋ ฌ์ ์์ฑํ๋ค.
const float radius = 10.0f;
float camX = sin(glfwGetTime()) * radius;
float camZ = cos(glfwGetTime()) * radius;
glm::mat4 view;
view = glm::lookAt(glm::vec3(camX, 0.0, camZ), glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0));
- ๊ฒฐ๊ณผ
์นด๋ฉ๋ผ๊ฐ ์์ ์ ์ค์ฌ์ผ๋ก ๋ฐ๋ผ๋ณด๋ฉฐ ์ฌ ์ฃผ์๋ฅผ ํ์ ํ๋ค.
โ ์นด๋ฉ๋ผ ์ด๋ํ๊ธฐ
์นด๋ฉ๋ผ ์์คํ ์ ์ค์ ํ๊ธฐ ์ํด ์นด๋ฉ๋ผ ๋ณ์๋ค์ ์ ์ํ๋ค.
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
๋ฐฉํฅ์ ์นด๋ฉ๋ผ์ ํ์ฌ ์์น์ ๋ฐฉํฅ ๋ฒกํฐ๋ฅผ ๋ํ ๊ฐ์ด๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์นด๋ฉ๋ผ๊ฐ ์ด๋ํ๋๋ผ๋ ํญ์ ๋ชฉํ ๋ฐฉํฅ์ ํฅํ๋๋ก ์ ์ง๋๋ค.
const float cameraSpeed = 0.05f;
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
cameraPos += cameraSpeed * cameraFront;
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
cameraPos -= cameraSpeed * cameraFront;
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
WASDํค๋ฅผ ์ด์ฉํ์ฌ ์นด๋ฉ๋ผ์ ์์น๋ฅผ ์กฐ์ ํ๋๋ก ํ๋ค.
* ์ธ์ ํ์ฌ ๋์จ ์ค๋ฅธ์ชฝ ๋ฒกํฐ๋ฅผ ์ ๊ทํํ๋ ์ด์ ๋ cameraFront ๋ณ์์ ํฌ๊ธฐ์ ๋ฐ๋ผ ํฌ๊ธฐ๊ฐ ๋ฌ๋ผ์ง ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
โ ์ด๋ ์๋ ์กฐ์ (deltaTime)
ํ์ฌ Input์ ํ๋ ์๋ง๋ค ์ ์ฉํ์ฌ ์ด๋น ๋ง์ ํ๋ ์์ ๋ ๋ํ๊ฒ ๋๋ฉด ์ด๋ ์๋๊ฐ ๋นจ๋ผ์ง๋ค.
์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ๋ณดํต 'deltaTime' ๋ณ์, ์ฆ ๋ง์ง๋ง ํ๋ ์์ ๋ ๋๋งํ๋๋ฐ ๊ฑธ๋ฆฐ ์๊ฐ์ ๊ณฑํ์ฌ ์ฌ์ฉํ๋ค. ํ ํ๋ ์์ ๋ ๋ํ๋๋ฐ ์ค๋๊ฑธ๋ฆฌ๋ฉด ๊ทธ ๋งํผ ์๋๋ฅผ ์ฆ๊ฐ์์ผ ๊ท ํ์ ๋ง์ถ๋ค.
float deltaTime = 0.0f;
float lastFrame = 0.0f;
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
ํ์ฌ ํ๋ ์๊ณผ ๋ง์ง๋ง ํ๋ ์์ ๋ณ์๋ก ์ ์ธํ์ฌ deltaTime์ ๊ณ์ฐํ๋ค.
float cameraSpeed = 2.5f * deltaTime;
์ดํ ์๋๋ฅผ ๊ณ์ฐํ ๋ deltaTime์ ๊ณฑํด์ค๋ค.
โ ๋ง์ฐ์ค๋ฅผ ์ด์ฉํ์ฌ ๋๋ฌ๋ณด๊ธฐ
์ฌ์ ๋๋ฌ๋ณด๊ธฐ ์ํด์ ๋ง์ฐ์ค ์
๋ ฅ์ ๋ฐ๋ผ cameraFront ๋ฒกํฐ๋ฅผ ์์ ํด์ผ ํ๋ค. ํ์ง๋ง ๋ง์ฐ์ค ํ์ ์ ๋ฐ๋ผ ๋ฐฉํฅ ๋ฒกํฐ๋ฅผ ๋ณ๊ฒฝํ๋ ๊ฒ์ ๋ณต์กํ๊ณ , ์ผ๊ฐ๋ฒ(Trigonometry)์ ๋ํ ์ง์์ด ํ์ํ๋ค.
โ Euler Angle (์ค์ผ๋ฌ ๊ฐ)
์ค์ผ๋ฌ ๊ฐ์ ๊ฐ์ฒด(rigid body)๊ฐ ๋์ธ ๋ฐฉํฅ์ 3์ฐจ์ ๊ณต๊ฐ์ ํ์ํ๊ธฐ ์ํด ์ค์ผ๋ฌ๊ฐ ๋์ ํ ์ธ ๊ฐ์ ๊ฐ๋์ด๋ค. ์ค์ผ๋ฌ ๊ฐ์๋ Pitch, Yaw, Roll 3๊ฐ์ ๊ฐ๋๊ฐ ์๋ค.

Pitch๋ ์ํ ๊ฐ๋๋ฅผ, Yaw๋ ์ข์ฐ ๊ฐ๋๋ฅผ, Roll์ ํ์ ๊ฐ๋๋ฅผ ๋ํ๋ธ๋ค. ๊ฐ๊ฐ์ ์ค์ผ๋ฌ ๊ฐ์ ๋จ์ผ ๊ฐ์ผ๋ก ํํ๋๋ฉฐ, ์ด ์ธ ๊ฐ์ง ๊ฐ์ ์กฐํฉํ์ฌ 3์ฐจ์์์์ ๋ชจ๋ ํ์ ๋ฒกํฐ๋ฅผ ๊ณ์ฐํ ์ ์๋ค.
ํ์ฌ ์ฐ๋ฆฌ์ ์นด๋ฉ๋ผ ์์คํ
์์๋ Pitch์ Yaw๊ฐ๋ง ๊ฐ์ง๊ณ ์๋ก์ด ๋ฐฉํฅ ๋ฒกํฐ๋ฅผ ๋ํ๋ด๋ 3D ๋ฒกํฐ๋ก ๋ณํํ ๊ฒ์ด๋ค.
- Yaw
3D ์ฌ์ ์์์ (y์ถ์ ๋ฐ๋ผ) ๋ด๋ ค๋ค๋ณธ๋ค๊ณ ์๊ฐํ๋ฉด ์ผ๊ฐํ์ ๋ ๋ณ์ด x์ถ๊ณผ z์ถ์ ํํํ๊ฒ ๋๋ค.

๋น๋ณ์ ๊ธธ์ด๋ฅผ 1๋ก ์ค์ ํ์ ๋, x์ถ ๊ธฐ์ค ๋ฐ์๊ณ ๋ฐฉํฅ์ผ๋ก Yaw ๊ฐ๋๋ฅผ ์ค์ ํ๋ฉด x์ถ ๋ณ์ ๊ธธ์ด๋ cos(Yaw)๊ฐ ๋๊ณ , z์ถ ๋ณ์ ๊ธธ์ด๋ sin(Yaw)๊ฐ ๋๋ค.
glm::vec3 direction;
// ๊ฐ๋๋ฅผ ๋จผ์ ๋ผ๋์์ผ๋ก ๋ณํํ๋ ์ ์ ์ ์
direction.x = cos(glm::radians(yaw));
direction.z = sin(glm::radians(yaw));
์ด๋ฅผ ์ด์ฉํด ์นด๋ฉ๋ผ ๋ฐฉํฅ ๋ฒกํฐ๋ฅผ ์์ฑํ๋ค. (ํ์ฌ Pitch๊ฐ์ ํฌํจ๋์ด ์์ง ์์)
- Pitch
์ด์ ์ฐ๋ฆฌ๊ฐ xz ํ๋ฉด์์ y์ถ์ ๋ฐ๋ผ๋ณธ๋ค๊ณ ์๊ฐํ๋ฉด ์ผ๊ฐํ์ ๋ ๋ณ์ด xzํ๋ฉด๊ณผ y์ถ์ ํํํ๊ฒ ๋๋ค.

๋ง์ฐฌ๊ฐ์ง๋ก y์ถ ๋ณ์ ๊ธธ์ด๋ sin(Pitch)๊ฐ ๋๋ค. ๋ํ xzํ๋ฉด์ ๋ณ์ด cos(Pitch)์ ์ํฅ์ ๋ฐ์ผ๋ฏ๋ก ์ต์ข ๋ฐฉํฅ ๋ฒกํฐ์ ํฌํจ์์ผ์ผ ํ๋ค.
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));
์ด๋ ๊ฒ Yaw์ Pitch๊ฐ์ 3์ฐจ์ ๋ฐฉํฅ ๋ฒกํฐ๋ก ๋ณํํ์๋ค.
- ๋ณด์
์ฐ๋ฆฌ๋ ์ฌ์ ๋ชจ๋ ๊ฒ์ด ์์ z์ถ ๋ฐฉํฅ์ผ๋ก ์์นํ๋๋ก ์ธํ ํ๋ค. ํ์ง๋ง x์ถ๊ณผ z์ถ์ ์ผ๊ฐํ์ ๋ณด๋ฉด Yaw ๊ฐ๋๊ฐ 0์ผ ๋ ์นด๋ฉ๋ผ์ ๋ฐฉํฅ ๋ฒกํฐ๊ฐ ์์ x์ถ์ ๊ฐ๋ฆฌํค๊ฒ ๋๋ค. ์นด๋ฉ๋ผ๊ฐ ๋ํดํธ ๊ฐ์ผ๋ก ์์ z์ถ์ ๋ฐ๋ผ๋ณด๊ฒ ํ๋ ค๋ฉด Yaw ๊ฐ์ ์๊ณ ๋ฐฉํฅ์ผ๋ก 90๋ ํ์ ์์ผ์ผ ํ๋ค.
// ์๊ณ ๋ฐฉํฅ์ผ๋ก ํ์ ํ๋ ค๋ฉด ์์ ๊ฐ์ ํ ๋น
yaw = -90.0f;
โ Mouse Input (๋ง์ฐ์ค ์ ๋ ฅ)
์ํ ๋ง์ฐ์ค ์์ง์์ Yaw ๊ฐ์ ์ํฅ์ ์ฃผ๊ณ ์์ง ๋ง์ฐ์ค ์์ง์์ Pitch ๊ฐ์ ์ํฅ์ ์ค๋ค.
๊ธฐ๋ณธ ์์ด๋์ด๋ ์ง๋ ํ๋ ์์ ๋ง์ฐ์ค ์์น๋ฅผ ์ ์ฅํ๊ณ ํ์ฌ ํ๋ ์์์ ๋ง์ฐ์ค ๊ฐ์ด ์ผ๋ง๋ ๋ณ๊ฒฝ๋์๋์ง ๊ณ์ฐํ์ฌ ์นด๋ฉ๋ผ๋ฅผ ์ด๋์ํจ๋ค.
- ์ธํ
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
๋จผ์ ๋ง์ฐ์ค ์ปค์๋ฅผ ๋ณด์ด์ง ์๊ฒ ํ๊ณ ์ฐฝ์ ์ค์์ ๋จธ๋ฌผ๋๋ก ํ๋ค.
Pitch์ Yaw๋ฅผ ๊ณ์ฐํ๊ธฐ ์ํด GLFW์๊ฒ ๋ง์ฐ์ค ์์ง์ ์ด๋ฒคํธ๋ฅผ ๊ฐ์งํ๋๋ก ์ง์ํด์ผ ํ๋ค. ์ด๋ฅผ ์ํด ๋ค์๊ณผ ๊ฐ์ ํ๋กํ ํ์ ์ ๊ฐ์ง ์ฝ๋ฐฑ ํจ์๋ฅผ ์ ์ธํ๋ค.
// xpos์ ypos๋ ๋ง์ฐ์ค ์์น๋ฅผ ๋ํ๋ธ๋ค.
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
์ฝ๋ฐฑ ํจ์๋ฅผ GLFW์ ๋ฑ๋กํ์ฌ ๋ง์ฐ์ค๊ฐ ์์ง์ผ ๋ ๋ง๋ค mouse_callback ํจ์๊ฐ ํธ์ถ๋๋๋ก ํ๋ค.
// ์ฝ๋ฐฑ ํจ์ ๋ฑ๋ก
glfwSetCursorPosCallback(window, mouse_callback);
- ์ ๋ ฅ ์ฒ๋ฆฌ
์นด๋ฉ๋ผ์ ๋ฐฉํฅ ๋ฒกํฐ๋ฅผ ์์ ํ ๊ณ์ฐํ๊ธฐ ๋ค์ ๋จ๊ณ๋ฅผ ์ํํ๋ค
1. ์ง๋ ํ๋ ์ ์ดํ ๋ง์ฐ์ค์ ์คํ์
์ ๊ณ์ฐํ๋ค.
2. ์คํ์
๊ฐ์ ์นด๋ฉ๋ผ์ Yaw์ Pitch๊ฐ์ ๋ํ๋ค.
3. ํผ์น ๊ฐ์ ์ต์/์ต๋ ์ ํ์ ์ถ๊ฐํ๋ค.
4. ๋ฐฉํฅ ๋ฒกํฐ๋ฅผ ๊ณ์ฐํ๋ค.
โ 1. ๋ง์ฐ์ค ์คํ์ ๊ณ์ฐ
๋จผ์ ๋ง์ฐ์ค์ ๋ง์ง๋ง ์์น๋ฅผ ์ ์ฅํ ๋ณ์๋ฅผ ์ ์ธํ๋ค. (์ด๊ธฐ๊ฐ์ ํ๋ฉด์ ์ค์ฌ ์ขํ๋ก ์ค์ )
// ํ๋ฉด ํฌ๊ธฐ๊ฐ 800 * 600 ์ผ ๋
float lastX = 400, lastY = 300;
๊ทธ๋ฆฌ๊ณ ๋ง์ฐ์ค ์ฝ๋ฐฑ ํจ์์์ ํ๋ ์ ์ฌ์ด์ ๋ง์ฐ์ค ์คํ์ ์ ๊ณ์ฐํ๋ค.
float xoffset = xpos - lastX;
// y์ขํ๋ ๋ฐ์
float yoffset = lastY - ypos;
lastX = xpos;
lastY = ypos;
const float sensitivity = 0.1f;
xoffset *= sensitivity;
yoffset *= sensitivity;
* ๋ง์ฐ์ค ์ ๋ ฅ์์ y์ขํ๋ ํ๋ฉด์ ์๋์ชฝ์์ ์์ชฝ์ผ๋ก ๋ฒ์๊ฐ ์ค์ ๋์ด ์์ผ๋ฏ๋ก, ๋ง์ฐ์ค์ ์์ง ์ด๋์ ์ฒ๋ฆฌํ ๋ y์ขํ์ ๋ฐฉํฅ์ ๋ฐ์ ์์ผ์ผ ํ๋ค.
โ 2. Yaw์ Pitch ๊ฐ์ ์คํ์ ์ ์ฉ
๋ค์์ผ๋ก ์ ์ญ ๋ณ์๋ก ์ ์ธ๋ Yaw์ Pitch ๊ฐ์ ์คํ์ ๊ฐ์ ๋ํ๋ค.
yaw += xoffset;
pitch += yoffset;
โ 3. Pitch ๊ฐ ์ ํ
์ฌ์ฉ์๊ฐ 89๋ ์ด์(90๋์์ LookAt ํ๋ฆฝ์ด ๋ฐ์ํจ) ๋๋ -89๋ ์ดํ๋ก ๋ณผ ์ ์๋๋ก ์ ์ฝ์ ์ถ๊ฐํ๋ค.
if(pitch > 89.0f)
pitch = 89.0f;
if(pitch < -89.0f)
pitch = -89.0f;
โ 4. ๋ฐฉํฅ ๋ฒกํฐ ๊ณ์ฐ
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);
๊ณ์ฐ๋ ๋ฐฉํฅ ๋ฒกํฐ๋ ๋ง์ฐ์ค์ ์์ง์์ผ๋ก๋ถํฐ ๊ณ์ฐ๋ ๋ชจ๋ ํ์ ์ ํฌํจํ๊ฒ ๋๋ค.
- ์ด๊ธฐ ๋ง์ฐ์ค ์์น ๋ณด์
์ฒ์ ๋ง์ฐ์ค ์ปค์๊ฐ ์ฐฝ์ ๋ค์ด์ค๋ฉด, ๋ง์ฐ์ค ์ฝ๋ฐฑ ํจ์๊ฐ xpos์ ypos ์์น๋ฅผ ์ปค์๊ฐ ํ๋ฉด์ ๋ค์ด์จ ์์น๋ก ํธ์ถํ๋ค. ์ด ์์น๋ ์ข ์ข ํ๋ฉด์ ์ค์์์ ์๋นํ ๋ฉ๋ฆฌ ๋จ์ด์ ธ ์๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ ํฐ ์คํ์ ์ด ๋ฐ์ํ๊ณ ๊ฒฐ๊ณผ์ ์ผ๋ก ํฐ ์ด๋ ์ ํ๊ฐ ๋ฐ์ํ๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ฒซ ๋ง์ฐ์ค ์
๋ ฅ์ด๋ผ๋ฉด ์ด๊ธฐ ๋ง์ฐ์ค ์์น๋ฅผ ์๋ก์ด xpos์ ypos ๊ฐ์ผ๋ก ์
๋ฐ์ดํธํ์ฌ ์๋ก ๋ค์ด์จ ๋ง์ฐ์ค ์์น ์ขํ๋ก ์คํ์
์ ๊ณ์ฐํ๋๋ก ํ๋ค.
- ์ต์ข ๋ง์ฐ์ค ์ฝ๋ฐฑ ํจ์
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
// firstMouse ์ด๊ธฐ๊ฐ์ true
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);
}
โ ์นด๋ฉ๋ผ ์ค (Zoom)
FOV (์์ผ๊ฐ) ๊ฐ์ ์กฐ์ ํ์ฌ ์ค ํจ๊ณผ๋ฅผ ๊ตฌํํ ๊ฒ์ด๋ค. ๋ง์ฐ์ค์ ์คํฌ๋กค ํ ๋ก FOV ๊ฐ์ ์กฐ์ ํ๊ธฐ ์ํด ๋ง์ฐ์ค ์คํฌ๋กค์ ์ํ ์ฝ๋ฐฑ ํจ์๋ฅผ ์์ฑํ๋ค.
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
fov -= (float)yoffset;
// fov ๊ฐ ์ ํ
if (fov < 1.0f)
fov = 1.0f;
if (fov > 45.0f)
fov = 45.0f;
}
์ ์ธํ ๋ง์ฐ์ค ์คํฌ๋กค ์ฝ๋ฐฑ ํจ์๋ฅผ GLFW์ ๋ฑ๋กํ๋ค.
// ์ฝ๋ฐฑ ํจ์ ๋ฑ๋ก
glfwSetScrollCallback(window, scroll_callback);
โ ์์ค ์ฝ๋
- ๋ฉ์ธ (์นด๋ฉ๋ผ ํด๋์ค ์ฌ์ฉํ ๋ฒ์ )
- ์นด๋ฉ๋ผ ํด๋์ค
https://learnopengl.com/code_viewer_gh.php?code=includes/learnopengl/camera.h
'๐จ Graphics > ๐ต OpenGL' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [OpenGL] ๋จธํฐ๋ฆฌ์ผ (Material) (0) | 2024.08.12 |
|---|---|
| [OpenGL] Phong ์กฐ๋ช ๋ชจ๋ธ (0) | 2024.08.12 |
| [OpenGL] ์์ผ๊ฐ(FOV), ํ๋ฉด๋น(Aspect Ratio) (0) | 2024.08.08 |
| [OpenGL] 3์ฐจ์ ๊ฐ์ฒด ๋ ๋ 2 (0) | 2024.08.08 |
| [OpenGL] 3์ฐจ์ ๊ฐ์ฒด ๋ ๋ 1 (0) | 2024.08.02 |