Full-screen Letterbox: How?

I’m cross-posting here because my answerhub post is getting zero traction.

My project is a top-down space shooter played in a 2D plane with 3D assets. Because of the design of the game, I really, really, really want the screen to stay a specific aspect ratio. I would love for the engine to just letterbox whenever the actual screen/window is a different aspect ratio than I want.

How can I do this?

My project is:

  • Local multiplayer
  • NOT split-screen
  • Using a PlayerCameraManager subclass with an Orthographic camera in blueprints
  • A C++ project (though most of the game is in blueprints so far)

I have tried setting the “constrain aspect ratio” on the camera spawned by my PlayerCameraManager, but that has no effect.

When using the config below, I get:

  • a stretched screen for [FONT=courier new]FullscreenMode of [FONT=courier new]0 (which is unpleasant)
  • resolution ignored for [FONT=courier new]FullscreenMode of [FONT=courier new]1 (which is the incorrect aspect ratio on many monitors)

// If you set this to true, the the resolution stuff above will be ignored
// 0 - True fullscreen
// 1 - Windowed fullscreen
// 2 - Windowed

Constrain aspect ratio does exactly that. However, you should not adjust the actual rendering resolution when using it.

So if you for example want a square aspect ratio on a HD monitor you should leave your resolution at 1920x1080 and the engine will add black bars on the sides to correctly letterbox it. If you instead set your resolution to 1080x1080 as well the engine will think that no letterboxing is needed and simply output a 1080x1080 image. How it is then displayed depends on your screen and graphics card settings, which tend to default to stretching the image.

Setting “constrain aspect ratio” on my camera has no effect, as I stated. Unless perhaps the stretching of the screen in FullscreenMode 0 means it is actually having an effect. If it is really up to the individual card whether to stretch or letterbox, then I am going to have to go down the much more difficult route of in-game letterboxing.

I am not adjusting the actual rendering resolution when using it. I’m always using the resolution 1920 x 1080.

What I was trying to say is that it should. Whether using a perspective or orthographic camera it should always do exactly that.

So one or more of the following are probably not done correctly:

  • The boolean is not set properly in your spawn code
  • You are not actually rendering at 1920x1080

The first is easy to check: simply pause and eject in the editor and select the spawned camera to see if it’s properly set. However, the issues you are describing with stretching in full screen seems to indicate that the issue might actually be that you are in fact not rendering at 1920x1080 at all. Because (I’m asuming 1920x1080 is also your screen resolution here) you should then not see any stretching whether constrain aspect ratio is on or not, regardless of the FullscreenMode.

To be able to help further you might want to post some images of what you have now and the code you are using to set both your camera and screen resolution.

Thank you! That is the first thing anyone has suggested that has actually moved this issue forward.

So, I can’t find the spawned camera. Literally. I can find spawned cameras, one for each of the four local players. Just not the one that the PlayerCameraManager is actually talking to. Not the one that’s actually used for the viewport. So…where the heck is my camera when I use a PlayerCameraManager? I can tell that none of the spawned cameras are my camera because (1) they are all set to perspective, and my viewport is very obviously working well orthographically, and (2) nothing that I do to the spawned cameras has any effect on the viewport.

If I touch the PlayerCameraManager’s attributes in anyway, they instantly take effect (like adjusting the orthographic width, for example). The PlayerCameraManager doesn’t have a “constrain aspect ratio” option, unfortunately. And I can’t find the camera.

So we have moved forward (the spawned cameras are red herrings). But I am still stumped.


Not implemented.

Well, I think I found out why.

// Engine/Source/Runtime/Engine/Private/PlayerCameraManager.cpp about line 487 on branch 4.11.2-release

void APlayerCameraManager::UpdateViewTarget(FTViewTarget& OutVT, float DeltaTime)
    // Don't update outgoing viewtarget during an interpolation 
    if ((PendingViewTarget.Target != NULL) && BlendParams.bLockOutgoing && OutVT.Equal(ViewTarget))

    // store previous POV, in case we need it later
    FMinimalViewInfo OrigPOV = OutVT.POV;

    //@TODO: CAMERA: Should probably reset the view target POV fully here
    OutVT.POV.FOV = DefaultFOV;
    OutVT.POV.OrthoWidth = DefaultOrthoWidth;
    OutVT.POV.bConstrainAspectRatio = false;   // <------ Hmmmmmm.

Looks like bConstrainAspectRatio is hardcoded to false. PlayerCameraManager isn’t fully implemented yet, with respect to aspect ratio, at least.

Did I take the wrong approach? Should I be just manually spawning a camera and controlling it somehow? I’m trying to do this the “right” way, but it seems that I may be going down an untraveled path. Should I just be compiling my own engine with source code modifications? I was really hoping to avoid that, but it’s looking more and more like I may have to do that. Not looking forward to maintaining custom patches for updates, though… :frowning:

So close!

I did my first build-from-source on OS X. That was an adventure in and of itself that involved a timely AnswerHub solution. If I set

OutVT.POV.bConstrainAspectRatio = true;

…then the aspect ratio is constrained! :slight_smile: …to the wrong aspect ratio. :mad:

I don’t understand where it is getting the aspect ratio from. It’s not from the PlayerCameraManager itself, because changing DefaultAspectRatio has zero effect on the outcome. I tried changing it in the PlayerCameraManager blueprint (no effect). I tried changing the default in the source code and recompiling the engine (no effect). I tried changing it on the actual object while running the game in the editor (no effect).

It appears it always uses the aspect ratio of 1.33333:

  • If I set resolution to the square 1440x1440 (ratio of 1.00), then the resulting aspect ratio is 1.33 (1440x1080, letterbox top and bottom).
  • If I set the resolution to 1920x1080 (which is already the exact ratio that I want: 1.77) then it still letterboxes to 1.33 (1440x1080, letterbox left and right).
  • If I set the resolution to 2560x1440 (also the ratio 1.77), then it letterboxes to 1.33 (1920x1440, letterbox left and right)

So at least it is consistent. Consistently wrong. :mad:


I fixed it.

diff --git a/Engine/Source/Runtime/Engine/Classes/Camera/PlayerCameraManager.h b/Engine/Source/Runtime/Engine/Classes/Camera/PlayerCameraManager.h
index eb2ff02..a9c6d4f 100644
--- a/Engine/Source/Runtime/Engine/Classes/Camera/PlayerCameraManager.h
+++ b/Engine/Source/Runtime/Engine/Classes/Camera/PlayerCameraManager.h
@@ -200,7 +200,7 @@ protected:

        /** Default aspect ratio */
-       UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=PlayerCameraManager)
+       UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=PlayerCameraManager, meta=(ClampMin = "0.1", ClampMax = "100.0"))
        float DefaultAspectRatio;

        /** Color to fade to (when bEnableFading == true). */
@@ -339,6 +339,10 @@ protected:

+       /** True if black bars should be added if the destination view has a different aspect ratio */
+       UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=PlayerCameraManager)
+       uint32 bConstrainAspectRatio : 1;
        /** True when this camera should use an orthographic perspective instead of FOV */
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PlayerCameraManager)
        uint32 bIsOrthographic : 1;
diff --git a/Engine/Source/Runtime/Engine/Private/PlayerCameraManager.cpp b/Engine/Source/Runtime/Engine/Private/PlayerCameraManager.cpp
index 7bf8275..7c15e93 100644
--- a/Engine/Source/Runtime/Engine/Private/PlayerCameraManager.cpp
+++ b/Engine/Source/Runtime/Engine/Private/PlayerCameraManager.cpp
@@ -28,6 +28,7 @@ APlayerCameraManager::APlayerCameraManager(const FObjectInitializer& ObjectIniti

        DefaultFOV = 90.0f;
        DefaultAspectRatio = 1.33333f;
+       bConstrainAspectRatio = false;
        DefaultOrthoWidth = 512.0f;
        bHidden = true;
        bReplicates = false;
@@ -484,7 +485,8 @@ void APlayerCameraManager::UpdateViewTarget(FTViewTarget& OutVT, float DeltaTime
        //@TODO: CAMERA: Should probably reset the view target POV fully here
        OutVT.POV.FOV = DefaultFOV;
        OutVT.POV.OrthoWidth = DefaultOrthoWidth;
-       OutVT.POV.bConstrainAspectRatio = false;
+       OutVT.POV.AspectRatio = DefaultAspectRatio;
+       OutVT.POV.bConstrainAspectRatio = bConstrainAspectRatio;
        OutVT.POV.bUseFieldOfViewForLOD = true;
        OutVT.POV.ProjectionMode = bIsOrthographic ? ECameraProjectionMode::Orthographic : ECameraProjectionMode::Perspective;

I’ll make a pull request.

It is pull request 2380

Can I see this function as a blueprint?