오늘의 TIL 목차 (22. 12. 06)
- TimeDelta
- find_if문과 함수 객체
- 뷰 스페이스 변환 행렬 원리
TimeDelta
[ TimeDelta ]
: 시간 평균(주기)로 각 컴퓨터 성능 별 나타나는 시간 주기를 말함.
TimeDelta = 인터벌(간격) / cpu 연산속도(프리퀀시)
메인보드가 갖고 있는 고해상도 타이머의 누적값을 얻어오는 함수
QueryPerformanceCounter(&m_CurrentTime); // 1000
QueryPerformanceCounter(&m_OldTime); // 1020
QueryPerformanceCounter(&m_OriginTime); // 1030
고해상도 타이머의 주파수를 얻어오는 함수, 주파수는 cpu 초당 클럭수 주기를 말함
QueryPerformanceFrequency(&m_CpuTick); // 1,600,000
-> 1초에 실행되는 틱 횟수가 m_pCpuTick에 저장됨 (약 1초에 1,600,000번 틱 실행)
■ TimeDelta를 구하는 이유
성능이 다른 두 컴퓨터
A는 1초당 틱 9회 발생
B는 1초당 틱 3회 발생
* 틱 : 프로그램 전체가 1회 실행되는 것 (=프레임)
Player가 m_vPos += 방향벡터 * 5스피드 로 이동한다 했을 때
A는 1초에 5 * 9인 45를 이동
B는 1초에 5 * 3인 15를 이동
=> 컴퓨터 성능에 따라 다른 결과값이 나타나는 것을 막기 위해 컴퓨터마다 시간 평균(TimeDelta)를 구해
동일한 결과값을 도출해내겠다는 목적
■ 설명
void Engine::CTimer::Update_Timer(void)
{
QueryPerformanceCounter(&m_tFrameTime); // 현재 카운터 받아오기
m_fTimeDelta = ((m_tFrameTime.QuadPart) - (m_tLastTime.QuadPart)) / _float(m_CpuTick.QuadPart);
m_tLastTime = m_tFrameTime; // 현재 카운터를 이전 카운터로 넣어주기
}

[ TimeDelta를 이용해 성능이 다른 두 컴퓨터에 속도 이동에 동일한 결과 도출 ]
A컴퓨터 (TimeDelta : 1/81) // 1초당 틱 9번 실행
m_vPos += 방향벡터 * 5(속도) * 1/81을 1초에 9번 실행
=> 5/81 * 9 = 5/9
B컴퓨터 (TimeDelta : 1/9) // 1초당 틱 3번 실행
m_vPos += 방향벡터 * 5(속도) * 1/9를 1초에 3번 실행
=> 5/9 * 3 = 3/5
=> TimeDelta를 곱해줌으로써 동일한 속도값을 얻을 수 있음
find_if문과 함수객체 연관
[ find_if문 ]
: 컨테이너를 지원하는 함수 (find는 map에서 지원하는 함수)
find_if(begin, end, 조건자);
-> 조건자에는 함수객체 또는 람다식이 들어감
* 함수객체 시 find_if문 자체가 operator()를 자동 호출하면서
알아서 begin ~ end부터 순회한 값이 차근차근 들어감(조건자 true시 해당 iter를 반환)
[ 함수객체 ]
: operator() 함수 오버로딩을 이용하여 객체를 가지고 함수처럼 사용할 수 있는 것
* 함수 객체이므로 객체 생성을 위해 클래스로 존재해야 함
[ 함수 객체 사용법 ]
CTag_Finder Dainn(L"Dainn"); // 매개변수 생성자
Dainn(_pair); // Dainn.operator(_pair);과 동일
*임시 객체로 생성하여 함수 객체 이용
CTag_Finder(L"Dainn")(_pair);
CTag_Finder()(_pair); // 기본 생성자의 경우
class CTag_Finder
{
public:
explicit CTag_Finder(const _tchar* pTag)
: m_pTargetTag(pTag)
{
}
~CTag_Finder() { }
public:
template<typename T>
bool operator()(const T& pair)
{
if (0 == lstrcmpW(m_pTargetTag, pair.first))
{
return true;
}
return false;
}
private:
const _tchar* m_pTargetTag = nullptr;
};
CTimer* Engine::CTimerMgr::Find_Timer(const _tchar* pTimerTag)
{
auto iter = find_if(m_umapTimers.begin(), m_umapTimers.end(), CTag_Finder(pTimerTag));
if (iter == m_umapTimers.end())
return nullptr;
return iter->second;
}
=> CTag_Finder(pTimerTag)는 임시 객체 선언으로 생성자 호출을 한 것.
find_if()가 내부적으로 함수 객체의 operator()을 호출하여 begin ~ end의 _pair을 넘겨주기 때문에
CTag_Finder(pTimerTag)()를 해줄 필요 없이 임시 객체만 적으면 된다.
뷰 스페이스 변환
[ 뷰 스페이스 변환 ]
: 월드 스페이스 -> z축 개념인 카메라가 추가된 뷰 스페이스로 변환
■ 랜더링 파이프라인 과정

로컬 -> 월드 행렬 -> 월드 스페이스 -> 카메라 행렬(뷰 행렬) -> 뷰 스페이스
-> 투영 행렬 (원근 or 직교) -> 투영 -> 뷰 행렬 -> 뷰 포트
* 디바이스->SetTransform(D3DTS_WORLD, &matWorld); 처럼 setTransform은
디바이스에 행렬을 저장하는 함수, 저장된 함수는 마지막에 장치가 알아서 순서대로 곱해준다.
- 세팅 순서는 상관없다는 얘기
■ 카메라 위치/ 방향 - 왼손 좌표계


■ 뷰 스페이스 변환 과정

[ 뷰 스페이스 변환 과정 ]
- 월드 스페이스 내의 카메라를 원점으로 이동시키고 z축도 양의 방향으로 회전시켜야 함
- 카메라의 이동 / 회전과 동일하게 월드 스페이스 내 모든 정점들에게도 이동 / 회전을 적용해야 함
* 정점에 카메라 역행렬을 곱해주면 뷰 스페이스 변환 *
카메라가 원점이고 z축이 양의 방향을 바라보고 있는 상태 = 항등행렬
행렬 * 역행렬 = 항등행렬
-> 우리는 임의의 카메라 행렬을 만들고, 카메라의 역행렬을 구할 것임
-> 구한 역행렬을 월드 스페이스 내 모든 정점들에 곱해주면 뷰 스페이스 변환 완료
■ 카메라 행렬


* 역행렬이 전치행렬인 이유 : 우향, 상향, 전방은 월드 내에서의 카메라 방향을 정의하기 때문에 이 세개의 벡터를 묶어 방위 벡터라고 부름. 방위 벡터는 반드시 정직교여야하고, 벡터들이 정직교가 되기 위해서는 각 벡터가 서로 수직이어야 하며 단위 길이어야 함. 방위 벡터를 행렬의 행에 넣을 것이고, 행 벡터가 정직교라는 것은 행렬이 직교임을 의미함. 직교 행렬은 행렬의 전치와 같은 특성
■ D3DXMatrixLookAtLH
_matrix matCamera; // 카메라 역행렬을 담을 행렬
D3DXMatrixLookAtLH(&matCamera, &vEye, &vAt, &vUp); // 뒤 세 벡터를 이용하여 역행렬을 구해 matCamera에 채워줌
m_pGraphicDev->SetTransform(D3DTS_VIEW, &matCamera); // 카메라 역행렬을 SetTransform에 넣어주면 뷰 스페이스 변환 완료!
■ 기능 / 주의
* 월드 -> 뷰 | 물체들이 월드 공간 상에 있으므로 카메라도 월드 공간 내에 존재
vEye : 위치벡터 - 카메라 월드 공간 상의 위치
vAt : 위치벡터 - 카메라가 바라보고 있는 지점의 위치
vUp : 방향벡터 - 카메라와 수직을 이루고 있는 방향 벡터
=> 카메라는 움직이기 때문에 x, y, z로 표현할 수 없고 가로축을 기준으로 회전한다.
=> 매 프레임마다 카메라를 만들고, 역행렬을 구해 모든 정점에 곱하여 뷰 스페이스 변환을 해줘야 함
'C++' 카테고리의 다른 글
| [TIL41장] 연산자함수 operator function (feat. 전위연산과 후위연산의 차이) (0) | 2024.01.22 |
|---|---|
| [TIL 40장] 변환 함수(ex. to_string, stoi), char과 tchar 관련 함수(ex. append, c_str, wsprintf, lstrcmp), WideCharToMultiByte (0) | 2023.02.26 |
| [TIL 35장] 포물선 공식, 직선의 방정식 (0) | 2022.10.12 |
| [TIL 34장] Win32 API 원리 (feat. 윈도우 초기화) (0) | 2022.09.30 |
| [TIL 33장] R-value 레퍼런스( feat. move() ), 이동 생성자 (0) | 2022.09.26 |