24/03/28
40화. Win32API Camera (1)
목표 : Camera 개념을 도입해보자
class CCamera :
카메라의 기본 위치는 화면의 정중앙이다.
왜냐하면 지금까지 카메라가 없음에도 화면상으로 출력하던 위치가 해당 위치이기 때문
또한 카메라가 정중앙에 초점을 두고 있으면, 객체들의 실제 좌표와 렌더링 좌표가 동일하다.
화면의 정중앙은 해상도의 절반을 의미한다. (x,y) = (Resolution.x / 2, Resolution.y / 2)
렌더링 좌표 :
렌더링 좌표는 카메라에 상대적인 좌표이다.
카메라가 오른쪽으로 이동하면 가만히 있던 물체는 상대적으로 왼쪽으로 가는것 처럼 보인다.
때문에 카메라가 이동하면 객체는 카메라가 이동한 거리만큼 바대 방향으로 이동하게된다.
우리가 구현하고 있는 화면상 기준점은 화면의 중심이고 카메라가 화면의 중심좌표로부터 이동한 거리의 반대 방향으로 물체들은 이동하게 될 것이다.
이를 수식화 해보면...
// vLookAt : 카메라의 초점 좌표
// vCenter : 화면의 중심
// vPos : 물체의 좌표
// vRenderPos : 렌더링 좌표
Vec2 vDiff = vLookAt - vCenter;
vRenderPos = vPos - vDiff;
CCamera::CalDiff() :
카메라가 화면의 중심좌표로부터 이동한 거리를 계산해주는 역할을 한다.
매 프레임 카메라의 update() 함수가 호출될 때마다 계산해주며, 계산한 이동거리값은 카메라 클래스의 멤버변수 "m_vDiff" 에 저장한다.
"카메라의 초점 좌표 - 화면의 중심좌표" 를 통해 구하는걸 볼 수 있다.
화면의 중심으로부터 우측하단 (↘) 으로 움직일수록 양(+)의 값이 나오고,
좌측상단(↖) 으로 움직일수록 음(-)의 값이 나온다.
(윈도우 좌표계는 우측으로 갈수록 x 값이 증가하고, 아래로 갈수록 y 값이 증가하는 좌표계이다.)
CCamera::GetRenderPos(Vec2) :
카메라로부터의 상대 좌표... 즉, 렌더링 좌표를 구하기 위해 CCamera::GetRenderPos(Vec2) 함수를 호출한다.
해당 함수를 호출하면 인자로 들어온 좌표값과 카메라의 이동거리 좌표를 계산하여 렌더링 좌표를 반환해준다.
객체들은 카메라의 이동방향과 반대 방향으로 움직이는것 처럼 보이기에 카메라의 이동거리를 객체의 좌표에 빼준다.
참고로 CObject 객체들은 렌더링 좌표를 구하기 위해 항시 CCamera 클래스의 함수를 호출해야하기에 CObject 클래스의헤더어 CCamera 클래스를 포함(#include) 시켜준다.
41화. Win32API Camera (2)
목표 : 객체들이 카메라에 상대적으로 움직이도록 해보기
CObject 클래스의 자식 객체들 렌더 수정 :
CObject 클래스의 자식 객체인 CPlayer, CMonster, CMissile 클래스의 경우 Animator 컴포넌트에 의해 이미지가 출력되고 있다. (Collider 의 경우 자체적으로 출력중)
코드 캡쳐 :


render() 함수에서 최종위치를 CCamera::GetRenderPos() 함수를 활용하여 실제 위치값을 렌더링 좌표로 변환해준다.
카메라 움직여보기 :
카메라에 줄 수 있는 효과 :
카메라 흔들림, 카메라 타겟 변경(부드럽게 화면 전환), etc...
마우스 클릭 이벤트 :
마우스 클릭 이벤트가 발생하면 해당 위치를 카메라의 초점 위치로 잡아준다.
해당 기능을 구현하려면 마우스 클릭 이벤트를 받을수 있도록 설정해줘야한다.
1. 키 매니저(KeyMgr)에 좌클릭, 우클릭에 관련된 가상 키코드와 구조체값을 추가해줌
2. 키 매니저에 마우스 좌표값 받을 수 있도록 멤버와 기능 추가
윈도우 함수 중 현재 마우스 좌표를 얻어올 수 있는 기능을 제공하는 함수가 있다. -> GetCursorPos(LPPOINT);
* windows 에서 타입앞에 "LP"가 붙으면 주소값을 의미한다.
GetCursorPos() 함수의 특징은 마우스의 좌표가 프로그램의 화면 기준이 아니라 내 모티터 화면 기준의 좌표라는 점이다.
때문에 해당 값을 바로 사용할 순 없다. 값 변환을 해줘야한다.
ScreenToClient(HWND, LPPOINT) 함수는 전체 화면에서의 좌표값을 특정 윈도우 기준 좌표로 변환해주는 Windows에서 제공하는 함수다.
이렇게 구해준 마우스 좌표값을 받아올 수 있는 Getter 함수도 CKeyMgr 클래스에 추가해준다.
자주 사용할 예정이니 메크로 등록
42화. Win32API Camera (3)
목표 : 마우스 이벤트를 이용한 카메라 초점 이동
카메라 초점 :
CCamera 클래스에 카메라의 초점 관려 변수를 하나 더 추가해준다.
m_vLookAt, m_vCurLookAt, m_vPrevLookAt ...
PrevLookAt의 경우 변수의 이름이 명확해서 이전 프레임의 초점인건 알겠는데...
LookAt 과 CurLookAt 이라... 무슨 차이인지 처음에 엄청 헷갈렸다.
그림으로도 설명하겠지만, 우선 글로 설명하자면...
LookAt의 경우 새롭게 지정된 카메라의 초점이고 CurLookAt은 새롭게 지정된 초점위치까지 가는 도중의 초점 위치로 해당 값은 LookAt과 같을수도 있고 다를수도 있다.
그림으로 설명하자면 아래와 같다.
이전 프레임까진 Prev 의 위치가 카메라의 초점이었는데 이번 프레임에 새롭게 New 위치가 카메라의 초점이 되었다.
카메라의 초점이 한번에 순간이동 하는게 아니라 자연스럽게 이동하는것 처럼 보이도록 하려고 하기에 Prev -> New 위치로 카메라의 초점이 서서히 이동한다.
이때 목적지 좌표까지 가는 도중의 카메라의 초점이 바로 CurLookAt이 된다.
"CurLookAt == LookAt" 되는 순간 CurLookAt은 LookAt으로 고정된다.
참고로 "fErrValue" 가 존재하는데 이는 오차값을 준거다.
오차값을 조건으로 준 이유는 2가지이다.
- vLookDir 은 두 실수값의 차로 구해진다.
실수값은 정수와 달리 "근사치" 이기에 완벽히 0으로 맞아 떨어지기 힘들다.
때문에 vLookDir 값이 음수와 양수를 왔다갔다 하게되며 이에 따라 카메라가 마구 흔들리게 된다.
이러한 이유로 vLookDir.Length() 값이 어느정도 오차값 범위 안에 들어오면 vCurLookAt 이 vLookAt 값으로 고정되도록 했다. - 또한 우연찮게 vLookAt - m_vPrevLookAt 의 결과가 0.f 로 맞아 떨어진다고 하더라고 문제가 발생한다.
바로 Normalize()를 진행할때 값을 벡터를 "0"으로 나누는 꼴이 된다는 점이다.
이는 무한이라는 결과를 뱉어내는데 해당 연산에 대해 assert() 처리를 해놨다.
assert()가 발생하면 프로그램이 멈추기에 오차값으로 두 값의 차가 0이 나오기전에 끊어주는 역할을 한다.
강의에선 다른 방식으로 구현했지만 난 해당 방법이 더 간단한거 같아서 이렇게 구현했다.
Next Note
Win32API_StudyNote_10
24/03/29
coder-qussong.tistory.com
'Win32API' 카테고리의 다른 글
Win32API_StudyNote_11 (0) | 2024.04.02 |
---|---|
Win32API_StudyNote_10 (0) | 2024.03.29 |
Win32API_StudyNote_8 (0) | 2024.03.25 |
Win32API_StudyNote_7 (0) | 2024.03.25 |
Win32API_StudyNote_6 (0) | 2024.03.24 |