Get the World Space Position of a Screen Position?

Hey all, so I’m attempting to get the world space position of the bottom right hand corner of my screen and I’ve tried getting the viewport size and then using DeprojectScreenPositionToWorld but it keeps returning world space co-ordinates that are near the middle of the screen. Here is my code:

// Get the Viewport Size
FVector2D ViewportVector = FVector2D(1, 1);
if (GEngine && GEngine->GameViewport)
{
GEngine->GameViewport->GetViewportSize(ViewportVector);
}

FVector Result;
FVector Direction;

APlayerController* PC = Cast<APlayerController>(GetWorld()->GetFirstPlayerController());
PC->DeprojectScreenPositionToWorld(ViewportVector.X, ViewportVector.Y, Result, Direction);
print(Result.ToString());

Any help is much appreciated, thank you :slight_smile:

This code works:



APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();

int32 ViewportSizeX, ViewportSizeY;
PlayerController->GetViewportSize(ViewportSizeX, ViewportSizeY);

auto ScreenLocation = FVector2D(ViewportSizeX, ViewportSizeY);

FVector WorldLocation;
FVector WorldDirection;

if (PlayerController->DeprojectScreenPositionToWorld(ScreenLocation.X, ScreenLocation.Y, WorldLocation, WorldDirection))
{
       UE_LOG(LogTemp, Warning, TEXT("WorldLocation: %s"), *WorldLocation.ToString());
}


WorldLocation has now the coordinates of:

](filedata/fetch?id=1778843&d=1592754808)

2 Likes

If you are doing it for ray trace here is how to get TraceStartPosition (world position of mouse pixel) and TraceEndLocation (a ray projected from the start location).



// cannot ray trace without player controller
if (_playerController == nullptr)
{
return;
}

// get mouse position
float mouseX;
float mouseY;
_playerController->GetMousePosition(mouseX, mouseY);

// get current camera location, rotation, direction
FVector cameraLocation = _playerController->PlayerCameraManager->GetCameraLocation();
FRotator cameraRotation = _playerController->PlayerCameraManager->GetCameraRotation();
FVector cameraDirection = cameraRotation.Vector().GetSafeNormal();

// trace start location is the mouse cursor in world coordinates
// trace end location is a ray in the direction of the camera
FVector traceStartLocation;
FVector traceEndLocation;
_playerController->DeprojectScreenPositionToWorld(mouseX, mouseY, traceStartLocation, cameraDirection);
traceEndLocation = traceStartLocation + MAXIMUM_INTERACTION_DISTANCE * cameraDirection;


Thank you so much I just tried this and it’s now working properly :slight_smile:

I wasn’t doing it for a ray trace but I’m going to try this out now for fun, thanks for the code :slight_smile:

This code doesn’t seem particularly robust to me.
If I’m next to a wall, this position will project to the other side of that wall. If there’s an interactable in that other room, that interactable would be “visible” to this code.
You need to either do an actual sweep test, or you need to read the depth buffer to get the end location to trace to. Reading depth would introduce a rendering stall, so you’ll generally want to read the depth buffer of the previous frame, which gives a bit of “jiggliness” to how deep you can trace, so a sweep test is usually better.
You might also want to sweep a sphere of some radius, because a ray could get through very small cracks in geometry, and still give access to things that aren’t “in the same room” as the player.

Yes. That code is only to get the ray. Then you trace however you wish. Multiple ways to do it. This is one way:



// create collision query parameters
// collision query parameters determined by player controller (mainly to ignore hitting certain objects)
FHitResult traceHitResult(ForceInit);
FCollisionQueryParams traceParameters = _playerController->GetCollisionQueryParameters();

// do ray trace
_playerController->GetWorld()->LineTraceSingleByChannel(traceHitResult, // result
traceStartLocation, // start
traceEndLocation, // end
ECC_Pawn, // collision channel
traceParameters); // trace parameters

// get unreal trace actor and component
_traceActor = traceHitResult.GetActor();
_traceComponent = traceHitResult.GetComponent();


You now have reference to the actor and component under the mouse cursor, out to a certain distance, with option to ignore certain actors.

BTW, I’ve seen many ways to do this posted in here. Is there another more minimal code way get the actor and component under a specific pixel given the player’s view and/or mouse position? Also needs the option to ignore certain actors (built into the trace parameters).

I’m always up for simplifying code. :cool: