GameChoi
Choi Programming
GameChoi
전체 방문자
오늘
어제
  • 분류 전체보기 (468)
    • C++ Algorithm & Study (184)
      • C++ & Algorithm Strategies (45)
      • Game Math & DirectX 11 (72)
      • Server + UE5 (29)
      • Lyra Clone Coding (37)
    • Create Game (284)
      • [Window API] Game Client & .. (55)
      • [DirectX] DirectX 2D & 3D (155)
      • [UE5] BLUEPRINT & C++ (74)
    • odds and ends (0)
      • English (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • Player State
  • Algorithm Strategies
  • Direct11
  • Game Room
  • protobuf
  • server
  • GAME Client
  • client
  • Game Server
  • UE5
  • Direct3D
  • Network Worker
  • core
  • Player Move Packet
  • RPG Game
  • c++
  • job queue
  • session
  • Other Character
  • Destination Move Packet

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
GameChoi

Choi Programming

[Direct11] 34. 3D Direct Application - Picking System
C++ Algorithm & Study/Game Math & DirectX 11

[Direct11] 34. 3D Direct Application - Picking System

2023. 6. 27. 17:52

1. 3D Direct Application

1.1 Picking Algorithm

1.1.1 Picking

 - 2차원 화면 좌표가 주어졌을  때, 점으로 투영된 3차원 물체를 알아내는 것

   - 3차원 공간을 2차원 화면 공간으로 변환하고 화면 공간을 다시 3차원 공간으로 변환

     - 2차원 화면의 한 점이 3차원 공간의 점에 고유하게 대응되지 않음

       - 즉 2차원 화면 점으로 투영될 수 있는 3차원 점이 여러개 일 수 있음

 - 위에 따라 사용자가 실제로 선택한 것이 어떤 물체인지 결정하는데 있어 약간의 애매모호함이 존재

   - 보통의 경우 카메라에서 가장 가까운 물체를 사용

 - 카메라의 시점에서 부터 어떠한 점 P에 클릭된 지점

   - 시점에서 점 P를 통과시키는 Ray를 쏘면 자신이 투영된 영역에 P가 포함되는 어떤 물체와 교차

     - 물체가 여러개 일 경우 카메라에서 가장 가까운 것을 물체로 선택, 교차하는 물체가 없는 경우도 존재

1.1.2 Viewport to Projection

 - 클릭된 화면의 점을 정규화된 장치 좌표(NDC)로 변환

   - 뷰포트 행렬은 정점을 정규화된 장치 좌표에서 화면 공간으로 변환

typedef struct D3D11_VIEWP0RT;

   - 일반적으로 게임의 경우 뷰포트는 후면 버퍼 전체에 해당, 깊이 버퍼의 깊이 값은 0에서 1까지 사용

 - 점 P는 NDC 공간의 한 점이라고 생각 후 화면 공간으로 변환

   - 화면 공간으로 변환하기 위해 뷰포트 행렬과의 곱을 통해 2차원 화면 점 R을 알 수 있게 됨

     - 점 R을 사용하여 점 P의 좌표를 구할 수 있게 되는데, 점 P로부터 Ray를 쏘려면 시야 공간 좌표가 필요 

      - 투영된 점을 시야 공간에서 NDC공간으로 변환할 때 x 성분의 종횡비 r로 나눔

        - 다시 시야 공간으로 돌아가려면 NDC의 x 성분에 종횡비를 곱하면 시야 공간 좌표가 나오게 됨

 - 투영 창과 원점 사이의 거리 d, 수직 사이각 α를 이용하여 시야 공간의 좌표를 구할 수 있음

1.1.2.1 C++ 응용 프로그램

void PickingDemo::Pick(int32 sx, int32 sy);

 - 위의 방식을 응용 프로그램에서 사용

   - 카메라의 투영 행렬을 이용하여 시야 공간에서 Ray를 계산

XMMATRIX P = _camera.Proj(); Matrix m = P;
float vx = (+2.0f * sx / _clientWidth - 1.0f) / m(0, 0);
float vy = (-2.0f * sy / _clientHeight + 1.0f) / m(1, 1);

   - 이 후 시야 공간의 Ray를 정의, 시야 공간의 원점에서 시작하여 위에서 구한 점까지의 Ray를 생성

XMVECTOR rayOrigin = ::XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f);
XMVECTOR rayDir = ::XMVectorSet(vx, vy, 1.0f, 0.0f);

1.1.3 Ray to World & Local Space

 - 위를 통해 시야 공간의 Ray를 구할 수 있게 되었지만 물체도 시야 공간에 있을 때만 유용

   - 시야 행렬은 기하구조를 세계 공간에서 시야 공간으로 변환하므로 역행렬을 통해 세계 공간으로 변환

 - 세계 공간의 Ray는 일부 물체들이 세계 공간을 기준으로 정의되어 있는 상황에서 유용

   - 대부분의 경우 물체의 기하구조는 물체 자신의 국소 공간을 기준으로 정의

     - Ray와 물체 교차 판정을 하기 위해 세계 공간의 Ray를 국소 공간으로 변환

 - 물체의 메시를 세계 공간으로 변호나해서 세계 공간의 Ray를 통해 교차 판정을 수행할 수 있지만 비용이 비쌈

1.1.3.1 C++ 응용 프로그램

void PickingDemo::Pick(int32 sx, int32 sy);

 - 카메라의 시야 행렬을 이용하여 세계 공간의 행렬로 변환

XMMATRIX V = _camera.View(); XMVECTOR D1 = ::XMMatrixDeterminant(V);
XMMATRIX invView = ::XMMatrixInverse(&D1, V);

 - 세계 공간의 행렬을 이용하여 국소 공간의 행렬로 변환

XMMATRIX W = ::XMLoadFloat4x4(&_meshWorld); XMVECTOR D2 = ::XMMatrixDeterminant(W);
XMMATRIX invWorld = ::XMMatrixInverse(&D2, W);

   - 위 두가지를 이용하여 시야 행렬에서 국소 공간으로의 변환 수행

     - 시야공간의 Ray를 물체의 국소 공간의 좌표계로 변환 및 교차 판정을 위해 Ray의 방향 벡터를 정규화

XMMATRIX toLocal = ::XMMatrixMultiply(invView, invWorld);
rayOrigin = ::XMVector3TransformCoord(rayOrigin, toLocal);
rayDir = ::XMVector3TransformNormal(rayDir, toLocal);
rayDir = ::XMVector3Normalize(rayDir);

1.1.4 Ray to Mesh

 - 레이와 메시가 같은 공간에 있다면 실제로 교차하는 지 판정

   - 모든 메시와의 삼각형들을 훑으면서 각 삼각형에 대해 교차 판정 수행

     - 여러가지가 교차한다면 카메라와 가장 가까운 것을 선택

1.1.4.1 C++ 응용 프로그램

void PickingDemo::Pick(int32 sx, int32 sy);

 - Ray가 메시의 경계상자와 교차하는 경우에만 메시 삼각형에 대해 교차 판정 수행

   - 경계상자와 교차하지 않는다면 메시와 교차할 가능성이 없음

_pickedTriangle = -1; float tmin = 0.0f;
if (_meshBox.Intersects(rayOrigin, rayDir, tmin)) { /* 교차 판정 수행 */ };

   - 삼각형의 Index, Vertex를 사용하여 삼각형안에 Ray가 포함되는지 확인

     - 포함되는 삼각형이 많은 경우 카메라와의 거리를 통해 가장 거리가 가까운 것을 선택

Distancemin = MathHelper::Infinity;
for (UINT i = 0; i < _meshIndices.size() / 3; ++i)
{
    UINT i0 = _meshIndices[i * 3 + 0];
    UINT i1 = _meshIndices[i * 3 + 1];
    UINT i2 = _meshIndices[i * 3 + 2];

    XMVECTOR v0 = ::XMLoadFloat3(&_meshVertices[i0].pos);
    XMVECTOR v1 = ::XMLoadFloat3(&_meshVertices[i1].pos);
    XMVECTOR v2 = ::XMLoadFloat3(&_meshVertices[i2].pos);
    
    float Distance = 0.0f;
    if (TriangleTests::Intersects(rayOrigin, rayDir, v0, v1, v2, Distance))
        if (Distance < Distancemin) { Distancemin = Distance;  _pickedTriangle = i; }
}

1.2 Picking System

1.2.1 C++ 응용 프로그램

 - 사용자는 오른쪽 마우스 버튼을 클릭하여 메시의 한 삼각형을 선택

   - 삼각형의 Index를 멤버 변수를 통해 저장해 두고 렌더링을 할 때 다른 삼각형들과 다르게 색상 변경

 - 먼저 같은 삼각형을 두번 그리는 것이므로 <=로 변경하여 삼각형이 깊이 판정을 통과하도록 설정

_deviceContext->OMSetDepthStencilState(RenderStates::LessEqualDSS.Get(), 0);

 - 삼각형을 미리만들어둔 색상으로 변경하고 쉐이더 적용

   - 삼각형 하나만 그리는 것이므로 선택된 삼각형에 해당하는 Index를 사용하여 그리고 깊이 버퍼를 복원

Effects::BasicFX->SetMaterial(_pickedTriangleMat);
activeMeshTech->GetPassByIndex(p)->Apply(0, _deviceContext.Get());
_deviceContext->DrawIndexed(3, 3 * _pickedTriangle, 0);
_deviceContext->OMSetDepthStencilState(0, 0);
저작자표시 (새창열림)

'C++ Algorithm & Study > Game Math & DirectX 11' 카테고리의 다른 글

[Direct11] 36. 3D Direct Application - Dynamic Cube Mapping System  (0) 2023.06.27
[Direct11] 35. 3D Direct Application - Cube Mapping System  (0) 2023.06.27
[Direct11] 33. 3D Direct Application - Instancing & Culling  (0) 2023.06.26
[Direct11] 32. 3D Direct Application - Camera  (0) 2023.06.26
[Direct11] 31. EX App Program - Quad Tesselation  (0) 2023.06.22
    'C++ Algorithm & Study/Game Math & DirectX 11' 카테고리의 다른 글
    • [Direct11] 36. 3D Direct Application - Dynamic Cube Mapping System
    • [Direct11] 35. 3D Direct Application - Cube Mapping System
    • [Direct11] 33. 3D Direct Application - Instancing & Culling
    • [Direct11] 32. 3D Direct Application - Camera
    GameChoi
    GameChoi

    티스토리툴바