왜 물체 이동시 느리게 이동되는거지?
$ ViewMat*ProjMat $ 가 되어야 하는데 반대로 곱함으로써 행렬곱의 계산이 엉뚱하게 되어서 그랬던 것이다.
이동 원리
화면에 마우스 클릭 시 Ray
를 발사해서 물체와 닿은 것을 체크해 물체의 이동 거리를 측정하는 방법이다.
내가 닿은 지점은 pickPoint = cursorWorldNear + dist * dir
이다.
특이한 부분이 하나 있는데, Ratio를 구한다는 것이다. prevRatio = dist / (cursorWorldFar - cursorWorldNear).Length()
파란색 dist
를 구하는 것이 해당 그림의 목표이다. 해당 값을 구해서 이동한 위치를 알아내는 것이다. 해당 식은 비례식을 이용한다.
$$ PrevDist : (PrevCursorWoldFar-PrevCursorWoldNear) = x : (NewCursorWoldFar-NewCursorWoldNear) $$
해당 식을 정리하게 되면, x를 통해서 newPos
의 위치 값을 구할 수 있다.
$$ x = \frac{dist}{PrevViewFrusturmLength} * NewViewFrusturmLength $$
그리고 물체를 클릭한 직후 m_dragStartFlag = false
를 해준다. D3D11은 실시간으로 돌아가기 때문에 바로 else문으로 넘어간다고 보아도 된다. 그렇게 되면 아래와 같은 계산을 수행하게 되는데 prevRatio
뒤에 뷰 프러스텀의 Z축 벡터를 곱하는 이유는 곡선에 대한 위치 값을 벡터로써 넘겨주어야 하기 때문입니다.
Vector3 newPos = cursorWorldNear +
prevRatio * (cursorWorldFar - cursorWorldNear);
Ray가 물체에 닿은 상태의 pos
를 체크 후, 계속 닿고 있는 상태에서 pos
를 갱신해주는 것이다.
GUI를 통해 이동시 생기는 회전 오류
GUI를 통해 이동 시 회전에 대해서 오류가 발생한다. BoundingSphere
도 같이 옮겨주는데 왜 이런 오류가 발생하는걸까?
-> mainObj의 Matrix가 회전 행렬을 지속적으로 업데이트하며 회전에 대해서 구현하는데, GUI로 이동행렬 업데이트 시 단순히, 이동행렬에 대해서만 처리해줘서 회전행렬에 대한 부분이 초기화되었기 때문에 이런현상이 발생하였다.
-> 따라서, mainObj Matrix의 이동행렬을 초기화하고 회전행렬만 남긴상태로 이동값이 담긴 행렬을 곱해주면서 GUI를 통한 이동을 구현하였다.
// Move
Vector3 transition = m_mainObj->m_worldRow.Translation();
m_mainObj->m_worldRow.Translation(Vector3(0.0f));
ImGui::SliderFloat3("Position", &transition.x, -5.0f, 5.0f);
m_mainObj->UpdateWorldRow(m_mainObj->m_worldRow *
Matrix::CreateTranslation(transition));
m_mainBoundingSphere.Center = m_mainObj->m_worldRow.Translation();
회전 원리
https://github.com/microsoft/DirectXTK/wiki/Quaternion
https://github.com/microsoft/DirectXTK/wiki/Matrix
https://github.com/microsoft/DirectXTK/wiki/Vector3
회전을 하기위해서 필요한 재료들?
- Quaternion을 이용할 생각인데, 그렇다면 quaternion을 어떻게 도출해야할까를 생각해야한다.
- 참고문서에 따르면, quaternion을 도출하기 위한 함수로는 3가지가 존재한다.
CreateFromAxisAngle
,CreateFromYawPitchRoll
,CreateFromRotationMatrix
이다. - 먼저, 축과 앵글을 통해서 도출할 수 있다. 이것을 구하기 위해서는 축을 설정할 줄 알아야한다. 마우스를 클릭하고 이동하는 궤적을 통해서 축을 도출해야한다. 앵글도 이러한 방식을 통해서 도출하면 될 것이다.
- 그렇다면, 궤적을 통해서 축은 어떻게 도출해야할까? 내가 클릭한 위치에서 중심까지의 방향 구한 다음 cross 연산을 통해서 축을 도출할 수 있을 것 같다.
- 앵글은 dot연산을 통해서 cos(theta)를 구하고, 여기서 theta를 도출하면 될 것 같다. 그렇다면 cos에서 어떻게 theta를 도출하는가? -> 역코사인 함수를 이용한다.
- c++에서는
std::acos
를 이용하면 된다.
위와 똑같이 했는데, 에러 발생함
그냥, 클릭 시 회전 값 계산이 진행이 되지 않아야 하는데 계산을 계속하면서 오류가 발생하였던 것으로 보임. 왜냐하면, 그냥 클릭 시에도 에러를 발생하였음.
그래서 1e-3을 통해서 위치에 대해 최저값 설정을 해주었더니, 회전이 작동한다.
그런데, 회전이 이상하게 작동함..
내가 마우스로 하는 회전과 반대방향으로 작동한다... 축을 에다가 -
부호를 붙힘으로써 해결하였다.
왜 -
를 붙혀야하는가?
이 부분은 내가 한 계산식으로 인해 발생한 문제이다. dot 연산과 달리 cross연산의 경우, 순서가 중요하다. prevVector가 X축으로 newVector가 Y축이라는 가정을 통해서 Z축을 도출했어야 하는데, 내가 계산을 반대로 하면서 발생한 문제이다.
해당 코드와 같이 작성하면 회전이 정상 작동하는 것을 볼 수 있다.
Vector3 newVector = pickPoint - m_mainBoundingSphere.Center;
newVector.Normalize();
float angle =
std::acos(newVector.Dot(prevVector)) * (180.0 / 3.141592) * 0.1f;
Vector3 axis = prevVector.Cross(newVector);
axis.Normalize();
if ((newVector - prevVector).Length() > 1e-3) {
q = SimpleMath::Quaternion::CreateFromAxisAngle(axis,
angle);
prevVector = newVector;
}
'Graphics' 카테고리의 다른 글
3. Directional Shadow Mapping (0) | 2024.06.21 |
---|---|
2. Depth Buffer와 안개 효과 (1) | 2024.06.14 |
[D3D11] 사각형 및 육면체 그리기 (0) | 2024.05.20 |
1. Blinn Phong 모델 (0) | 2024.05.14 |
Texture 사용하기 (0) | 2024.05.14 |