🎨DirectX

[DX] 지면의 높이 구하기 2 (D3DXIntersectTri 함수), Raycast/Picking

공대 컴린이 2023. 2. 6. 10:47
728x90

🎢 지면의 높이 구하기 2

저번에는 같은 크기의 그리드 지면에서 높이를 구하는 방법을 공부하였다.

이번에는 정규화되어있지 않고 서로 다른 크기의 그리드 지면에서 높이를 구하는 방법을 알아보자.

🚩 D3DXIntersectTri 

지면의 크기가 다른 경우에는 "삼각형 충돌"을 이용하여 높이를 구할 수 있다.

먼저 "반직선" "삼각형 충돌"의 수식이 필요하다. 해당 수식은 D3DXIntersectTri 함수를 이용하여 구할 수 있다.

D3DXIntersectTri 함수는 "Start" 지점과 충돌을 검출할 "방향(Direction)"이 필요하다.

 

직선은 시작지점과 끝지점이 모두 정해져있는 선분을 말하고, 반직선은 시작지점은 존재하고, 어느 방향으로 나갈지 방향만이 존재하고 끝지점이 정해져있지 않은 선분이다.

따라서 방향은 플레이어방향에서 지면으로 위에서 아래로 가는 방향이 일반적이니 방향을 (0, -1, 0)으로 설정한다.

 

D3DXIntersectTri 함수를 사용하면 플레이어가 위치한 삼각형의 위치를 구해낼 수 있다.

또한 삼각형에서 얼마만큼 비율로 움직였는지를 반환해주기 때문에, 저번 시간에 구한 높이 구하는 방법에 필요했던 모든 요소를 함수 하나로 해결할 수 있게된다.

함수 성분

  • p0 : 첫 번째 삼각형의 꼭짓점 위치
  • p1 : 두 번째 삼각형의 꼭짓점 위치
  • p2 : 세 번째 삼각형의 꼭짓점 위치
  • pRayPos : 광선이 시작되는 지점을 지정
  • pRayDire : 광선의 방향을 지정
  • pU : uv중 Raycast에 충돌된 삼각형의 u값 초기화
  • pV : uv중 Raycast에 충돌된 삼각형의 v값 초기화
  • pDist : 광선 교차 매개 변수 거리
  • 반환값 : 광선(Raycast)이 삼각형 영역과 교차하는 경우 TRUE를 반환, 그렇지 않으면 FALSE를 반환
  • 사용 수식 : V1 + U(V2 - V1) + V(V3 - V1).

💡 총정리

결과적으로 이전 방법과 지금 방법은 같은 결과를 보이지만,이전에 공부했던 지면의 높이 구하기 방법은 플레이어가 이동 지점으로부터 얼마만큼의 위치 비율을 이동했는지 구한 뒤, 그 비율을 이용하여 높이를 구했다면, 이번에 공부한 내용은 함수를 사용하여 플레이어가 위치한 삼각형과 충돌을 검사해서 높이를 구할 수 있고, 삼각형의 크기가 일정하지 않아도 정상적으로 높이를 구할 수있다 라는 점이 다르다.

💡 언어 정리

높이를 구하는 이 과정을 Picking이라고도 하고 RayCast라고도 부른다.

Picking은 무언가(플레이어가 위치하는 삼각형)를 선택하겠다 라는 의미이고 RayCast는 반직선을 쏴서 선택하겠다 라는 의미로 둘다 같은 의미이다.


📄 Terrain.cpp (Raycast 함수 부분만 출력)

float Terrain::GetVerticalRaycast(Vector3 & position)
{
	UINT x = (UINT)position.x;
	UINT z = (UINT)position.z;

	if (x < 0 || x > width) return FLT_MIN;
	if (z < 0 || z > height) return FLT_MIN;


	UINT index[4];
	index[0] = width * z + x;
	index[1] = width * (z + 1) + x;
	index[2] = width * z + x + 1;
	index[3] = width * (z + 1) + x + 1;

	Vector3 p[4];
	for (int i = 0; i < 4; i++)
		p[i] = vertices[index[i]].Position;

	Vector3 start(position.x, 50, position.z);
	Vector3 direction(0, -1, 0);

	float u, v, distance;
	Vector3 result(-1, FLT_MIN, -1);

	// TRUE는 bool이 아니라 int형 윈도우API 변수
	// Get Height함수와 다르게 비율로 구하는 것이 아니라 충돌된 삼각형의 UV를 구하는 것이므로
	// 삼각형의 크기가 달라져도 전혀 무리가 없다.
	if (D3DXIntersectTri(&p[0], &p[1], &p[2], &start, &direction, &u, &v, &distance) == TRUE) 
		result = p[0] + (p[1] - p[0]) * u + (p[2] - p[0]) * v; // 왼쪽 삼각형

	if (D3DXIntersectTri(&p[3], &p[1], &p[2], &start, &direction, &u, &v, &distance) == TRUE)
		result = p[3] + (p[1] - p[3]) * u + (p[2] - p[3]) * v; // 오른쪽 삼각형

	return result.y;
}

[ 실행 결과 ]

728x90