Point Test (수학)

Jaemyeong Lee·2025년 4월 2일

게임 서버1

목록 보기
216/220

📘 1. MathUtils 클래스 생성

먼저 유틸리티 기능을 담당할 MathUtils 클래스를 생성합니다.

  • 위치: Engine/99.Headers/Math/
  • 주요 기능: PointInXXX, ClosestPoint 시리즈
struct MathUtils
{
	static bool PointInSphere(const Point3D& point, const Sphere3D sphere); 
	static Point3D ClosestPoint(const Sphere3D& sphere, const Point3D& point); 

	static bool PointInAABB(const Point3D& point, const AABB3D& aabb);
	static Point3D ClosestPoint(const AABB3D& aabb, const Point3D& point);

	static bool PointInOBB(const Point3D& point, const OBB3D& obb);
	static Point3D ClosestPoint(const OBB3D& obb, const Point3D& point);

	static bool PointOnPlane(const Point3D& point, const Plane3D& plane);
	static Point3D ClosestPoint(const Plane3D& plane, const Point3D& point);

	static bool PointOnLine(const Point3D& point, const Line3D& line);
	static Point3D ClosestPoint(const Line3D& line, const Point3D& point);

	static bool PointOnRay(const Point3D& point, const Ray3D& ray);
	static Point3D ClosestPoint(const Ray3D& ray, const Point3D& point);
};

🎯 2. 점 포함 테스트 (Point-In-Test)

✅ 구 내부 판정 (PointInSphere)

구 내부에 점이 있는지를 판단하려면, 중심과 점 사이의 거리를 구하고 그것이 반지름보다 작거나 같은지를 비교합니다.

bool MathUtils::PointInSphere(const Point3D& point, const Sphere3D sphere)
{
	float distSq = (point - sphere.position).LengthSquared();
	return distSq <= sphere.radius * sphere.radius;
}

✅ 구에서 가장 가까운 표면의 점 (ClosestPoint)

Point3D MathUtils::ClosestPoint(const Sphere3D& sphere, const Point3D& point)
{
	Vec3 dir = (point - sphere.position).Normalized();
	return sphere.position + dir * sphere.radius;
}

✅ AABB 내부 판정 (PointInAABB)

각 축의 최소/최대값 사이에 있는지 체크합니다.

bool MathUtils::PointInAABB(const Point3D& point, const AABB3D& aabb)
{
	Point3D min = AABB3D::GetMin(aabb);
	Point3D max = AABB3D::GetMax(aabb);

	return (point.x >= min.x && point.x <= max.x &&
			point.y >= min.y && point.y <= max.y &&
			point.z >= min.z && point.z <= max.z);
}

✅ AABB에서 가장 가까운 점

Point3D MathUtils::ClosestPoint(const AABB3D& aabb, const Point3D& point)
{
	Point3D min = AABB3D::GetMin(aabb);
	Point3D max = AABB3D::GetMax(aabb);

	return Point3D(
		std::clamp(point.x, min.x, max.x),
		std::clamp(point.y, min.y, max.y),
		std::clamp(point.z, min.z, max.z)
	);
}

✅ OBB 내부 판정 (PointInOBB)

OBB는 축이 회전되어 있는 박스이므로, 내적을 통한 투영으로 판별합니다.

bool MathUtils::PointInOBB(const Point3D& point, const OBB3D& obb)
{
	Vec3 dir = point - obb.position;
	auto right = obb.orientation.Right();
	auto up = obb.orientation.Up();
	auto forward = obb.orientation.Backward();

	vector<Vec3> axis = { right, up, forward };
	vector<float> size = { obb.size.x, obb.size.y, obb.size.z };

	for (int i = 0; i < 3; ++i)
	{
		float proj = dir.Dot(axis[i]);
		if (proj > size[i] || proj < -size[i])
			return false;
	}

	return true;
}

✅ OBB에서 가장 가까운 점

Point3D MathUtils::ClosestPoint(const OBB3D& obb, const Point3D& point)
{
	Vec3 dir = point - obb.position;
	Point3D result = obb.position;

	auto right = obb.orientation.Right();
	auto up = obb.orientation.Up();
	auto forward = obb.orientation.Backward();

	vector<Vec3> axis = { right, up, forward };
	vector<float> size = { obb.size.x, obb.size.y, obb.size.z };

	for (int i = 0; i < 3; ++i)
	{
		float proj = dir.Dot(axis[i]);
		proj = std::clamp(proj, -size[i], size[i]);
		result += axis[i] * proj;
	}

	return result;
}

✅ 평면 위 점 판별 (PointOnPlane)

평면은 normal · point == distance를 만족하면 해당 평면 위에 있습니다.

bool MathUtils::PointOnPlane(const Point3D& point, const Plane3D& plane)
{
	return fabs(point.Dot(plane.normal) - plane.distance) < FLT_EPSILON;
}

✅ 평면에서 가장 가까운 점

Point3D MathUtils::ClosestPoint(const Plane3D& plane, const Point3D& point)
{
	float dot = point.Dot(plane.normal);
	float dist = dot - plane.distance;
	return point - plane.normal * dist;
}

✅ 선 위에 있는지 (PointOnLine)

선분 상의 점은 해당 선분과의 가장 가까운 점이 자신일 때 포함됩니다.

bool MathUtils::PointOnLine(const Point3D& point, const Line3D& line)
{
	Point3D closest = ClosestPoint(line, point);
	return (closest - point).LengthSquared() < FLT_EPSILON;
}

✅ 선분에서 가장 가까운 점

Point3D MathUtils::ClosestPoint(const Line3D& line, const Point3D& point)
{
	Vec3 lineVec = line.end - line.start;
	float t = (point - line.start).Dot(lineVec) / lineVec.Dot(lineVec);
	t = std::clamp(t, 0.0f, 1.0f);
	return line.start + lineVec * t;
}

✅ 광선 위에 있는지 (PointOnRay)

광선은 방향성이 있으므로, 시작점과 동일하거나, 방향이 같고 출발점으로부터 동일 선상에 있어야 포함됩니다.

bool MathUtils::PointOnRay(const Point3D& point, const Ray3D& ray)
{
	if (point == ray.origin)
		return true;

	Vec3 toPoint = (point - ray.origin).Normalized();
	return fabs(toPoint.Dot(ray.direction) - 1.0f) < FLT_EPSILON;
}

✅ 광선에서 가장 가까운 점

Point3D MathUtils::ClosestPoint(const Ray3D& ray, const Point3D& point)
{
	float t = (point - ray.origin).Dot(ray.direction);
	t = std::max(0.0f, t); // 음수면 시작점보다 뒤쪽 → ray 시작점으로 고정
	return ray.origin + ray.direction * t;
}

profile
李家네_공부방

0개의 댓글