# 25.12 Rotate / Switch Ortho Problems Report Отчет составлен по содержимому чата и локальным изменениям кода в проекте. Цель: зафиксировать весь путь расследования проблем с вращением (ось/pivot) и прыжками камеры при переключении ортографической и перспективной проекции. --- ## 1. Подробное описание проблемы, наблюдений, логов и взаимосвязей ### 1.1 Контекст и среда - Сцены очень крупные (километры), много LAS облаков, иногда GLB модели. - Рабочий сценарий: уйти далеко, вернуться к объекту, переключать ortho/persp, вращать камеру. - Пользователь каждый тест делает с очисткой кэша браузера. Сервер не перезапускается. - На «свежем» состоянии проблемы часто не проявляются сразу, но появляются спустя время/навигацию. ### 1.2 Симптомы (что видит пользователь) 1) **Смещение оси вращения (pivot drift).** - Вращение идет вокруг точки, которая не совпадает с курсором или целевым объектом. - Часто ощущается, что точка вращения «за камерой» или сильно в стороне. - В ortho проявляется чаще, но бывает и в perspective. - Иногда исчезает после переключения в perspective или после фокуса (двойной клик). 2) **Прыжки камеры при переключении ortho <-> perspective.** - При переключении камера уезжает назад или в сторону на 50–200+ метров. - После прыжка новая дистанция становится «новой нормой» для следующих переключений. - Особенно часто при переключении из ortho в perspective. 3) **Клиппинг (статические отсечки) в ortho.** - Периодически появляется «плоскость отсечения», которая не зависит от зума. - Отсечка исчезает при смене ракурса/переключении проекции, но может вернуться. 4) **Нестабильный зум (скачки шага).** - После сильного отлета зум начинает «пропускать шаги». - Приближение становится грубым: следующая позиция уже «за объектом». ### 1.3 Наблюдения (устойчивые повторения) - Проблемы чаще всего возникают после **сильного отлета** и перемещения на большое расстояние. - При аккуратной локальной работе (вокруг одного объекта) поведение обычно стабильнее. - Переключение в perspective и небольшой «полет» иногда стабилизируют pivot. - После double-click фокусировки проблемы временно исчезают. ### 1.4 Логи, которые использовались В процессе добавлены и использовались флаги: - `window.__dcProjDebug = true` - `window.__dcPivotDebug = true` - `window.__dcAllowOffsetEye = true` (опционально, для диагностики) Типовые лог-сообщения: - Проекции: `[dc-proj] persp->ortho`, `[dc-proj] ortho->persp`, `proj-switch(before/after)` - Пивот: `[dc-pivot] start`, `[dc-pivot] start-clamp`, `[dc-pivot] ortho-pivot`, `[dc-pivot] persp-pick`, `[dc-pivot] ortho-eye-normalize` Что замечено по логам: - В ortho часто фиксируется **несоответствие между eyeLookDist и orthoScale** (orthoScale намного больше). - В некоторых логах `pickDist`/`rayDist` сильно отличаются от `eyeLookDist`. - Были ситуации, когда `pivotPos == look`, но ощущение вращения все равно «кривое», значит проблема не только в выборе pivot, а в состоянии камеры (eye/scale). ### 1.5 Взаимосвязи и гипотезы Основные гипотезы, подтвержденные частично логами и наблюдениями: - **Проблемы накопительные**: чем больше дальних перемещений и масштаба, тем выше шанс сломаться. - **Пивот в ortho** при выборе через pick/ray нестабилен в больших сценах. - **Сильные отлеты** приводят к разрыву между `orthoScale` и `eyeLookDist`, что искажает ось вращения. - **Переключение проекций** использует параметры, которые не всегда согласованы с текущим состоянием камеры. --- ## 2. Подробное описание всех попыток исправления Ниже приведены все попытки с указанием: где делали, что меняли, зачем, ожидаемый результат и фактический результат. ### Попытка 1. Настройки клиппинга в UI (viewport) **Где:** UI блок `Viewport` (инспектор). **Что сделали:** добавили поля для клиппинга (perspective/ortho), позже min/max. **Зачем:** пользователь видел слишком ранние отсечки и хотел управлять дистанцией. **Ожидание:** контроль near/far клиппинга решит отсечки и приблизит камеру. **Факт:** в perspective стало предсказуемее, в ortho появились «статические» отсечки, которые не всегда зависели от камеры. Проблема клиппинга осталась. ### Попытка 2. Принудительный near/far (0.01 / 1e9) **Где:** параметры камеры. **Зачем:** исключить влияние near/far. **Ожидание:** клиппинг исчезнет. **Факт:** не помогло, отсечки остались. ### Попытка 3. Включение логов и сбор метрик **Где:** консольный дебаг, далее встроенные логи. **Что:** добавлены `[dc-proj]` и `[dc-pivot]` логи. **Зачем:** видеть dist, orthoScale, pickDist, rayDist. **Ожидание:** найти связь между параметрами и рывками/пивотом. **Факт:** выявлены несоответствия scale/dist и роль сильных отлетов, но без прямого фикса. ### Попытка 4. Форк core-камеры в локальный файл **Где:** `frontend/lib/dc-camera-context.es.js` **Что:** из minified xeokit сделали локальную «контекстную» версию для правок. **Зачем:** исправлять первоисточник, а не обертки. **Ожидание:** полный контроль над Camera/Ortho/Perspective. **Факт:** сначала ошибки сборки (duplicate identifier, lookAtMat4v undefined), после коррекции файл заработал и стал основным местом правок. ### Попытка 5. Удаление обертки проекций **Где:** `frontend/dcViewer.js` **Что:** удален `projectionSync` (обертка синхронизации проекций). **Зачем:** убрать внешние корректировки, которые могут конфликтовать. **Ожидание:** меньше неожиданных прыжков. **Факт:** источник конфликтов убран, но прыжки и pivot drift остались. ### Попытка 6. Пересчет ortho/persp в Camera.projection **Где:** `frontend/lib/dc-camera-context.es.js` (Camera.projection setter) **Что:**\n - `persp -> ortho`: масштаб берется из `dist` и `fov` - `ortho -> persp`: дистанция берется из `orthoScale` и `fov` - убраны расчеты на основе `rayDist` **Зачем:** сделать переключение более детерминированным. **Ожидание:** стабильная дистанция при переключениях. **Факт:** иногда лучше, но рывки оставались, особенно после большого зума. ### Попытка 7. Отключение offsetEyeFromLook **Где:** `frontend/lib/dc-camera-context.es.js` **Что:** `offsetEyeFromLook` теперь false по умолчанию, включается через флаг `__dcAllowOffsetEye`. **Зачем:** offset подозревался как источник смещения оси вращения. **Ожидание:** pivot станет стабильнее. **Факт:** стало немного стабильнее, но проблема не исчезла. ### Попытка 8. Clamp pivot по dot/ratio **Где:** `PivotController.startPivot` **Что:** если pivotDist/eyeLookDist слишком большой или направление не совпадает, pivot принудительно сбрасывается на `look`. **Зачем:** исключить pivot за камерой. **Ожидание:** уменьшение случаев «кривой» оси. **Факт:** часть экстремальных случаев ушла, но проблема оставалась. ### Попытка 9. Эвристики ortho pick pivot **Где:** обработчик mouse/touch для pivot в `dc-camera-context.es.js` **Что:** pick pivot принимается только при нормальных dot/ratio и пределах `rayDist`. **Зачем:** в ortho pick часто уводил pivot в неверное место. **Ожидание:** меньше смещений оси. **Факт:** поведение было нестабильным, в некоторых случаях хуже. ### Попытка 10. Ortho eye normalize **Где:** `PivotController.startPivot` **Что:** если `orthoScale >> eyeLookDist`, camera.eye отодвигается вдоль вида на `max(eyeLookDist, orthoScale)`. **Зачем:** уменьшить расхождение между масштабом и дистанцией камеры. **Ожидание:** стабилизация оси вращения в ortho после сильного зума. **Факт:** результаты неоднозначные, иногда хуже. ### Попытка 11. Полное отключение pick pivot в ortho (последняя правка) **Где:** mouse/touch обработчики pivot в `dc-camera-context.es.js` **Что:** при ortho pivot всегда `camera.look`, pick/ray не используются. **Зачем:** убрать нестабильность pick pivot. **Ожидание:** стабильная ось вращения в ortho. **Факт:** требуется повторный тест после этой правки. ### Попытка 12. Жесткая фиксация `look` и движение `eye` вдоль направления **Где:** `Camera.projection` setter **Что:** при переключении проекций `look` фиксируется, `eye` пересчитывается только по направлению вида (без боковых смещений). **Зачем:** убрать скачки в сторону/назад при ortho <-> persp. **Ожидание:** переключение без прыжков по позиции. **Факт:** требуется повторный тест после этой правки. ### Попытка 13. Расширенные логи **Где:** `dc-camera-context.es.js` **Что:** добавлены детальные логи `[dc-proj]` и `[dc-pivot]`. **Зачем:** фиксировать реальные параметры во время рывков. **Ожидание:** получить воспроизводимые метрики для анализа. **Факт:** помогло подтвердить связь с сильным зумом, но без полного решения. --- ## 3. Итоговое состояние на момент отчета Актуальные изменения в форке: - `frontend/lib/dc-camera-context.es.js`: - упрощен пересчет ortho/persp; - `offsetEyeFromLook` по умолчанию false; - pivot clamp при подозрительном pivot; - `ortho-eye-normalize` (эксперимент); - **в ortho pivot всегда `look`**, pick/ray игнорируется (последняя правка); - логи `__dcProjDebug` и `__dcPivotDebug`. - `frontend/dcViewer.js`: - удалена обертка `projectionSync`. Состояние проблемы: - после ряда правок поведение часто становится лучше на короткой дистанции, но при сильных отлетах проблема возвращается. - основной подозреваемый: накопление состояния в камере + разрыв между `orthoScale` и `eyeLookDist` + нежелательные pivot‑решения в ortho. --- ## 4. Что требуется для следующей итерации 1) Свежий тест после последних правок (без длительных старых сессий). 2) Логи: - `window.__dcProjDebug = true` - `window.__dcPivotDebug = true` 3) Сценарий: - сильно отлететь, - вернуться к объекту, - вращать в ortho, - переключить ortho/persp. Если вновь поймается «кривая ось» или «скачок дистанции», лог должен сопровождать момент, чтобы анализировать разницу между `eyeLookDist`, `orthoScale`, `pivotDist`, `pickDist`, `rayDist`.