Picking
Picking
-
마우스 클릭을 통해 Object를 고를 때 사실 화면에서 보여지는 것은 2D로 변환된 Screen Space이다.
-
따라서 우린 Ray Casting을 사용해 레이저를 쏘듯 카메라에서 Object까지 가상의 선을 그어 Object와의 HIT여부를 검사한다.
-
Collider Component를 만들어 Ray cast 충돌 검사에 사용한다.
shared_ptr<GameObject> SceneManager::Pick(int32 screenX, int32 screenY)
{
shared_ptr<Camera> camera = GetActiveScene()->GetMainCamera();
float width = static_cast<float>(GEngine->GetWindow().width);
float height = static_cast<float>(GEngine->GetWindow().height);
Matrix projectionMatrix = camera->GetProjectionMatrix();
// ViewSpace에서 Picking 진행
float viewX = (+2.0f * screenX / width - 1.0f) / projectionMatrix(0, 0);
float viewY = (-2.0f * screenY / height + 1.0f) / projectionMatrix(1, 1);
Matrix viewMatrix = camera->GetViewMatrix();
Matrix viewMatrixInv = viewMatrix.Invert();
auto& gameObjects = GET_SINGLE(SceneManager)->GetActiveScene()->GetGameObjects();
float minDistance = FLT_MAX;
shared_ptr<GameObject> picked;
for (auto& gameObject : gameObjects)
{
if (gameObject->GetCollider() == nullptr)
continue;
// ViewSpace에서의 Ray 정의
Vec4 rayOrigin = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
Vec4 rayDir = Vec4(viewX, viewY, 1.0f, 0.0f);
// WorldSpace에서의 Ray 정의
rayOrigin = XMVector3TransformCoord(rayOrigin, viewMatrixInv);
rayDir = XMVector3TransformNormal(rayDir, viewMatrixInv);
rayDir.Normalize();
// WorldSpace에서 연산
float distance = 0.f;
if (gameObject->GetCollider()->Intersects(rayOrigin, rayDir, OUT distance) == false)
continue;
if (distance < minDistance)
{
minDistance = distance;
picked = gameObject;
}
}
return picked;
}
-
스크린의 높이와 너비와 마우스의 클릭 위치를 가져와 ViewSpace에서 Picking을 한다.
-
World Space에서 충돌검사를 하기 위해 view Matrix의 역행렬을 이용해 View Space에서의 Ray를 WorldSpace로 변환.
-
WorldSpace에서 Ray와 Collider사이의 충돌 여부 계산.
결과
- 디버깅을 통해 구체가 클릭되면 HIT ! 이 출력되게 설정하였다.
Author And Source
이 문제에 관하여(Picking), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@sansam41/Picking저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)