Just an update for anyone not getting this to work in UE5.
Code for the .h
UFUNCTION(BlueprintPure, Category = "UI Math")
static bool ProjectWorldToScreenBidirectional(APlayerController const* Player, const FVector& WorldPosition, FVector2D& ScreenPosition, bool& bTargetBehindCamera, bool bPlayerViewportRelative = false);
Code for the .cpp
bool UIBlueprintFunctionLibrary::ProjectWorldToScreenBidirectional(APlayerController const* Player, const FVector& WorldPosition, FVector2D& ScreenPosition, bool& bTargetBehindCamera, bool bPlayerViewportRelative)
{
FVector Projected;
bool bSuccess = false;
ULocalPlayer* const LP = Player ? Player->GetLocalPlayer() : nullptr;
if (LP && LP->ViewportClient)
{
// get the projection data
FSceneViewProjectionData ProjectionData;
if (LP->GetProjectionData(LP->ViewportClient->Viewport, /*out*/ ProjectionData))
{
const FMatrix ViewProjectionMatrix = ProjectionData.ComputeViewProjectionMatrix();
const FIntRect ViewRectangle = ProjectionData.GetConstrainedViewRect();
FPlane Result = ViewProjectionMatrix.TransformFVector4(FVector4(WorldPosition, 1.f));
if (Result.W < 0.f) { bTargetBehindCamera = true; } else { bTargetBehindCamera = false; }
if (Result.W == 0.f) { Result.W = 1.f; } // Prevent Divide By Zero
const float RHW = 1.f / FMath::Abs(Result.W);
Projected = FVector(Result.X, Result.Y, Result.Z) * RHW;
// Normalize to 0..1 UI Space
const float NormX = (Projected.X / 2.f) + 0.5f;
const float NormY = 1.f - (Projected.Y / 2.f) - 0.5f;
Projected.X = (float)ViewRectangle.Min.X + (NormX * (float)ViewRectangle.Width());
Projected.Y = (float)ViewRectangle.Min.Y + (NormY * (float)ViewRectangle.Height());
bSuccess = true;
ScreenPosition = FVector2D(Projected.X, Projected.Y);
if (bPlayerViewportRelative)
{
ScreenPosition -= FVector2D(ProjectionData.GetConstrainedViewRect().Min);
}
}
else
{
ScreenPosition = FVector2D(1234, 5678);
}
}
return bSuccess;
}
Changed:
if (LP->GetProjectionData(LP->ViewportClient->Viewport, eSSP_FULL, /*out*/ ProjectionData))
To
if (LP->GetProjectionData(LP->ViewportClient->Viewport, /*out*/ ProjectionData))
And added Daniel_Alves_br’s suggestion.
I suggest you to add na ELSE parameter to set bTargetBehindCamera back to false when look to the tag point again.
if (Result.W < 0.f) { bTargetBehindCamera = true; } else {bTargetBehindCamera = false;}