반응형

심즈같은 게임에서 위와 같이 위젯에서 요소를 끌어서 3D 월드 좌표에 배치하는 기능을 간간히 볼 수 있다.  

 

 

위젯에서 드래그를 감지하려면 UUserWidget에 OnDragDetected OnDragCancelled OnDragEnter 등 마우스의 드래그에 대한 가상함수가 있다.

모바일에서의 터치 감지는 OnTouchStarted  OnTouchMoved OnTouchEnded 등 함수들도 확인할 수 있다.

 

OnMouseButtonDown 함수를 먼저 오버라이드해서 DetectDragIfPressed 함수로 드래그가 작동하였는지 판별하라고 하는데 도저히 OnDrag~ 관련 함수가 호출되지 않아서 다른방법을 사용하였다.

 

 

 

헷갈렸던 개념 

ViewPort - 게임이 렌더링 되는 영역 (게임화면)

Screen - 모니터의 화면 픽셀 좌표

 

Project(투영) = 월드(3D) -> 스크린(2D)

Deproject = 스크린(2D) -> 월드(3D)

 

 

문제점 개선

1. PlayerController 의 GetMousePosition 함수는 마우스 입력이 캡처되었을 때 PlayerController에서 보는 마우스 좌표가 고정된다.

-> 버튼이 Pressed 된 순간 캡처되고, Pressed 를 유지한 채로 움직일 때 마우스 좌표를 갱신하지 않는다.

 

2. 2D 화면상 좌표를 3D 월드 좌표로 변환해주는 DeprojectScreenPositionToWorld 함수가 스크린 좌표만을 받는다.

(PlayerController 의 GetMousePosition 은 스크린 좌표임) 

고로 뷰포트의 좌표를 받으면 결과가 다르다.

뷰포트 좌표로 Deproject 했을 때

 

그래서 마우스 캡처됨과 동시에 현재 스크린 좌표상의 마우스 포지션을 가져오는 방법은 다음 과정을 거쳐야 한다. 

// 현재 게임화면상의(뷰포트) 기준 마우스위치
FVector2D MousePos = UWidgetLayoutLibrary::GetMousePositionOnViewport(GetWorld());
// 현재 뷰포트의 Geometry (위치,크기,스케일,DPI정보 등)
FGeometry ViewportGeometry = UWidgetLayoutLibrary::GetViewportWidgetGeometry(GetWorld());

// 위젯 로컬 좌표 -> Viewport 좌표로 변환
// PixelPosition - 화면상의 절대 픽셀 위치 (Geometry 고려한 값)
// ViewportPosition = MousePos
FVector2D PixelPosition, ViewportPosition;
USlateBlueprintLibrary::LocalToViewport(GetWorld(), ViewportGeometry, MousePos, PixelPosition, ViewportPosition);

GetMousePosition 대신 사용해야하는 코드이다.

현재 ViewPort 에 있는 MousePos 와 ViewPort의 Geometry 기반으로

PixelPosition - ViewPort 기반에서의 MousePos 를 스크린 좌표로 변환된 위치

ViewPortPosition = MousePos

 

PixelPosition이 마우스가 캡처 된 상태에서 스크린 상의 좌표가 된다.

 

 

 

스크린 상의 PixelPosition 을 기반으로 Deproject를 하면 올바르게 마우스 위치로 GhostActor가 따라다니는 것을 확인할 수 있다.

void UDragPlacementManager::Tick(float DeltaTime)
{
    if (!GhostActor.IsValid() || !OwnerController.IsValid())
        return;

    // ******** Pressed 되었을 때만 인식해서 계속 마우스 위치 받아야 함 - GetMousePositionOnViewport *************
    // PlayerController의 GetMousePosition 은 Pressed 되었을 때 위치만 가져와서 문제

    // 현재 게임화면상의(뷰포트) 기준 마우스위치
    FVector2D MousePos = UWidgetLayoutLibrary::GetMousePositionOnViewport(GetWorld());
    // 현재 뷰포트의 Geometry (위치,크기,스케일,DPI정보 등)
    FGeometry ViewportGeometry = UWidgetLayoutLibrary::GetViewportWidgetGeometry(GetWorld());

    // 위젯 로컬 좌표 -> Viewport 좌표로 변환
    // PixelPosition - 화면상의 절대 픽셀 위치 (Geometry 고려한 값)
    // ViewportPosition = MousePos
    FVector2D PixelPosition, ViewportPosition;
    USlateBlueprintLibrary::LocalToViewport(GetWorld(), ViewportGeometry, MousePos, PixelPosition, ViewportPosition);
    
    float MouseX = PixelPosition.X, MouseY = PixelPosition.Y;

    FVector WorldOrigin, WorldDir;
    if (OwnerController->DeprojectScreenPositionToWorld(MouseX, MouseY, WorldOrigin, WorldDir))
    {
        FHitResult Hit;
        FVector End = WorldOrigin + WorldDir * 10000.f;
        if (OwnerController->GetWorld()->LineTraceSingleByChannel(Hit, WorldOrigin, End, ECC_Visibility))
        {
            GhostActor->SetActorLocation(Hit.Location);
        }
    }
}

 

 

반응형

'언리얼' 카테고리의 다른 글

Zen Storage  (0) 2025.12.31
DerivedDataBackendGraph  (0) 2025.12.24
World Widget Depth Test  (0) 2025.09.24
Custom Depth Stencil Pass  (0) 2025.09.19
언리얼 오브젝트 참조 관계  (4) 2025.07.30

+ Recent posts