Announcement

Collapse
No announcement yet.

Get the World Space Position of a Screen Position?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    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

    #2
    This code works:

    Code:
    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:

    Click image for larger version  Name:	1.jpg Views:	0 Size:	105.7 KB ID:	1778843
    Last edited by EvilCleric; 06-21-2020, 02:19 PM.
    "I have harnessed the shadows that stride from world to world to sow death and madness."

    Comment


      #3
      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).

      Code:
      // 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;

      Comment


        #4
        Originally posted by EvilCleric View Post
        This code works:

        Code:
        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:

        Click image for larger version Name:	1.jpg Views:	0 Size:	105.7 KB ID:	1778843
        Thank you so much I just tried this and it's now working properly

        Comment


          #5
          Originally posted by Shmoopy1701 View Post
          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).

          Code:
          // 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;
          I wasn't doing it for a ray trace but I'm going to try this out now for fun, thanks for the code

          Comment


            #6
            Originally posted by Shmoopy1701 View Post
            TraceEndLocation (a ray projected from the start location).

            Code:
            traceEndLocation = traceStartLocation + MAXIMUM_INTERACTION_DISTANCE * cameraDirection;
            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.

            Comment


              #7
              Originally posted by jwatte View Post

              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:

              Code:
              // 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.
              Last edited by Shmoopy1701; 06-24-2020, 11:57 AM.

              Comment


                #8
                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.

                Comment

                Working...
                X