Как избежать проблем с плавающей запятой на больших картах - Unity, Unity3D - Ответ 17285874

Gammister

, я сейчас пытался мини-сцену сделать со смещением мира (контроллер на 0.0.0 всегда), на первый взгляд вроде все работает, террейн с объектами смещается, все ок. Но... Я использую шейдеры, в частности шейдер, который оставляет на песке следы от ног и колес. Использую тесселяцию для объема следов. Партиклы. Все это смещается вместе с рендер-камерой персонажа. Покопаюсь еще, но, мне кажется, что не будет этот метод нормально работать в моем случае, слишком много компонентов, которые лучше не двигать..

Добавлено через 16 минут

PS: почитал документацию к активу Neo FPS. Автор актива затрагивает эту тему и в пакет у него включен инструмент для смещения начала координат (Origin Shift). В документации у него есть небольшой ликбез на эту тему и методы решения.

Приложу переведенный кусок, может, кому интересно будет:

Кликните здесь для просмотра всего текста

NeoFPS содержит систему под названием origin shift, которая периодически изменяет положение мира и его содержимого, чтобы точка зрения игрока оставалась на определенном расстоянии.
Это используется в больших игровых мирах, чтобы компенсировать визуальные и физические ошибки, которые увеличиваются с увеличением расстояния от точки отсчета.

Что такое точность с плавающей точкой.
Для хранения позиций трансформации в Unity используются 32-битные значения с плавающей точкой.
Стандартное значение с плавающей запятой использует 1 бит для представления знака числа (+ или -), 8 бит для представления знака числа (+ или -). (+ или -), 8 бит для представления экспоненты и 23 бита для представления мантиссы. Вы можете представить себе экспоненту как положение десятичной точки в ряду цифр числа, представленного мантиссой.
Например, мантисса равна 1, а экспонента (по основанию 10) 3 означает, что конечный результат равен 1000. Справа от значения мантиссы находятся 3 нуля. Мантисса, равная 1, и экспонента, равная - 4 означает, что конечный результат равен 0,0001.Слева от значения в мантиссе 4 нуля (включая один перед десятичной точкой). Если бы максимальное значение мантиссы равнялось 999, то это означало бы, что если вы хотите представить значение больше 1000 с помощью экспоненты, то в мантиссе не осталось бы достаточно цифр, чтобы представить все, что находится справа от десятичной точки. Если ваше число представляет метры, то к этому моменту вы теряете точность см и мм.

Современные (IEEE 754) плавающие числа, очевидно, имеют гораздо большую точность, чем в приведенном выше примере, но все же наступает момент, когда
вы теряете точность до миллиметра, и удивительно, как рано проявляется этот эффект. Влияние неточности плавающей точки также усугубляются при выполнении большого количества математических операций, например при вычислении мирового положения из иерархии локальных позиций.

Поскольку в NeoFPS оружие персонажа масштабируется, чтобы избежать обрезания декораций, а затем помещается прямо перед камерой, вы увидите, что вершины сетки оружия начинают "плавать" уже на расстоянии 500 м от начала координат.
Чем дальше, тем хуже. Если вы когда-нибудь выпадали за пределы карты в игре и позволяли своему персонажу продолжать падать, то вы могли вы могли наблюдать такой эффект, когда персонаж в конце концов превращается в шар из беспорядочных полигонов.

К сожалению, из-за того, как Unity работает с иерархиями сцен и представляет трансформации, эта проблема практически неизбежна.
Однако есть несколько способов смягчить эту проблему. HDRP вводит мод, который центрирует мир по отношению к камере
при рендеринге, что может значительно уменьшить эффект визуального плавания, однако это не помогает при физических столкновениях. Еще одним популярным решением является простой скрипт смещения корня, которым поделились на ныне не существующей вики unity.

Оригинальный скрипт с плавающим началом из вики сканировал все корневые объекты в сцене, когда происходило смещение начала координат. Этот подход прост и не требует особых настроек для работы. Однако у него есть
главный недостаток - он работает только с базовыми трансформациями. Вы можете адаптировать его для проверки компонентов объекта и применять специализированное поведение, но это добавит много накладных расходов на вызовы GetComponent() и вызовет другие проблемы с расширяемостью.

Решение NeoFPS по смещению начала координат использует подписчиков, прикрепленных к объектам в мире. Это позволяет им специализироваться на том если у вас есть новые компоненты, которые требуют уникального решения, вы можете просто создать пользовательский компонент на базе IOriginShiftSubscriber и подписаться на систему смещения начала координат с его помощью. Примером причины, по которой вы может потребоваться специализация для компонентов, которые рассчитывают скорость, используя дельты положения от одного кадра к другому.
Они должны компенсировать тот факт, что они только что переместились на сотни метров каждый раз, когда смещается точка отсчета, или получить 1000 м/с скорость в следующем кадре.

Вернуться к обсуждению:

Как избежать проблем с плавающей запятой на больших картах Unity, Unity3D