가장 가까운 NavMesh 위치 탐색

  • ProjectPointToNavigation을 많이 사용한다
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(GetWorld());
NavSys->ProjectPointToNavigation(MoveRequest.GetGoalLocation(), ProjectedLocation, INVALID_NAVEXTENT, &AgentProps);
  • 위 함수를 사용해 보통은 Z축 기준으로 하방에 있는 NavMesh 위의 Position을 탐색한다

Extent의 의미

  • Extent 박스와 교차하는 폴리곤들 중에서만 가장 가까운 점을 찾기 때문에, 실제로 더 가까운 폴리곤이 Extent 범위 밖에 있으면 찾지 못합니다.
// NavigationSystem.h
bool ProjectPointToNavigation(const FVector& Point, FNavLocation& OutLocation, const FVector& Extent = INVALID_NAVEXTENT, const FNavAgentProperties* AgentProperties = NULL, FSharedConstNavQueryFilter QueryFilter = NULL)
	{
		return ProjectPointToNavigation(Point, OutLocation, Extent, AgentProperties != NULL ? GetNavDataForProps(*AgentProperties, Point) : GetDefaultNavDataInstance(FNavigationSystem::DontCreate), QueryFilter);
	}

// NavigationType.h
#define INVALID_NAVEXTENT (FVector::ZeroVector)
  • EXTENT 범위를 충분히 넓게 가져가지 않으면 아무 검사도 하지 않을 수 있다
bool UNavigationSystemV1::ProjectPointToNavigation(const FVector& Point, FNavLocation& OutLocation, const FVector& Extent, const ANavigationData* NavData, FSharedConstNavQueryFilter QueryFilter) const
{
	SCOPE_CYCLE_COUNTER(STAT_Navigation_QueriesTimeSync);

	if (NavData == nullptr)
	{
		NavData = GetDefaultNavDataInstance();
	}

	return NavData != nullptr && NavData->ProjectPoint(Point, OutLocation
											, UE::Navigation::Private::IsValidExtent(Extent) ? Extent : NavData->GetConfig().DefaultQueryExtent
											, QueryFilter);
}
  • 이 경우, NavData의 Config에 접근해 Default Extent 값을 가져와 적용한다
  • 즉, 이 함수를 사용한다면 매번 분명히 의도한 Extent값을 넣어주거나 DefaultQueryExtent에 프로젝트에 통용될 만한 유의미한 값을 세팅해줘야 한다

진짜 가까운 NavMesh를 탐색하는가?

  • Extent와 겹치는 NavMesh를 검사하고, findNearestPoly2D와 closestPointOnPoly를 통해 실제 NavMesh 상의 가장 가까운 Point를 반환하는 건 맞는 것으로 보인다
dtStatus dtNavMeshQuery::closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest) const
{
    // ...
    closestPointOnPolyInTile(tile, poly, pos, closest);
    return DT_SUCCESS;
}

void dtNavMeshQuery::closestPointOnPolyInTile(const dtMeshTile* tile, const dtPoly* poly, const float* pos, float* closest) const
{
    // ...
    
    // Clamp point to be inside the polygon.
    dtVcopy(closest, pos);
    if (!dtDistancePtPolyEdgesSqr(pos, verts, nv, edged, edget))
    {
        // Point is outside the polygon, clamp to nearest edge.
        float dmin = FLT_MAX;
        int imin = -1;
        for (int i = 0; i < nv; ++i)
        {
            if (edged[i] < dmin)
            {
                dmin = edged[i];
                imin = i;
            }
        }
        const float* va = &verts[imin*3];
        const float* vb = &verts[((imin+1)%nv)*3];
        dtVlerp(closest, va, vb, edget[imin]); // 가장 가까운 edge 위의 점
    }

    // Find height at the location using detail mesh
    // ...
}
  • 다만 Extent 체크를 Sphere가 아닌 육면체로 하기 때문에, 항상 가장 가까운 Point를 반환하지는 못할 수도 있다
    • 따라서 충분한 Extent 수치를 항상 고려하고 인자에 넣어야 한다