分辨率修改实际上是更改SceneViewport的分辨率,Unreal的FSceneViewport提供了两种更改分辨率的方法。
// 设置固定分辨率,仅更新视口分辨率,不会改变Window大小
void SetFixedViewportSize (uint32 NewSizeX, uint32 NewSizeY);
// 设置自由分辨率,会更新整个window的窗口分辨率
void SetViewportSize(uint32 NewSizeX,uint32 NewSizeY)
可以通过调用 FSceneViewport::SetFixedViewportSize(0,0) 重新使窗口分辨率能够随着viewport变化而灵活变化。因此,想要更改Unreal视口的分辨率,最重要的是获取当前的视口。很多文章都提供GEngine->GameViewport->GetGameViewport()来获取该视口,但好像在编辑器模式下这种获取方式是无法获得视口的,而在游戏运行模式下,采用这种方式又会造成UE5的闪退,于是整理一下本文采用的方法。
编辑器模式下的分辨率修改
FLevelEditorModule 是引擎中的一个重要模块,用于管理和扩展 LevelEditor,在函数 SpawnLevelEditor 中创建了整个UE界面,因此我们可以通过FLevelEditorModule来获取当前视口。FLevelEditorModule提供了以下函数来获取当前活动视口。
/**
* Gets the first active viewport of all the viewports.
*/
virtual TSharedPtr<class IAssetViewport> GetFirstActiveViewport();
/**
* Gets the first active viewport of all the viewports.
*/
virtual TSharedPtr<class SLevelViewport> GetFirstActiveLevelViewport();
因此,编辑器模式下修改分辨率的代码为
FLevelEditorModule& LevelEditorModule = FModuleManager::Get().GetModuleChecked<FLevelEditorModule>(TEXT("LevelEditor"));
TSharedPtr<SLevelViewport> ViewportInterface = LevelEditorModule.GetFirstActiveLevelViewport();
SceneViewport = (FSceneViewport*)ViewportInterface->GetActiveViewport();
SceneViewport->SetFixedViewport(1920,1080);
运行模式下的分辨率修改
运行在UE的Viewport中
因为还运行在UE的Viewport中,与编辑器下获取视口的方法一样。
FLevelEditorModule& LevelEditorModule = FModuleManager::Get().GetModuleChecked<FLevelEditorModule>(TEXT("LevelEditor"));
TSharedPtr<SLevelViewport> ViewportInterface = LevelEditorModule.GetFirstActiveLevelViewport();
FSceneViewport* SceneViewport = (FSceneViewport*)ViewportInterface->GetActiveViewport();
SceneViewport->SetFixedViewport(1920,1080);
以新窗口运行(New PIE)
此时该视口发生变化,新窗口的视口为
FSceneViewport* SceneViewport = nullptr;
UGameViewportClient* GameViewport = GEditor->PlayWorld->GetGameViewport();
if(GameViewport)
SceneViewport = GameViewport->GetGameViewport();
而由于以新窗口运行,是在SWindows组件下的,因此只更改视口大小是没有效果的,因此我们改变包裹视口的窗口大小,让视口去自适应的变换大小。
TSharedPtr<SWindow> SceneWindow = SceneViewport->FindWindow();
SceneWindow->Resize(FVector2D(1920,1080));//Resize函数是根据视口对窗口大小进行变换的,能够保证视口大小是1920x1080
以Standalone模式运行
现在就是一个独立的游戏程序了,在编辑器内进行的操作已经很难对它起作用了。所以在游戏中增加了一个Button,通过来更改分辨率了,其中r.SetRes 1920x1080w是针对窗口的,r.SetRes 1920x1080f是针对全屏模式的。
GEngine->Exec(NULL, TEXT("r.SetRes 1920x1080w"));
补充
发现用上面的方式修改了编辑器模式下的视口分辨率会造成鼠标和选中目标之间的偏差,阅读源代码后发现,鼠标坐标是当前视口FSceneViewport中的CachedCursorPos。
//这里bLocalPosition默认是true
void FSceneViewport::GetMousePos( FIntPoint& MousePosition, const bool bLocalPosition )
{
if (bLocalPosition)
{
MousePosition = CachedCursorPos;
}
else
{
const FVector2D AbsoluteMousePos = CachedGeometry.LocalToAbsolute(FVector2D(CachedCursorPos.X / CachedGeometry.Scale, CachedCursorPos.Y / CachedGeometry.Scale));
MousePosition.X = AbsoluteMousePos.X;
MousePosition.Y = AbsoluteMousePos.Y;
}
}
而CachedCursorPos的计算方式如下,从中可以看出鼠标坐标的计算包含一个缩放系数CachedGeometry.Scale,这个缩放系数是由实际视口形状大小和上面设置的视口分辨率计算出来的,但如果电脑屏幕分辨率设置并不是100%的话,初始的CachedGeometry.Scale也就不是1,从而造成了后续鼠标点击位置和实际鼠标位置之间的偏差。
void FSceneViewport::UpdateCachedCursorPos( const FGeometry& InGeometry, const FPointerEvent& InMouseEvent )
{
const FPlatformUserId UserId = IPlatformInputDeviceMapper::Get().GetUserForInputDevice(InMouseEvent.GetInputDeviceId());
if (UserId == FSlateApplication::SlateAppPrimaryPlatformUser)
{
FVector2D LocalPixelMousePos = InGeometry.AbsoluteToLocal(InMouseEvent.GetScreenSpacePosition());
LocalPixelMousePos.X = FMath::Clamp(LocalPixelMousePos.X * CachedGeometry.Scale, (double)TNumericLimits<int32>::Min(), (double)TNumericLimits<int32>::Max());
LocalPixelMousePos.Y = FMath::Clamp(LocalPixelMousePos.Y * CachedGeometry.Scale, (double)TNumericLimits<int32>::Min(), (double)TNumericLimits<int32>::Max());
CachedCursorPos = LocalPixelMousePos.IntPoint();
}
}
暂时还没有找到除了更改引擎外的处理方法qaq。
4709

被折叠的 条评论
为什么被折叠?



