I made that post but never added the code to update the FOV of the mirror scene capture.
This is what the final mirror Tick() code looked like. Definitely has room to be improved upon. It was good enough though for the app we shipped years ago.
Variables in .h file.
// scene capture component that renders mirrored scene
UPROPERTY()
ASceneCapture2D* _sceneCapture2d = nullptr;
// min and max fov
// fov changes when player moves toward/away from mirror
float _fovAtCloseDistance = 110.0f;
float _fovAtMaxDistance = 40.0f;
float _closeDistance = 100.0f;
float _farDistance = 900.0f;
// ref to player controller
ABasePlayerController* _playerController = nullptr;
Updating the scene capture in the mirror in Tick() function, removing null checks and other stuff not related to the logic.
// get player viewpoint
FVector playerCamPosition;
FRotator playerCamRotation;
_playerController->GetCameraLocationAndRotation(playerCamPosition, playerCamRotation);
// calculate reflection vector: r = d-2(dot(d,n))n
// n = mirror forward vector
// d = player vector to mirror
// r = reflection vector
FVector n = GetActorForwardVector();
n.Normalize();
FVector d = GetActorLocation() - playerCamPosition;
d.Normalize();
FVector r = d - 2 * (FVector::DotProduct(d, n)) * n;
// update FOV based on how far the player is from the mirror
// far away from mirror = narrow fov
// closer to mirror = wider fov
// lerp fov between min distance and max distance
float distanceToPlayer = (GetActorLocation() - playerCamPosition).Size();
float clampedDistanceToPlayer = FMath::Clamp(distanceToPlayer, _closeDistance, _farDistance);
float fovLerpAlpha = (clampedDistanceToPlayer - _closeDistance) / (_farDistance - _closeDistance);
float newFovAngle = FMath::InterpExpoOut(_fovAtCloseDistance, _fovAtMaxDistance, fovLerpAlpha);
// set scene capture camera angle and fov
_sceneCapture2d->SetActorRelativeRotation(r.Rotation());
_sceneCapture2d->GetCaptureComponent2D()->FOVAngle = newFovAngle;
// draw debug angle test code
// uncomment to visualize reflection angle in game
FVector lineStart = GetActorLocation();
FVector lineEnd = GetActorLocation() + r * 20.0f;
DrawDebugLine(GetWorld(), lineStart, lineEnd, FColor::Red);
Some possible improvements we never got around to:
- adjust FOV based on angle to mirror surface
- adjust FOV based on width of mirror surface