Автор разбирает техническую проблему Unreal Engine: движок фиксирует горизонтальный FOV и масштабирует его через аспект вьюпорта. Это приводит к некорректному поведению при смене соотношения сторон (ультраширокие, 4:3 и т.п.). В данном фрагменте статьи описан способ исправить это через собственный подкласс камеры и корректную математику FOV.
Подкласс камеры
Создаётся обёртка над ACameraActor:
UCLASS() class AMyCamera : public ACameraActor { };Цель — подменить тип компонента камеры внутри актёра, чтобы контролировать расчёт обзора.
Автор отмечает неудобство разделения логики между компонентом и актёром камеры в Unreal:
- PlayerController и CameraManager по-разному работают с компонентами камеры, встроенными в разные типы актёров.
- У CineCamera часть функционала (например, Look at Tracking) живёт в актёре, часть — в компоненте, поэтому при встраивании компонента без обёртки часть возможностей теряется.
Математика FOV и аспект
Ключевой момент: соотношение сторон применяется к тангенсу половины угла FOV, а не к самому углу. Поэтому при перерасчёте FOV нужно работать в правильном пространстве:
- перевести угол в радианы,
- взять половину угла, посчитать tan(halfAngle),
- умножить/поделить тангенс на аспект,
- обратно восстановить угол через atan и перевести в градусы.
Автор оборачивает FMath::RadiansToDegrees и FMath::DegreesToRadians в макросы R2D и D2R, чтобы упростить код.
Получение корректного аспекта
Функция CameraUtil::CalcAspectRatio(UWorld* W) должна возвращать реальное соотношение сторон. В примере по умолчанию возвращается 16:9 как fallback, если нет вьюпорта. В рабочем коде автор:
- берёт аспект не с экрана, а с Local Player,
- тем самым учитывает split-screen мультиплеер (предполагается, что все сплиты имеют один и тот же аспект, поэтому достаточно смотреть на первого игрока).
Инъекция компонента камеры
В конструкторе AMyCamera используется «магическое» DI-решение: через имя члена "CameraComponent" подменяется тип подкомпонента камеры на нужный (аналогично тому, как можно заменить CharacterMovementComponent в наследниках Character).
Альтернатива: CameraModifier
Если нельзя контролировать подкласс CameraActor, можно использовать CameraModifier и в нём пост-обработать DesiredView тем же кодом перерасчёта FOV. Автор считает этот путь более неудобным в типичном воркфлоу и поэтому не использует его как дефолт.
Выводы
- Корректный перерасчёт FOV при смене аспекта требует работы с тангенсом половины угла, а не с самим углом.
- Лучше создать собственный подкласс ACameraActor и подменить тип компонента камеры через конструктор.
- Аспект-рейшо нужно брать с Local Player, чтобы корректно поддерживать split-screen.
- Если нельзя менять тип актёра камеры, можно применить тот же код через CameraModifier, но это менее удобно.