← Модуль 3/Камеры
EN
Модуль 3 · 3D-революция (1993–1999)

Камеры: от фиксированных к динамическим

В 2D камера просто следила за игроком в плоскости. В 3D она стала автономным оператором: держать героя в кадре, не утыкаться в стены, не дезориентировать и не отнимать управление. От пререндер-ракурсов Resident Evil к Lakitu-оператору Mario 64 и Z-таргету Zelda — это история про то, как приручить камеру.
~15 мин
Суть за 30 секунд
Камера — это view-матрица из урока про конвейер (обратная трансформация «глаза»), которую каждый кадр заново вычисляет риг. В 3D рига три задачи разом: следовать за целью (spring-arm / штанга), не клиппиться сквозь геометрию (коллизия штанги — притянуть камеру, если за спиной стена) и двигаться плавно (демпфирование, не линейный lerp, а экспоненциальное сглаживание — кадронезависимое и без перелёта). Ранний 3D решал проблему в лоб: фиксированные пререндер-ракурсы (Resident Evil, FF7) + tank-управление, потому что при смене ракурса «вперёд» меняет смысл. Mario 64 (1996) впервые отдал камеру игроку (оператор-Lakitu, аналог-стик, управление относительно камеры) — смело, но «скитчево». Zelda: Ocarina of Time (1998) добила проблему Z-таргетингом: лок-он на врага кадрирует обоих и превращает движение в страйф вокруг цели. Это скопировала вся индустрия.

Камера = view-матрица, которую считает риг

Напомним конвейер: view-матрица переводит мир в пространство камеры — это обратная матрица «глаза». Построить её из позиции камеры eye и точки интереса target — это look-at: три ортонормированных оси + перенос.

forward = normalize(target − eye)        // куда смотрит камера
right   = normalize(cross(up, forward))  // вправо (up — мировой «вверх»)
up'     = cross(forward, right)          // истинный «вверх» камеры
// view = базис [right | up' | forward]ᵀ + перенос (−eye)
// (соглашение +Z в кадр; в OpenGL/gluLookAt forward = eye−target, знак обратный)

Вся «работа камеры» сводится к одному вопросу: чему равны eye и target в этом кадре? В FPS просто: eye = голова игрока, target = eye + направление взгляда; камера и есть глаза. В третьем лице за это отвечает риг — небольшая система ограничений поверх позиции героя.

Риг третьего лица: штанга, коллизия, демпфер

Камера висит на штанге (spring-arm / boom) — жёстком «удилище» длины L от цели (обычно за спиной и чуть выше). Три слоя поверх:

1. Коллизия штанги. Из цели в желаемую позицию камеры пускают луч/сферу. Если на пути стена на расстоянии d < L — камеру притягивают на d (минус «кожа»-зазор), чтобы не провалиться сквозь геометрию. Пример: штанга L=4 м, стена в 2.5 м за спиной → камера садится на 2.5−0.2 = 2.3 м. Отошёл от стены — штанга плавно вытягивается обратно.

2. Демпфирование. Камера не телепортируется к цели — она догоняет. Линейный lerp с фиксированным коэффициентом зависит от fps и либо дёргает, либо перелетает. Берут экспоненциальное сглаживание (критически задемпфированное, без колебаний):

pt+Δt = T+ (pt−T) · e−Δt/τ

где T — целевая позиция камеры, τ — постоянная времени (меньше τ = жёстче слежение). Пример: τ=0.12 с, кадр Δt=1/60 с → множитель e^(−0.0167/0.12) ≈ 0.87, то есть камера закрывает ~13% зазора за кадр — и ровно столько же за то же время на любом fps (экспонента кадронезависима, в отличие от наивного lerp(p, T, 0.13)).

3. Look-ahead. Камеру чуть ведут в сторону движения/взгляда — игрок видит, куда бежит, а не затылок. Те же демпферы, но для смещения target.

свободно цель камера штанга L=4 за спиной стена цель стена хотели сюда луч уткнулся в стену → камеру притянули на d−зазор

Управление относительно камеры — и почему пререндер требовал «танка»

Аналог-стик в 3D породил вопрос: «вперёд» — это куда? Mario 64 ввёл camera-relative-конвенцию: толкнул стик «от себя» → герой бежит от камеры, влево → влево по экрану. Интуитивно, но требует, чтобы камера была предсказуемой и плавной — иначе при её рывке «вперёд» внезапно меняет смысл и героя несёт не туда.

Ранний 3D с фиксированными пререндер-ракурсами (Resident Evil 1996, поля FF7) именно от этого и страдал: камера режет с ракурса на ракурс, и «вверх на стике» каждую секунду значит новое направление. Решение — tank-управление: стик/крест поворачивает персонажа (влево/вправо — разворот, вверх — вперёд по его носу), движение отвязано от камеры вообще. Неуклюже, но переживает любую смену ракурса. Tomb Raider (1996) пошёл тем же путём; Mario 64 в том же году выбрал аналог + camera-relative — две развилки одной проблемы.

Z-таргетинг: переключение режима камеры и управления

Прорыв — Ocarina of Time (1998). Зажал Z → лок-он на враге: камера ставит в кадр обоих (героя и цель), а семантика управления меняется — боковое движение становится страйфом по кругу вокруг цели, прыжок — уклонением вбок/бэкфлипом. Фея Navi работает «личностью» этого лок-она (подсвечивает цель). Один хват разом решает и кадрирование, и наведение, и читаемость боя — то, с чем камера Mario 64 («оператор-Lakitu», смелая, но скитчевая) воевала вручную. Индустрия скопировала Z-таргетинг мгновенно; лок-он Dark Souls — прямой потомок.

Хардкор · инженерия: spring-arm, коллизия, окклюзия, виртуальные камерыможно пропустить
  • Spring-arm в движках. Unreal — SpringArmComponent (длина, лаг позиции/поворота, тест коллизии), Unity — Cinemachine с теми же ручками. Камера крепится к концу штанги, штанга делает collision-probe и демпфинг.
  • Sphere-cast, не ray-cast. Притягивание по тонкому лучу даёт мерцание на углах (луч проскакивает мимо края). Кастуют сферу радиусом с ближнюю плоскость камеры — камера не клиппит угол стены.
  • Окклюзия ≠ коллизия. Стена между камерой и героем (а не за спиной) — отдельная беда: либо dolly-in (придвинуть камеру), либо fade/dither загораживающей геометрии, либо сделать её прозрачной. Выбор зависит от жанра.
  • Критическое демпфирование. Пружина с перелётом (underdamped) даёт «качание» камеры — тошнотворно. Берут критическое (SmoothDamp Unity / экспоненту) — приходит к цели максимально быстро без колебаний.
  • Разделение aim/look. Куда целится игрок и куда смотрит камера — часто разные векторы (особенно в шутерах от третьего лица): прицел по центру экрана, камера демпфирована — иначе дрожание прицела передаётся в картинку.
  • Виртуальные камеры + блендинг. Современный подход (Cinemachine): расставить «виртуальные камеры» на ситуации, движок блендит между ними по приоритету — режиссура без хардкода в одном монолитном контроллере.
Хардкор · дизайн: кадрирование, читаемость и тошнотаможно пропустить
  • Не отнимай управление резко. Худшее — выдрать камеру из рук игрока в неожиданный момент. Если нужно срежиссировать ракурс (катсцена, узкий коридор) — делай это плавно и предсказуемо, верни управление так же мягко.
  • Композиция. Правило третей, «воздух» над головой (headroom), вести взгляд по ходу движения (look-ahead). Камера — оператор: герой не должен елозить в углу кадра.
  • Тошнота (motion sickness). Триггеры: высокий FOV-мисматч с реальным углом обзора, лаг камеры/ввода, тряска и автоматическое качание, резкие непрошеные повороты. Бюджет camera-shake — маленький; опция отключить — обязательна.
  • FOV и скорость. Шире FOV → сильнее ощущение скорости и периферия (но искажение краёв и риск тошноты); уже → «телефото», спокойнее, но клаустрофобно. FOV — это и game feel (см. модуль 9), и комфорт.
  • Первое vs третье лицо. FPS — максимальная иммерсия и точность прицела, но нулевая периферия и не видно своего тела/окружения за спиной. Третье лицо — обзор и «вижу персонажа», ценой того, что камера сама становится игровой системой со своими багами.
Аналогия
Камера третьего лица — это оператор со стэдикамом на удочке-кране: идёт за актёром (слежение), держит его в кадре с «воздухом» над головой (композиция), подаётся вперёд по ходу движения (look-ahead), а если между ним и актёром столб — мягко поднырнёт ближе или сместится (коллизия/окклюзия). И главное — у хорошего оператора рука плавная: он не дёргает кадр рывками (демпфирование) и не качает его, как на волнах (критическое, не пружинное).
Почему это важно
В 3D камера перестаёт быть «окном» и становится автономным агентом, который каждый кадр решает конфликт целей: показать героя, не утонуть в стене, не закрыть обзор, не укачать и не отнять контроль. Это один из самых недооценённых и самых «ломких» компонентов 3D-игры — плохая камера убивает игру вернее, чем средняя графика. И это чистый пример инженерии под человеческое восприятие: математика view-матрицы тут проста, вся сложность — в эргономике и ощущении.
🔁 За пределами игр — куда это переносится
Камера-риг — это смена системы отсчёта (view-матрица) плюс демпфированное слежение за целью (сглаживание + маленький решатель ограничений).

Робототехника / CV: view-матрица = экстринсики камеры (поза в мире); «эгоцентрическая vs аллоцентрическая» система координат — буквально выбор eye/target. Spring-arm с коллизией = крошечная задача constraint-solving, родня обратной кинематике (IK) манипулятора.

ML / AI: экспоненциальное демпфирование камеры — это EMA (экспоненциальное скользящее среднее), тот же приём, что momentum в SGD, Polyak-усреднение target-сетей в RL и сглаживание метрик: «иди к цели, но гладко, гася рывки». View-матрица и проекция — это экстринсики+интринсики в NeRF / 3D Gaussian Splatting / SfM, где они дифференцируемы и оптимизируются. Эгоцентрический кадр — основа embodied-агентов и robot learning.

UX / визуализация: «следуй за фокусом, но плавно» — автоскролл к активному элементу, smooth-pan карт, камера-облёт в 3D-вьюверах; критическое демпфирование, чтобы не было перелёта и качания.

Принцип: выбери систему отсчёта под наблюдателя; следуй за целью демпфированно (гаси рывки экспонентой, без колебаний); и разрули конфликтующие ограничения маленьким решателем, а не кучей if.

🔧 Запусти и поковыряй — на домашнем компе
Во что поиграть — ниже (🕹). Здесь — собрать риг руками в движке:
🔧 Поковырять (debug) ~40 мин, Godot/Unreal
В Godot повесь SpringArm3D + Camera3D на персонажа; в Unreal — SpringArmComponent (включи bDoCollisionTest, CameraLag). Загони героя спиной в стену — увидишь притягивание камеры; покрути длину штанги и лаг/демпфер (жёстко→дёргано, мягко→плывёт, найди критическое). Поставь столб между камерой и героем — поймай окклюзию, попробуй прозрачность/dolly-in. Добавь camera-relative управление и lock-on-режим (страйф вокруг цели) — мини-Z-таргет.
🧪 Потестить (глазами QA) ~15 мин
Гоняй классические баги камеры: клиппинг сквозь стену в тесных местах, окклюзия (герой пропал за геометрией), «потеря субъекта» (камера отстала/смотрит не туда), рывок при смене зоны/ракурса, тошнотный перелёт-качание, конфликт ручного поворота и автодоводки. Чеклист QA по камере.
Чеклист: воспроизвёл притягивание штанги у стены; нашёл критическое демпфирование (без качания); сломал камеру окклюзией и починил; собрал lock-on-страйф.

🕹 В какие игры поиграть — и что заметить

Эволюция от «камеру вообще не двигаем» к управляемому ригу и лок-ону. По каждому: что внутри и во что сыграть, чтобы почувствовать.

Resident Evil / FF7 1996–97 · фиксированные ракурсы

Камера не двигается вовсе — заранее срежиссированные пререндер-ракурсы, между которыми идут резкие катсы. Чтобы управление пережило смену ракурса, движение отвязали от камеры: tank-управление (поворот корпуса + «вперёд по носу»).

🎮 Сыграй: в Resident Evil (или поля FF7) пройди через границу комнаты — камера режет на новый ракурс, и если бы управление было camera-relative, «вперёд» тут же сменило бы смысл. Почувствуй, зачем нужен «танк»: он один и тот же при любом ракурсе.

Super Mario 64 1996 · оператор-Lakitu, аналог

Первая серьёзная динамическая камера в руках игрока: её «держит» Lakitu-оператор (диегетически — снимает Марио на удочке-камере), C-кнопки крутят ракурс, движение — относительно камеры через аналог-стик. Смело и до сих пор играбельно, но камера временами «скитчевая» — застревает, теряет угол в тесноте.

🎮 Сыграй: в Mario 64 зайди в узкий коридор или угол — почувствуй, как камера дёргается и борется за ракурс (C-кнопками доводишь вручную). Это передовая 1996-го и одновременно список проблем, которые решит Zelda через два года.

Zelda: Ocarina of Time 1998 · Z-таргетинг

Лок-он как режим камеры и управления: зажал Z — камера кадрирует героя и цель, движение становится страйфом по кругу, прыжки — уклонениями. Navi — «личность» лок-она. Решило ровно те беды, с которыми мучился Mario 64.

🎮 Сыграй: в OoT (или 3DS-ремейке) подерись с врагом, зажав Z: камера сама держит обоих в кадре, ты кружишь и блокируешь, не думая о ракурсе. Отпусти Z — и вернётся вся морока свободной камеры. Один хват = решённая проблема.

Tomb Raider 1996 · follow + tank

Камера-«хвост» за Ларой плюс tank-управление: компромисс между следящей камерой и неоднозначностью направления. Прямой предок «traversal»-камеры Uncharted (модуль 5).

🎮 Сыграй: в Tomb Raider у края платформы заметь, как камера то следует, то упирается в стену, а управление остаётся «танковым» — поворот Лары, а не экранное «вперёд». Контраст с аналогом Mario 64 того же года.

Современный риг Dark Souls · God of War · Unreal

Тот же скелет, доведённый до блеска: spring-arm с коллизией и демпфером, lock-on-страйф (прямой наследник Z-таргета в Dark Souls), бесшовная камера без катов (God of War 2018 — весь сюжет «одним кадром»).

🎮 Посмотри: в любой соулс-игре включи лок-он на босса — это Z-таргетинг 1998-го. В God of War 2018 обрати внимание, что камера ни разу не режет — один непрерывный план; это инженерия рига, а не магия. В Unreal-демо с SpringArm загони камеру в стену — увидишь притягивание из этого урока.

Связи
основа
3D-конвейер — камера = view-матрица (обратный «глаз»); риг лишь решает, чему равны eye и target каждый кадр.
контраст
Контроллеры и ввод — camera-relative vs tank: одно и то же нажатие стика значит разное в зависимости от рига камеры. Вход и камера связаны жёстко.
дальше
Обзор · Модуль 3 — модуль 3D-революции закрыт: рендер (Doom/Quake/конвейер), сеть (предсказание), камера. Дальше — онлайн-миры.
Вопросы пытливого ума
Почему пререндер-ракурсы вынуждали к tank-управлению, а не наоборот?
Потому что при резкой смене ракурса camera-relative управление ломается: ты держишь «вперёд» (от камеры), камера режет на встречный план — и «вперёд» мгновенно стало «назад», героя несёт в обратную сторону. Tank отвязывает движение от камеры вообще (поворот корпуса + ход по носу), поэтому переживает любой кат. Это не эстетический выбор, а вынужденный: фиксированные ракурсы требуют управления, инвариантного к ракурсу.
Математика view-матрицы простая — почему тогда камера «самое сложное» в 3D?
Потому что сложность не в матрице, а в конфликте целей под живого человека. Каждый кадр риг одновременно хочет: показать героя, не клиппиться сквозь стену, не закрыть обзор окклюзией, вести взгляд по движению, не укачать, не отнять управление и угадать намерение игрока. Эти цели противоречат друг другу (придвинуться от стены ⟂ держать обзор ⟂ не дёрнуть кадр), и идеального решения нет — есть компромисс под восприятие. Это эргономика, а не геометрия.
Почему демпфируют экспонентой, а не линейным lerp или пружиной?
Линейный lerp(p, T, k) с фиксированным k зависит от fps (на 30 и 144 Гц камера догоняет с разной скоростью) и либо дёргает, либо мажет. Пружина с инерцией (underdamped) перелетает и качается — тошнотно. Экспоненциальное / критически задемпфированное сглаживание приходит к цели максимально быстро без колебаний и кадронезависимо (множитель e^(−Δt/τ) учитывает реальный Δt). Поэтому индустрия осела на SmoothDamp/экспоненте, а не на наивном lerp.
Зачем Z-таргетинг меняет ещё и управление, а не только камеру?
Потому что в бою «куда смотреть» и «как двигаться» — одна задача. Просто навести камеру на врага мало: игроку нужно кружить, блокировать, уклоняться относительно цели. Z-таргет связывает камеру (кадрирует обоих) и семантику ввода (боковое → страйф вокруг, прыжок → уклон) в один режим — и потому ощущается «решённым», а не костыльным. Разведи их — и получишь камеру Mario 64, где наведение и движение воюют между собой.
Почему высокий FOV даёт «скорость», но и тошноту?
Широкий FOV впихивает больше мира в экран → объекты по краям проносятся быстрее и сильнее искажены (периферийный «разгон») → мозг читает это как скорость. Но если экранный FOV сильно расходится с реальным углом, под которым глаз видит монитор, плюс есть лаг камеры/ввода — вестибулярный аппарат и зрение спорят, отсюда укачивание. Поэтому FOV — ползунок и про ощущение скорости (game feel), и про комфорт; единственно верного значения нет, оно зависит от дистанции до экрана.
Почему sphere-cast, а не ray-cast для коллизии штанги?
Тонкий луч из цели в камеру проскакивает мимо углов: на ребре стены луч то задевает, то нет от кадра к кадру → камера мерцает (то притянута, то нет). Сфера радиусом с ближнюю плоскость камеры «толще» — она упирается в угол заранее и стабильно, и камера не клиппит ребро ближней плоскостью. Тот же приём, что capsule-cast для тела персонажа: объёмный зонд против дребезга на острых краях.
Что почитать