Files
onboarding-project/docs/worklog/18-camera-config-made-live.md
T
2026-08-14 15:03:43 +03:00

7.1 KiB
Raw Blame History

Камера з конфігу платформи стала реальною (2026-08-14)

Слайдери camera_position_p/_l і camera_rotation_p/_l у Scene settings були мертві: CameraFollowC.init() рахував позицію з константи CAMERA_OFFSET і виводив кут одноразовим lookAt(), а конфіг не читав узагалі. Продюсер міг крутити шість повзунків без жодного ефекту.

Вимога: повзунки прибирати не можна, вони мають працювати — і в експорті, і в прев'ю платформи.

Що з'ясувалось під час розбору

Формат конфігу читається не так, як виглядає. У globalSettings.ts кожна вісь масивного параметра описана як [min, max, default], тому camera_position_p виглядав як три трійки координат. Насправді дефолт — це третій елемент кожної трійки, а в рантаймі Template.getCategory("global") віддає плаский [x, y, z]. Перевірено прогоном справжнього formConfigForPlayable(formConfigUI(...)) над нашим же globalSettings.

Старі дефолти були з іншої моделі камери. [-2, 5, 42] — це абсолютна позиція камери зі статичного SDK-шаблону. У грі з follow-камерою абсолютна позиція безглузда (її перезаписує кожен кадр), осмислений лише офсет відносно гравця. Оскільки ці значення ніколи ні на що не впливали, від них нічого не залежало — семантику переінтерпретовано на офсет.

Object3D.lookAt і Camera.lookAt — різні. Перша спроба вирахувати еквівалентний кут дала x=53.13, y=0, z=0 і виглядала правдоподібно, але контрольна перевірка (зібрати кватерніон назад із цих кутів і зміряти forward · напрямок_на_ціль) дала −1.0 — камера дивилась рівно в протилежний бік. Причина в самому three.js:

if (this.isCamera || this.isLight) _m1.lookAt(_position, _target, this.up);
else                               _m1.lookAt(_target, _position, this.up);

Звичайний Object3D наводить на ціль свою вісь +Z, камера — −Z. Розрахунок на Object3D замість PerspectiveCamera дає дзеркальний результат. Урок: будь-який офлайн-розрахунок орієнтації перевіряти зворотним ходом (відновити з чисел і зміряти скалярний добуток), а не приймати правдоподібні числа на віру.

Справжній кут для офсету (0, 8, -6) — x=-126.87, y=0, z=-180. Еквівалентна, але читабельніша форма x=53.13, y=180, z=0 дає той самий кватерніон і той самий up-вектор — саме її записано в дефолти. y=180 тут не довільне: риг стоїть позаду гравця на −Z і дивиться назад у +Z, а камера three.js за замовчуванням дивиться в −Z.

Тип параметра — int, тож 53.13 округлено до 53. Відхилення від старого кадру — 0.13°, візуально непомітно.

Що змінено

  • globalSettings.ts — тільки дефолти (id, назви, типи й діапазони не чіпані; діапазони вже покривали нові значення). Портрет і ландшафт отримали однаковий риг, бо гра й досі використовує один CAMERA_OFFSET для обох — тепер їх можна розвести з платформи.
  • CameraFollowC — новий applyRigFromConfig(): читає офсет і кут за поточною орієнтацією, застосовує кут, лишається єдиним писарем camera.rotation. readVec3() відсіює биті значення, і тоді кут виводиться старим способом (frameTargetAndStoreRotation()) — зламаний конфіг деградує до «кадрує гравця», а не до порожнього неба.
  • beforeResourcesLoadedCb — updateVariableConfig тепер маршрутизує camera_position_*/camera_rotation_* у CameraFollowC, FOV лишається за CameraC. Роздільна власність — це і є захист від повторення бага з двома писарями.
  • resizeCb — на зміні орієнтації перечитує і FOV, і риг.
  • DebugConfigC — повзунки кута/дистанції сідають із того самого конфігу (readCameraRigFromConfig()), дубльована константа DEFAULT_CAMERA_OFFSET прибрана. setOffset() і далі авто-кадрує й синхронізує rotationDeg.
  • TestSceneC.CAMERA_OFFSET — лишився як фолбек, коментар оновлено.

Перевірено

  • npx vite build — 886 модулів, чисто.
  • Прогін реального SDK-пайплайна: гра читає camera_position_p = [0, 8, -6], camera_rotation_p = [53, 180, 0]; відновлена з цих чисел камера дивиться на гравця з похибкою 0.13°.
  • npx tsc --noEmit у проєкті не запускається — tsconfig.json містить moduleResolution: node10, яку TypeScript 7 видалив (TS5108). З обходом цієї опції лишаються дві доіснуючі помилки, обидві не в зміненому коді: deep-import three/src/math/Color у ThreeC.ts і застаріла декларація SDK для JoystickC.init({ color }).

Не перевірено

Візуально в браузері нічого не запускалось. Потрібен ручний прогін: старт у портреті, поворот у ландшафт, правка повзунків на платформі наживо.

Відкрите

Значення, збережені для вже наявних креативів на платформі, лишились у старій (абсолютній) семантиці — їх треба одноразово перевиставити на офсет-значення.