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 |