강의

https://inf.run/Ju6ZN

 

학습 페이지

 

www.inflearn.com

 

3D 그래픽스에서 가장 기본적인 구성 단위 중 하나인 Triangle의 Point Test와 Intersection, Raycast에 대해 알아보자 이 삼각형을 통해 우리는 네비게이션 매쉬(갈 수 있는 범위를 정해준다.)와 같은 요소를 만들어 줄 수 있다.

1. Point Test

만약 삼각형을 클릭했을 때 그것을 판별해야한다고 할 때 Point Test를 하게 될 것이다. 이때 삼각형을 구성하는 벡터들을 사용해서 교차 벡터를 계산하고 이들의 내적을 검사해준다. 

// 점이 삼각형 내부에 있는지 판단하는 함수
bool MathUtils::PointInTriangle(const Point3D& p, const Triangle3D& t)
{
	Vec3 a = t.a - p; // 점 p에서 삼각형의 꼭짓점 a로의 벡터
	Vec3 b = t.b - p; // 점 p에서 삼각형의 꼭짓점 b로의 벡터
	Vec3 c = t.c - p; // 점 p에서 삼각형의 꼭짓점 c로의 벡터

	// 삼각형의 각 변에 대해 점 p를 포함하는 평면의 법선 벡터 계산
	Vec3 normPBC = b.Cross(c); // PBC의 법선 벡터 (u)
	Vec3 normPCA = c.Cross(a); // PCA의 법선 벡터 (v)
	Vec3 normPAB = a.Cross(b); // PAB의 법선 벡터 (w)

	// 법선 벡터들의 방향이 모두 같은지 확인하여 점이 삼각형 내부에 있는지 판단
	if (normPBC.Dot(normPCA) < 0.0f)
		return false; // PBC와 PCA 법선 벡터가 서로 반대 방향이면 점은 삼각형 내부에 없음

	else if (normPBC.Dot(normPAB) < 0.0f)
		return false; // PBC와 PAB 법선 벡터가 서로 반대 방향이면 점은 삼각형 내부에 없음

	return true; // 그 외의 경우 점은 삼각형 내부에 있음
}

※벡터 투영

투영은 벡터에서 다른 벡터의 선분을 구하기 위한 함수로 정사영이해서 비율을 알 수 있다.

// 벡터 a를 벡터 b에 투영하는 함수
Vec3 MathUtils::ProjectVecOnVec(Vec3 a, Vec3 b)
{
	b.Normalize(); // 벡터 b를 정규화

	float dist = a.Dot(b); // 벡터 a와 정규화된 벡터 b의 내적 계산

	return b * dist; // 투영된 벡터 반환
}

2. Intersection

충돌 검사는 삼각형을 구성하는 점으로 평면 방정식을 생성하고 이를 통해 충돌과 물리 계산을해주면 된다.

// 삼각형으로부터 평면을 생성하는 함수
Plane3D MathUtils::FromTriangle(const Triangle3D& t)
{
	Plane3D result;

	// 삼각형의 두 변의 벡터를 외적하여 평면의 법선 벡터를 계산
	result.normal = (t.b - t.a).Cross(t.c - t.a);
	result.normal.Normalize(); // 법선 벡터를 정규화

	// 평면의 거리 계산 (법선 벡터와 삼각형의 한 꼭짓점의 내적으로 계산)
	result.distance = result.normal.Dot(t.a);

	return result;
}

3. Raycast

삼각형과 레이케스팅의 충돌 검사는 위의 코드로 만들어준 평면을 통해 교차점을 찾아주면 된다. 

//삼각형 내의 점에 대한 바리센트릭 좌표를 계산
Vec3 MathUtils::Barycentric(const Point3D& p, const Triangle3D& t)
{
	return Vec3();
}

// 레이와 삼각형의 충돌 검사
bool MathUtils::Raycast(const Triangle3D& triangle, const Ray3D& ray, OUT float& distance)
{
	Plane3D plane = FromTriangle(triangle); // 삼각형으로부터 평면 생성

	float t = 0;
	// 레이와 평면의 충돌 검사
	if (!Raycast(plane, ray, OUT t))
		return false; // 충돌하지 않으면 false 반환

	// 충돌 지점 계산
	Point3D result = ray.origin + ray.direction * t;

	// 충돌 지점에 대한 바리센트릭 좌표 계산
	Vec3 barycentric = Barycentric(result, triangle);

	// 바리센트릭 좌표를 사용하여 충돌 지점이 삼각형 내부에 있는지 확인
	if (barycentric.x >= 0.0f && barycentric.x <= 1.0f &&
		barycentric.y >= 0.0f && barycentric.y <= 1.0f &&
		barycentric.z >= 0.0f && barycentric.z <= 1.0f)
	{
		distance = t; 
		return true; 
	}
	return false; // 충돌하지 않음
}

 

+ Recent posts