
심즈같은 게임에서 위와 같이 위젯에서 요소를 끌어서 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 은 스크린 좌표임)
고로 뷰포트의 좌표를 받으면 결과가 다르다.

그래서 마우스 캡처됨과 동시에 현재 스크린 좌표상의 마우스 포지션을 가져오는 방법은 다음 과정을 거쳐야 한다.
// 현재 게임화면상의(뷰포트) 기준 마우스위치
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 |