This page has been translated automatically.
Видеоуроки
Интерфейс
Основы
Продвинутый уровень
Подсказки и советы
Основы
Программирование на C#
Рендеринг
Профессиональный уровень (SIM)
Принципы работы
Свойства (properties)
Компонентная Система
Рендер
Физика
Редактор UnigineEditor
Обзор интерфейса
Работа с ассетами
Контроль версий
Настройки и предпочтения
Работа с проектами
Настройка параметров ноды
Setting Up Materials
Настройка свойств
Освещение
Sandworm
Использование инструментов редактора для конкретных задач
Расширение функционала редактора
Встроенные объекты
Ноды (Nodes)
Объекты (Objects)
Эффекты
Декали
Источники света
Geodetics
World-ноды
Звуковые объекты
Объекты поиска пути
Player-ноды
Программирование
Основы
Настройка среды разработки
Примеры использования
C++
C#
UnigineScript
UUSL (Unified UNIGINE Shader Language)
Плагины
Форматы файлов
Материалы и шейдеры
Rebuilding the Engine Tools
Интерфейс пользователя (GUI)
Двойная точность координат
API
Containers
Common Functionality
Controls-Related Classes
Engine-Related Classes
Filesystem Functionality
GUI-Related Classes
Math Functionality
Node-Related Classes
Objects-Related Classes
Networking Functionality
Pathfinding-Related Classes
Physics-Related Classes
Plugins-Related Classes
IG Plugin
CIGIConnector Plugin
Rendering-Related Classes
Работа с контентом
Оптимизация контента
Материалы
Визуальный редактор материалов
Сэмплы материалов
Material Nodes Library
Miscellaneous
Input
Math
Matrix
Textures
Art Samples
Учебные материалы
Внимание! Эта версия документация УСТАРЕЛА, поскольку относится к более ранней версии SDK! Пожалуйста, переключитесь на самую актуальную документацию для последней версии SDK.
Внимание! Эта версия документации описывает устаревшую версию SDK, которая больше не поддерживается! Пожалуйста, обновитесь до последней версии SDK.

Растительность: советы по созданию

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

Полигональные растения#

Модели растений на основе полигональных сеток следует использовать для крупных планов и средних расстояний для наиболее реалистичного представления реальной зелени. Крайне важно использовать оптимизированные 3D-модели деревьев в проектах реального времени.

В этом разделе вы познакомитесь с некоторыми советами по созданию растительности в UNIGINE и стороннем программном обеспечении для создания цифрового контента.

Моделирование#

При подготовке 3D-модели дерева с густой листвой избегайте создания топологии для всех ветвей и листьев; вместо этого гораздо эффективнее с точки зрения производительности имитировать мелкие детали с помощью текстур. Главное правило моделей, оптимизированных для использования в реальном времени, — «чем меньше полигонов — тем лучше». Следование этому правилу гораздо важнее для рендеринга густого леса, наполненного различными видами растений и трав.

Поэтому настоятельно рекомендуется подготовить несколько уровней детализации ( LOD ) для использования растения на разном расстоянии от камеры.

Общий рабочий процесс моделирования дерева выглядит следующим образом:

  1. Смоделируйте несколько небольших веток с листьями и запеките модели в атласы текстур — полученные текстуры будут текстурами вашей листвы. Вот примеры таких текстур:

  2. Создавайте низкополигональные сетки, которые будут представлять собой фрагменты листвы, накладывайте UV-развертку для правильного текстурирования. Кусочки не обязательно должны быть плоскими, вы можете поэкспериментировать с формой и изгибом сетки. Также важно подготовить как минимум 3 LOD, поэтому обязательно оптимизируйте сетки LOD в полной мере:

    Branches

    LOD для листвы
  3. Создайте ствол с большими ветвями и уровнями детализации для него. Подготовьте и назначьте необходимые текстуры и материалы.

    LOD багажника

    Также рекомендуется перенести нормали от ствола к примыкающим вершинам ветвей, чтобы придать суставам более естественный вид:

    Скорректированные нормали ветвей на стыках обеспечивают более естественный вид
  4. Распределите LOD кусков листвы по ветвям соответствующих LOD ствола, образующих крону дерева:

    Tree LODs

    Тот факт, что одинаковое количество чанков используется во всех LOD, может привести к увеличению количества полигонов. Однако такой подход имеет ряд преимуществ:

    • Большое разнообразие ветвей позволяет создавать более реалистичные растения.
    • Лучший, почти бесшовный переход между уровнями детализации. Все элементы можно в любой момент откорректировать, чтобы избавиться от каких-либо несоответствий.
    • Более либеральный художественный конвейер позволяет художникам собирать деревья разного размера и возраста из одних и тех же фрагментов.
    • Точная работа постэффектов даже на самых низких LODах (SSAO, SSGI и т.д.).
  5. Также рекомендуется создать отдельный LOD с низкой детализацией листвы, чтобы упростить отбрасывание теней. Вы можете продублировать самый низкий LOD и еще больше оптимизировать его для этой цели и настроить отбрасывание теней в УНИГИНЕ.
  6. Для лучшего слияния с рельефом подготовьте отдельную нижнюю часть ствола с назначенным новым материалом. Вы можете объединить его с сеткой самого высокого уровня детализации для удобства:

    Bottom part of the tree for blending with terrain

  7. Ориентировать модель чтобы он был импортирован в UNIGINE соответствующим образом, сбросьте все преобразования.

    Обратите внимание на правильное положение опорной точки меша (видимо, все LOD должны иметь одинаковое положение). Как правило, стержень размещают в самой нижней точке растения для удобства проектирования мира. Однако вы можете изменить положение оси вращения, если это необходимо для стеблевая анимация .

  8. В результате модель имеет следующее содержание:

    Для удобства рекомендуется добавлять постфиксы к названиям уровней детализации, которые будут использоваться в дальнейшем при импорте.

  9. Рассмотрите возможность дальнейшей корректировки нормали вершин цвета вершин и UV для листья анимация .
  10. Экспорт модели в рекомендуемый формат FBX.

Настройка внешнего вида растения#

Импортируйте созданную модель в UNIGINE, следуя Руководство по импорту FBX а также добавить растение на сцену .

Чтобы сделать все отдельные объекты поверхностями одного Mesh Static, включите Объединить статические сетки в настройках импорта.

Настройка уровней детализации#

Установите дистанцию видимости для LOD включив опцию Combine By Postfixes и изменив значения в настройках импорта.


Теневой LOD#

Когда динамическое отбрасывание теней используется, все полигоны рендерятся еще раз для каждого источника света с включенными тенями. Источники света World могут иметь до 4 каскадов теней, поэтому количество полигонов, визуализируемых в карты теней, может быть огромным, что приводит к сильному снижению производительности. Оценить это число можно с помощью Профилировщик рендеринга .

Вот почему лучше всего использовать низкополигональную сетку для теней листвы. Выполните следующие шаги:

  1. Отключите отбрасывание теней для всех LOD листвы, кроме LOD Shadow. Вы можете сделать это одним из следующих способов:

  2. Скройте теневой LOD для любой камеры, отключив все ее биты. Маска видового экрана .

См. демонстрацию настройки теневого LOD в Видеоурок по битовой маскировке.

Настройка материалов#

Если в опциях импорта был включен флаг Import Materials, все необходимые материалы уже сгенерированы и назначены поверхностям дерева. Рассмотрим параметры материала, на которые стоит обратить внимание:

  • Сделайте материал листьев Alpha-Test, чтобы вырезать тексели в соответствии с альфа-каналом текстуры Albedo.
  • Если зеркальные блики некорректны, рекомендуется установить значение Specular на 0.

    Incorrect lighting on flat leaves

    Неправильное освещение в предварительном просмотре отладки рендеринга отражений (слева) и итоговом изображении (справа)
  • Рассмотрите возможность включения опции Two Sided для материала, чтобы сделать листву более плотной. Будьте осторожны, так как это может значительно повлиять на производительность, если в сцене слишком много полигонов.

    Может быть лучше переключить режим Backside Normal на параметр To Front Side, так как он обычно дает более реалистичные результаты для листвы.

  • Если текстуры делают очевидным, что листва состоит из плоских кусков, отличным решением этой проблемы является функция Angle Fade, которая вырезает полигоны, обращенные к камере под экстремальными углами.

    Примечание
    Эта функция может работать некорректно для мешей с модифицированными нормалями.
  • Настройка прозрачности материала листвы необходима для лучшего вида. Увеличьте значение Translucent, чтобы позволить свету проходить через объект.

    Вы также можете включить использование Translucent Map на вкладке States, чтобы указать одноканальную текстуру, которая будет определять непрозрачные части объекта (например, ветви).

    Примечание
    Нет необходимости прорисовывать волокна и мелкие детали листьев на полупрозрачной текстуре, если Обычный карта используется и определяет такие неровности поверхности.
    Текстура альбедо
    Полупрозрачная текстура
  • Включите флаг Terrain Lerp для материала нижней части дерева, чтобы смешать ваше дерево с Местность в вашей сцене.

Настройка нормалей вершин#

Тот факт, что листва состоит из плоских кусков, приводит к неточному затенению. Чтобы противодействовать этому и скрыть плоскостность меша, отрегулируйте нормали вершин и затените листву.

Возможны следующие решения:

  • Включите параметр Normals Rotated To Camera, чтобы все нормали поверхности были ориентированы на камеру, игнорируя нормали геометрии. Эта функция зарекомендовала себя как быстрое решение, хотя она делает все полигоны заштрихованными одинаково.

  • Отредактируйте нормали вершин вручную в программном обеспечении для моделирования. Перенесите нормали вершин из граничной клетки, чтобы листва выглядела как гладкая и густая крона дерева.

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

    Transferring normals from a boundary cage

    Перенос нормалей из граничной клетки

    В результате плоскостность геометрии листвы менее заметна (справа):

MIP-карты#

Техника MipMapping , поддерживаемая средством визуализации UNIGINE, подразумевает выборку более низких текстур для более мелких и удаленных полигонов. При этом мелкие черты листвы начинают стираться с расстоянием. В некоторых случаях ветки и листья вдали от камеры выглядят толще, чем на крупном плане.

MIP maps

MIP-карты

Эта проблема может быть решена с помощью следующих подходов:

  • Включите функцию Mip Bias, чтобы сместить расстояние, на котором выполняется переключение между уровнями MIP. Этот параметр существенно влияет на производительность.
  • По умолчанию карты MIP для текстуры генерируются автоматически при импорте с использованием фильтрации Box, которая может давать слишком размытые результаты. Попробуйте переключиться на тип фильтрации Point, чтобы получить более четкие карты MIP.
  • Вы также можете подготовить пользовательские карты MIP в стороннем программном обеспечении. Например, вот сравнение карт MIP, созданных с использованием фильтрации Box и более четкой фильтрации Kaiser:

    Чтобы импортировать текстуру с пользовательскими уровнями MIP, используйте опцию Combine для текстуры с выложенными уровнями MIP или сохраните их в формате .dds и импортируйте текстуру с включенной опцией Unchanged.

Анимация#

Включите состояние Vegetation, чтобы активировать набор параметров, связанных с анимацией.

Vegetation options

Анимация растительности состоит из Корень а также Листья анимация. Чтобы включить их оба, установите Animation в параметр Default или Field.

При этом Field Animation делает растение уязвимым Полевая анимация объемы, позволяющие вам локально переопределять параметры анимации (например, симуляция эффектов нисходящей струи несущего винта в непосредственной близости от винтокрылого аппарата).

Анимация стеблей#

Анимация стебля применяет перемещение вершин на основе пространственного 3D-шума, чтобы имитировать изгиб ствола или стебля растения, вызванный ветром. Точка вращения меша считается фиксированной, и чем дальше вершина находится по оси Z, тем сильнее к ней применяется движение.

Таким образом, необходимо правильно расположить точку вращения (обычно это самая нижняя точка стержня) и сориентировать модель так, чтобы ось Z была направлена вверх.

Stem animation preview

Пример анимации стебля

Набор Параметры управляет анимацией.

Animation parameters

Обратите внимание, что все поверхности растения должны иметь одинаковые параметры анимации стебля, чтобы синхронизировать их движение.

Different stem animation parameters result in not synchronized parts of the tree

Различные параметры анимации ствола приводят к несинхронизированным частям дерева

Анимация листьев#

Анимация листьев — это еще один уровень анимации вершинного шейдера, в основном применяемый к листве, обеспечивающий дополнительное изгибание деталей. Использование этого типа анимации требует предварительной корректировки геометрии на этапе моделирования.

Несколько подходов анимация листьев доступна из коробки. Выберите тип анимации, используя опцию Leaves.

Геометрия на основе цвета вершин#

Этот рекомендуемый подход, обеспечивающий наилучший контроль над листвой, подразумевает, что листья визуализируются как многоугольники, а цвета вершин используются для анимации.

Движения растительности определяются RGB-каналами цветов вершин следующим образом:

Красный канал используется для анимации более мелких или периферийных частей растительности (листьев). Яркие части анимированы, а темные — жесткие.
Зеленый канал используется для определения порядка движения ветвей с целью их десинхронизации. Последовательность движений начинается от самого яркого элемента к самому темному.
Синий канал используется для определения того, какие части ветвей можно сгибать. Более светлые участки обозначают сгибаемые участки, а более темные участки   —   жесткие участки.

То параметры анимации управление движением вершин:

Также регулярно используется анимация ветвей с помощью этой техники, даже если они прикреплены к стволу:

Зеленый и синий каналы определяют движение вершин; Красный канал не используется для ответвлений

При этом связанные поверхности должны иметь одинаковые цвета вершин на соседних вершинах и одинаковые параметры анимации, чтобы синхронизировать их движение:

Цвета смежных вершин ствола и листвы одинаковы, поэтому при анимации геометрия остается связанной.

Геометрия Анимация листьев на основе цвета вершин
Геометрия на основе UV#

Это довольно устаревший подход, когда листья визуализируются как стандартные полигоны. Это требует, чтобы UV Channel 2 был определен для сетки.

Геометрическая анимация на основе UV
UV Channel 2: самые жесткие вершины находятся в верхнем левом углу.

Анимация использует UV-канал 2 объекта следующим образом: в UV-сетке [0,1] — точка опоры для движений объекта и самая жесткая часть объекта, а ближе к [1,0] объект становится более гибким. .

Управляйте движением вершин через тот же Параметры анимации .

Billboard#

Billboard — наиболее удобный способ анимации удаленной растительности: все четырехугольники визуализируются как billboards, которые всегда смотрят в камеру; UV Channel 2 определяет размер и движение полигонов. Следовательно, меш листвы должен содержать только четырехугольники для листьев.

Куст на основе рекламных щитов
Сетка куста

Анимация использует UV-канал 2 объекта следующим образом: в UV-сетке [0,1] является точкой опоры для движения рекламного щита, а размер рекламного щита можно изменить, масштабируя полигон в UV-канале.

УФ канал 1
УФ канал 2
Сетка (вверху) и результат (внизу)

Управляйте движением полигонов через тот же Параметры анимации .

Глобальные параметры анимации#

Анимация стебля и листьев также контролируется глобальным Параметры анимации растительности . С помощью этих настроек вы можете глобально настроить интенсивность анимации стеблей и листьев, скорость и эффект ветра, а также контролировать погодные условия в каждом мире.

Обратите внимание, что глобальные параметры — это просто множители для параметров анимации для каждого материала.

Рассадка растений#

Для случайной расстановки большого количества одинаковых мешей по местности используется Mesh Clutter. Mesh Clutter процедурно распределяет объекты и отображает только те объекты, которые находятся в области видимости. Типичный алгоритм выглядит следующим образом:

  1. Нажмите Create -> Clutter -> Mesh и укажите ресурс .mesh, который будет использоваться в качестве исходного меша для Mesh Clutter. Щелкните внутри вьюпорта, чтобы разместить новый узел в мире.

    Примечание
    Ассеты .fbx являются контейнерами для ассетов .mesh, щелкните правой кнопкой мыши ассет и выберите Open или дважды щелкните его, чтобы получить доступ к его содержимому.
  2. Если у вас уже есть настроенное дерево в вашем мире, вы можете скопировать все материалы и параметры с поверхностей настроенного дерева и вставить их последовательно или по именам поверхностей до 0_фл.

  3. Поместите узел в сцену и установите Size, чтобы покрыть всю игровую область.

    Примечание

    Операции с объектами Mesh Clutter основаны на числах с плавающей запятой, поэтому не рекомендуется использовать размеры, превышающие 10000 по длине и ширине. Если вам нужно заполнить области за пределами этого предела, вам нужно будет вручную разделить один объект Mesh Clutter на сетку из нескольких помех.

    Инструмент Sandworm автоматически выполняет нарезку при создании ландшафта.

  4. Настройте параметры рассеяния: установите желаемое Плотность в ячейках на единицу площади; разнообразить внешний вид леса, рандомизировав Масштаб, смещение и поворот параметры.
  5. Сделайте объект беспорядка дочерним по отношению к ландшафту и включите Перекресток флаг, чтобы деревья следовали за поверхностью.

    Примечание
    Если флаг Intersection включен, включите и выключите его, чтобы принудительно повторно сгенерировать объект Clutter.
  6. Настроить Видимость а также Тускнеть расстояния. Учитывая количество полигонов, которые могут вступить в игру в густом лесу, рекомендуется сделать Mesh Clutter видимым на как можно более коротких расстояниях и использовать объекты Impostor на более дальних расстояниях.
  7. По умолчанию деревья разбросаны по всей территории. Ты сможешь маскировать участки растительностью с помощью следующих подходов:

    • Используя одноканальную текстуру. Вы можете подготовить текстуру в стороннем ПО или создать новую и нарисовать маску с нуля. Все объекты Mesh Clutter и Grass, использующие эту текстуру, обновляются на лету.

    • Используямаски Landscape Terrain. Вы можете использовать данные масок Landscape Terrain для определения плотности растительности, при условии, что ваш мир содержит Landscape Terrain с настроенными масками: выберите нужную маску в параметре Mask Terrain:

      Ландшафтная местность
      Предварительный просмотр маски ландшафтного ландшафта
      Растительность разбросана согласно маске местности

      Вы также можете отредактировать маску с помощью Редактор кистей и обновлять Mesh Clutter на лету.

      Примечание
      Все данные ландшафтного ландшафта, включая маски, подлежат потоковая передача данных . Если у вас неоптимизированные настройки потоковой передачи, узким местом может быть загрузка данных маски при запуске мира и изменение положения камеры, что влияет на производительность генерации Mesh Clutter.
    • В качестве дополнительной функции, маскировка сеткой также доступен:

    • Вырез по пересечению с объектами:

      1. Создайте Mesh Static или Decal, представляющий ограничивающий объем выреза. Включите для него флаг Clutter Interaction.
      2. Выберите и включите часть маски Intersection объекта, которая будет использоваться для функции выреза.
      3. Включите тот же бит маски Cutout Intersection объекта Clutter.
      4. Скрыть визуальное представление объекта от камеры, отключив все биты его маски Viewport и отключив отбрасывание теней для этого.

      Удаление растительности внутри прямоугольной области
  8. Сохраняйте оптимальное значение Step для лучшей производительности.

    Clutter визуализируется как 2D сетка, в каждой ячейке которой случайным образом разбросаны сетки в зависимости от плотности и вероятности появления. Генерация сеток в ячейках осуществляется с временным интервалом, начиная с ближайших ячеек, чтобы снизить нагрузку на ЦП.

    Деление клеток

    Значение Step определяет размер ячейки в единицах. Таким образом, это значение указывает результирующее количество ячеек по каждой оси (размер, деленный на шаг). Настоятельно рекомендуется выбирать значения, которые делятся без остатка .

    Примечание
    Для каждой ячейки требуется DIP -вызов 1, поэтому чем больше количество ячеек (т. е. чем меньше шаг), тем больше снижается производительность. Однако создание большой ячейки занимает больше времени. Когда камера движется достаточно быстро, маленькие ячейки создаются одна за другой очень быстро и плавно, но большие могут заметно всплывать в поле зрения и вызывать небольшую задержку рендеринга.

Таким же образом можно разбрасывать кусты и куски многоугольной травы по местности.

Кусок оптимизированной полигональной травы

Наконец, комбинируя несколько зарослей для разных типов деревьев, кустов и травы, вы получаете разнообразный вид растительности.

Комбинация нескольких объектов Mesh Clutter для разнообразной растительности

Ручная расстановка#

В качестве последнего штриха вы можете разместить деревья как Static Mesh там, где это необходимо. Эффективно с точки зрения производительности собрать значительное количество идентичных мешей в объект Mesh Cluster, чтобы обрабатывать и отображать кучу мешей как один объект.

Примечание
С точки зрения оптимизации производительности объекты Mesh Cluster имеют преимущество перед объектами Mesh Clutter, поскольку сетки, запечённые в кластеры, поддерживают отбраковку Окклюдеры , что позволяет повысить производительность, когда их перекрывает какая-либо геометрия (например, здание).

Вы можете запечь одинаковые меши своей иерархии или собрать все подобные меши в мире. Подробную информацию о способах сбор кластера .

Другой удобный подход к быстрому распределению скоплений травы, кустов и деревьев по сцене — это использование инструмента «Кисть размещения сетки»:

  1. Переключиться на Cluster Editor Режим:

  2. Выберите один или несколько объектов Mesh Cluster в сцене или создайте новый с помощью кнопки Create в окне Active Tool.
  3. Закрашиваем области кистью, раскидывая сетки по сцене:

  4. Если нужно, редактировать кластер вручную, чтобы изменить положение или удалить некоторые сетки.

Billboard#

Billboard — это плоский прямоугольный объект, который всегда обращен к камере. Использование billboards вместо полнофункциональных объектов, которые едва видны издалека, значительно упрощает и ускоряет рендеринг.

Импосторы#

С точки зрения UNIGINE, Impostor — это объект, подобный billboard, способный имитировать внешний вид полигональных сеток, отображая различные области текстур в зависимости от угла обзора. Объекты Impostor служат для ускорения рендеринга геометрии за счет уменьшения количества полигонов при сохранении визуальной точности.

Текстура альбедо для самозванца дерева

Встроенный инструмент Impostor Creator упрощает создание Impostors для одиночных сеток и Mesh Clutters.

Для леса на основе Mesh Clutter объект Grass с материалом grass_impostor_base будет использоваться как низкополигональный LOD. При этом Clutter и параметры травы должны совпадать, чтобы положение и ориентация всех LOD были одинаковыми.

Mesh Clutter и самозванцы
Каркасы мешей и самозванцев

Объекты травы также визуализируются как 2D-сетка для оптимизации производительности. Параметр Step определяет размер ячейки. Обычно импосторы видны гораздо дальше, чем меши, и соответственно нужно выбирать значение Step. Вы можете использовать параметр Subdivision, который разделяет большие ячейки травы так, чтобы они соответствовали меньшим ячейкам Mesh Clutter, чтобы совместить положения случайно разбросанных объектов с позициями самозванцев на основе травы. Следовательно, Clutter Step должен соответствовать соотношению значений Step/Subdivision травы.

Трава#

Объект Grass с материалом grass_base может заполнять пустые места на местности и увеличивать общую плотность нижней растительности в сцене. Материал grass_base предназначен для представления основных характеристик травы. Он имеет более низкую визуальную точность по сравнению с материалом mesh_base, поэтому Grass следует рассматривать как дополнительный заполняющий слой травы.

Во-первых, вам нужно подготовить текстуру Diffuse с фрагментами, представляющими небольшие пучки травы:

Диффузная текстура для травы разных типов

Чанки размещаются в текстуре следующим образом:

  • Вертикальные столбцы представляют разные виды трав, каждый из которых будет распределен согласно соответствующему каналу текстуры Mask. Поэтому количество столбцов должно совпадать с количеством каналов текстуры Mask; в противном случае пучки травы будут срезаны неправильно.
  • Горизонтальные ряды представляют вариации травы определенного вида (тоньше, гуще, спутаннее и т. д.). Строков может быть от 1 до 4, и это число должно совпадать со значением Num Textures.

Для текстуры травы со столбцами 4 следует использовать маску с 4 каналами:

RGBA Маска-изображение для травы 4 -х различных типов

Обратитесь к разделу Texture Slots для более подробной информации.

Однако визуально привлекательная трава может снизить производительность, если она отображается целиком. Все вычисления разделены по времени и выполняются для каждой ячейки 2D-сетки, что позволяет выполнять рендеринг с интерактивной частотой кадров. Поэтому выбор оптимального Step для ячеек имеет решающее значение для повышения производительности.

Дополнительные сведения о создании и настройке травы см. в подробном руководстве: Добавление травы .

Смотрите также#

Последнее обновление: 23.06.2023
Build: ()