Введение
Данный раздел рекомендуется прочитать тем, кто только начал работать с UNIGINE, чтобы ознакомиться с терминологией и основными принципами работы.
Как устроены виртуальные миры#
Проект#
Когда вы приступаете к разработке приложения в UNIGINE, вы создаете проект. Проект содержит в себе код, контент и метаданные разрабатываемого приложения.
Проект может состоять из одной или нескольких многокомпонентных 3D сцен, которые называются мирами (worlds).
Управление проектами осуществляется через UNIGINE SDK браузер.
Мир#
Виртуальный мир (world) в UNIGINE представляет собой 3D-сцену, которая включает в себя множество различных нод (nodes), таких как статическая геометрия, источники освещения, камеры и т. д., организованных в графы сцены, которые установлены в определенном положении, а также глобальные настройки (рендеринг, физика и пр.), которые применяются ко всей сцене.
Граф сцены в UNIGINE — это иерархическая древовидная структура нод.
Каждый мир представлен XML-файлом с расширением .world.
При создании нового проекта через SDK браузер создается и новый *.world файл, имя которого идентично названию проекта.
Для редактирования существующих миров и создания новых используется редактор UnigineEditor. Количество создаваемых миров не ограничено.
Нода#
В UNIGINE все объекты, добавляемые в сцену, называются нодами (nodes). Ноды могут быть различных типов в зависимости от своего визуального представления и поведения.
Различные типы встроенных нод отвечают практически любым запросам пользователей. При необходимости, пользователь может добавить свой тип ноды вручную.
Кроме того, функциональность любой ноды можно расширить посредством добавления к ней необходимых компонентов.
У каждой ноды есть своя матрица трансформации, которая определяет положение, вращение и масштаб ноды в виртуальном мире.
Есть ноды, которые имеют визуальное представление: объекты, эффекты и декали. У них есть поверхности, которые определяют их геометрию (полигональную сетку). Остальные типы нод (источники освещения, камеры и т. д.) невидимы.
Параметры нод, как правило, хранятся в файле с расширением .world, но могут храниться и в отдельных XML-файлах с расширением .node. На эти файлы можно ссылаться из файла .world через ссылочные ноды (Node References) — специальные ноды, которые используются для подгрузки нод).
Меш#
Меш (mesh) — это набор полигонов, который определяет геометрию объекта. Ему присущи следующие особенности:
- у каждого меша есть одна или несколько поверхностей;
- максимальное число полигонов, из которых может состоять поверхность, равняется 2 147 483 647 (для ObjectMeshStatic и ObjectMeshSkinned) или 65 535 (для ObjectMeshDynamic);
- 2 UV-канала для текстурирования;
- поддержка цветов вершин.
Анимацию в UNIGINE можно реализовать с использованием скелетной анимации (skinned mesh), морфинговых объектов (morph targets) — ключевых кадров или динамических мешей (dynamic mesh) — через код.
В среде выполнения меши хранятся в собственных форматах UNIGINE с расширениями .mesh (статический меш + дополнительные данные об анимации) и .anim (внешние данные об анимации).
Импорт модели FBX в движок подразумевает автоматическую конвертацию в формат .mesh.
Поверхность#
Поверхность (surface) — это подмножество геометрии (т. е. меша) объекта, не перекрывающее другие подмножества. Для каждой поверхности можно назначить собственный материал или свойство. Кроме того, каждую из поверхностей независимо от других можно включить или выключить.
Поверхности внутри меша можно организовать в иерархию и использовать для переключения между уровнями детализации (LOD).
3D меш солдата на иллюстрации ниже состоит из четырех поверхностей: глаза, кожа, экипировка (броня, рация, сумки) и обмундирование (одежда, обувь, каска, перчатки).
Материал#
В терминах UNIGINE материал (material) — это правило, которое определяет, как будет выглядеть поверхность: ее взаимодействие с источниками освещения, параметры отражения и т. д. В основе этого правила лежат:
- вершинный, фрагментный и геометрический шейдеры, которые по факту и рисуют материал, учитывая различные условия;
- назначенные пользователем текстуры, которые передаются в шейдеры;
- режимы, задающие условия, на основе которых применяются те или иные шейдеры;
- параметры, которые определяют, каким именно способом будут использоваться шейдеры.
В UNIGINE есть готовый набор встроенных базовых материалов. При работе с материалами рекомендуется унаследовать пользовательский материал от базового и откорректировать настройки для получения желаемого результата. Вы можете сами создать шейдеры при помощи языка UUSL (Unified UNIGINE Shader Language) или HLSL/GLSL, но тогда вам придется самостоятельно переносить их при каждом релизе SDK.
Помимо обычных материалов, которые применяются к поверхностям, существуют так называемые материалы для постобработки, которые применяются поверх финальной картинки (например, для создания эффекта ночного видения или тепловизора). Вы можете создавать собственные пост-эффекты при помощи нестандартных пост-материалов и шейдеров.
Иерархия материалов#
Материалы организованы в иерархию с учетом наследования параметров и перегрузки (примерно как в объектно-ориентированном программировании). При наследовании материала все его параметры наследуются от родительского материала. Если для родителя изменяется значение какого-либо параметра, оно автоматически изменяется и во всех его дочерних материалах, за исключением тех, в которых оно до этого переопределялось (корректировалось) вручную.
Например, материал A имеет два параметра (цвет — синий и коэффициент отражения 1,4), а материал Б унаследован от материала A, и его цвет после этого изменили вручную (на красный). При изменении коэффициента отражения у материала А на 2,0 у материала Б будут следующие параметры: цвет — красный (переопределенный) и коэффициент отражения 2,0 (унаследованный).
Наследование параметров очень удобно для массового контроля значений параметров нескольких материалов.
Свойство#
Свойство (property) — это “материал”, применяемый для логики приложений. При помощи свойства определяется поведение объекта и его взаимодействие с другими объектами и самим виртуальным миром. У свойств могут быть различные типы параметров — от обычного целого числа для подсчета заработанных персонажем очков до ноды, материала или файла (для текстур, мешей, звуков и т. д.), или свойства, тем самым упрощая доступ к различным ресурсам.
Свойства можно использовать для создания компонентов, чтобы расширить функциональность нод.
Свойства, как и материалы, организованы в иерархию с наследованием параметров. Но в отличие от материалов, свойства могут применяться либо к поверхности, либо к ноде.
Как добавлять контент в виртуальный мир#
Каждый элемент контента, который может использоваться в вашем мире или проекте, называется ассет (asset). Ассет может быть получен из файла, созданного при помощи стороннего приложения, например 3D модель, аудиофайл, изображение или любой другой тип файла, который поддерживается движком UNIGINE.
Основным инструментом для доступа к системе ассетов является браузер ассетов в UnigineEditor. Он используется для организации контента в проекте: создания, импорта, просмотра и переименования ассетов, а также их перемещения из папки в папку и управления их иерархией.
Каждый раз при создании или импорте ассета редактор UnigineEditor проделывает всю необходимую работу, включая конверсию ассетов (будь то JPG-текстура или FBX-модель) в свой формат (например, сжатые текстуры .dds, геометрия .mesh, анимации .anim и пр.), который используется движком в среде выполнения. В результате такой конверсии генерируются файлы среды выполнения, и UnigineEditor обновляет их каждый раз, когда вы вносите изменения в соответствующий ассет.
Более подробную информацию о работе системы ассетов можно найти в статье Assets Workflow.
UnigineEditor#
При помощи редактора UnigineEditor можно собрать виртуальный мир — импортировать и размещать в пространстве ноды, добавлять им материалы и свойства, выставлять освещение, а также корректировать глобальные настройки (такие как физику и рендеринг). Наш редактор практикует подход "Что видишь, то и получаешь", то есть вы сразу же видите финальный вариант сцены (как в среде выполнения).
Об импорте 3D моделей в UNIGINE мы рассказываем в этом обучающем видеоролике:
Как мы видим виртуальный мир#
Для визуализации UNIGINE использует стандартную перспективную проекцию. Также можно переключиться на ортографическую проекцию.
В процессе отображения виртуального мира задействованы три сущности:
- Камера (camera) — структура, содержащая две матрицы: вид и проекцию. Через эту структуру устанавливаются параметры камеры: поле зрения, маски, ближняя и дальняя плоскости отсечения и постпроцессные материалы. Затем камера передает параметры в окно просмотра, которое воспроизводит изображение с этой камеры. Камера привязывается к персонажу, который контролирует положение камеры.
- Окно просмотра (viewport) получает параметры камеры и воспроизводит полученное от нее изображение на экран. Кроме того, оно обеспечивает все функции главного рендерера, такие как рендеринг кубических текстур, стерео-рендеринг или панорамный рендеринг.
- Персонаж (player) — это нода, которая управляется через устройства ввода (клавиатура, мышь, джойстик). К ней привязана камера. Как только персонаж меняет положение в пространстве, матрица вида с его внутренней камеры тоже изменяется.
В UNIGINE есть несколько типов персонажей: Player Dummy, Player Actor, Player Persecutor и Player Spectator.
Освещение#
Освещение в мирах создается путем размещения источников освещения. У этих нод есть параметры, с помощью которых можно настроить различные характеристики света, такие как яркость, цвет и т. д. Для настройки источников освещения можно использовать и физические параметры, такие как цветовая температура и освещённость.
Различные типы источников излучают свет различными способами. Например, лампочка излучает свет во всех направлениях. В UNIGINE она представлена источником ненаправленного освещения (omni light). Фонарь или фары автомобиля излучают свет в виде конуса в определенном направлении, представляя собой источник направленного освещения (projected light). Лучи света от солнца кажутся параллельными, поскольку их источник находится на очень большом расстоянии. Для имитации такого типа освещения в UNIGINE применяется источник глобального освещения (world light).
Подробнее об освещении в UNIGINE смотрите в обучающем видеоролике по освещению.
Рендеринг#
UNIGINE сочетает полностью отложенный рендеринг с применением методов прямого рендеринга:
- вся непрозрачная геометрия отображается на отложенном этапе (deferred pass);
- прозрачная геометрия отрисовывается на этапе прямого рендеринга (forward pass).
Более детальная информация о применяемых методах рендеринга приводится в статье Rendering Sequence.
Все настройки рендеринга (глобальное освещение, тени, сглаживание контура, пост-эффекты и т. д.) можно регулировать через настройки рендеринга в UnigineEditor и сохранять в файле с расширением *.render для последующего использования. Каждый проект содержит настройки для предустановок низкого, среднего, высокого и ультравысокого качества, а также оптимизированные настройки для оптимальной работы в VR. Для того чтобы применить необходимые настройки, выберите их двойным щелчком в браузере ассетов (Asset Browser).
Как мы слышим звуки#
Помимо визуальной составляющей, важным компонентом технологий реального времени является звук. Именно звук создает ощущение погружения в виртуальный мир. Раскатистое эхо, которое заставляет думать, что действие происходит в просторном здании, мягкий перестук шагов по каменному полу или промчавшийся мимо автомобиль — все это можно смоделировать. UNIGINE представляет систему многоканального звука с поддержкой стереозвука на основе функции HRTF (функции моделирования восприятия звука), различные 3D эффекты, преграждение и множественная реверберация звука. Можно задать проигрывание звука в формате MP3, WAV или OGA при контакте объектов для имитации их физических свойств на уровне звука. К движущимся объектам применяется эффект Допплера с целью достоверной имитации движения источника звука по отношению к слушателю.
Все настройки звука регулируются через настройки звука в UnigineEditor. Можно сохранять настройки в файлы формата *.sound для последующего использования.
Как задается физическое поведение#
В UNIGINE реализована упрощенная ньютоновская физика. Сценарии, в которых использование физических свойств будет более оптимальным, чем жёстко запрограммированная анимация объектов:
- определение коллизий (предотвращение прохождения через стены);
- имитация идеально упругих столкновений (перераспределение кинетической энергии);
- имитация простых механизмов, представленных твердыми телами и разрушаемыми соединениями;
- имитация основных физических явлений: гравитация, трение, выталкивающая сила;
- процедурное разрушение мешей;
- имитация движения тканей и шнуров.
Для симуляции физики отводится собственное количество кадров в секунду, а область действия задается дистанцией симуляции физики. Физические свойства могут задаваться только для объектов.
Тело#
Чтобы объект мог участвовать во взаимодействиях с другими объектами или внешними физическими силами, нужно задать ему некоторые физические свойства. А для этого у объекта должно быть тело (body). Существует несколько видов тел: твердое (rigid body), тряпичная кукла (ragdoll body), разрушаемое (fracture body), шнур (rope body), ткань (cloth body), вода (water body) и траектория (path body).
Виртуальная физика тела, почти так же, как и в реальном мире, оперирует понятиями скорости, силы, массы, плотности и т. д.
Форма#
В отличие от тела, которое имитирует различные типы физического поведения, форма (shape) представляет собой некоторый объем (сфера, капсула, цилиндр, куб, выпуклый многоугольник), который твердое тело занимает в пространстве. У объекта, для которого имитируется физика, обычно есть одно тело и одна или несколько форм, которые отвечают за коллизию (столкновение) объектов друг с другом.
Определение коллизии#
Алгоритм определения коллизии позволяет установить точки соприкосновения форм и предотвратить их взаимное проникновение. Доступ к точкам соприкосновения и нормалям осуществляется через API.
Соединение#
Соединения (joint) используются для соединения нескольких объектов с учетом баланса масс и ограничения степеней свободы их движения относительно друг друга. В UNIGINE представлены различные виды соединений: жесткое (fixed joint), шарнирное (hinge joint), шаровое (ball joint), призматическое (prismatic joint), цилиндрическое (cylindrical joint), колесное (wheel joint) и подвеска (suspension joint).
Глобальные настройки физики#
В UNIGINE есть глобальные настройки физики (гравитация, коэффициент проницаемости и т. д.), которые воздействуют на все физические объекты виртуального мира.
Как управлять виртуальным миром#
Языки программирования#
Для реализации логики проекта в UNIGINE могут использоваться следующие языки программирования:
- C++ обеспечивает максимальную производительность и эффективную интеграцию с существующей базой исходного кода.
- C# — разумное соотношение скорости и простоты использования.
- UnigineScript — скриптовый язык с мгновенной компиляцией и множеством полезных функций.
Все API унифицированы: любой из классов, методов и постоянных величин доступен через любой API, за исключением незначительных языковых отличий.
Дополнительная информация приводится в следующих статьях с примерами использования кода:
- UnigineScript API, C++ API and C# API usage examples
- Examples of UnigineScript extension using C++ API
- Examples of UnigineScript extension using C# API
Использование нескольких языков в одном проекте#
В UNIGINE предусмотрено использование разных языков программирования (C++, C# и UnigineScript) для разных частей проекта. Как правило, C++ используется для базовых классов и затратных по производительности операций; UnigineScript — для логики приложения. Можно обращаться к методам из одного API, используя другой, а также вручную расширить функциональность API. Можно обойтись и без этого и использовать только один язык, например, написать всё приложение только на C++.
Логика среды выполнения#
У приложений, разработанных на UNIGINE, есть собственный жизненный цикл, который состоит из определенных этапов. Какие-то из этих этапов выполняются однократно, остальные же отрабатываются каждый кадр. Схематически эти этапы можно представить следующим образом:
В UNIGINE есть три основных логических компонента. В каждом из них есть набор функций (которые называются init(), update(), render() и т. д.), содержащих действия, которые выполняются на соответствующих этапах рабочего цикла движка. Эти компоненты называются системная логика, логика мира и логика редактора.
-
Системная логика (system logic) включает в себя код, который выполняется в течение всего жизненного цикла приложения (его объем существует даже при переключении между мирами).
- Для приложений, написанных на UnigineScript, системная логика пишется в файле системного скрипта (unigine.usc).
- Для приложений на C++ создается файл AppSystemLogic.cpp, а для приложений на C# — AppSystemLogic.cs. Этот файл хранится в папке source/ вашего проекта. В файле уже реализованы методы для добавления кода.
-
Логика мира (world logic) — это логика виртуального мира. Эта логика используется, только когда загружен данный мир.
- Для приложений, написанных на UnigineScript, логика мира пишется в файле скрипта мира (файл *.usc с названием как у проекта); загружается и выгружается вместе с соответствующим миром.
- Для приложений на C++ создается файл AppWorldLogic.cpp, а для приложений на C# — AppWorldLogic.cs. Этот файл хранится в папке source/ вашего проекта и остается загруженным в течение всего рабочего цикла движка. В файле уже реализованы методы для добавления кода.
-
Логика редактора (editor logic) — это логика, которая действует только во время работы UnigineEditor.
- Файл логики редактора создается вручную и добавляется при помощи аргументов командной строки.
Рекомендуем более подробно изучить последовательность выполнения, в том числе и в многопоточном режиме.
Компонентная система#
Компонентная система (component system) позволяет реализовать логику приложения при помощи набора строительных элементов — компонентов и назначить эти элементы на ноды, тем самым расширяя их базовый функционал. Можно назначить компонент на ноду как через код, так и через UnigineEditor путем добавления соответствующего свойства.
Логика компонента реализуется внутри функций init(), update(), render()и т. д. Как и для основных компонентов логики, эти функции выполняются на соответствующих этапах рабочего цикла движка.
Логика компонента действует, только если включены соответствующая нода и компонент. То есть, при необходимости можно включать и выключать логику каждого отдельного компонента в среде выполнения.
На одну ноду можно назначить несколько свойств, которые соответствуют различным компонентам, а порядок выполнения логики компонентов можно корректировать в среде выполнения. Всё это обеспечивает гибкий подход и дает свободу действий в реализации любого возможного функционала.
Более детальная информация о компонентной системе представлена в соответствующей статье Component System.
Определение пересечения#
В UNIGINE реализован алгоритм быстрого определения пересечений, который может использоваться для бросания лучей (рэйкастинга), расчета линии прямой видимости, расчета высоты над уровнем поверхности и т. д.
Возможен также поиск пересечения между ограничивающими объёмами нод.
Примеры и демо-проекты#
В UNIGINE представлен обширный набор примеров и демонстрационных проектов, которые иллюстрируют основные принципы работы с движком (операции со встроенными нодами, настройки рендеринга и GUI и т. д.). Представлены примеры для каждого из трех языков программирования. Для всех примеров предоставлен исходный код. Посмотреть примеры можно в SDK браузере -> вкладка Samples.
Помимо этого в SDK входит набор демонстрационных сцен с контентом, иллюстрирующих возможности различных настроек встроенных объектов UNIGINE, использование уровней детализации и материалов, регулировку настроек рендеринга и параметров растительности. Эти примеры доступны в UNIGINE SDK браузере в качестве демо-проекта: откройте Samples -> Demos и установите демо-проект Samples.
Как оптимизировать проект#
UNIGINE предлагает широкий спектр инструментов оптимизации (например, уровни детализации и механизм битовых масок), чтобы ускорить работу приложения и повысить ее качество. Для их использования требуется определенная подготовка контента и соблюдение рекомендаций при его добавлении в проект.
Уровни детализации#
Чем проще геометрия 3D-объектов, тем меньше нагрузка на рендер. Поэтому при увеличении расстояния между камерой и объектами имеет смысл плавно переключаться между уровнями их детализации (LOD-ами).
Как правило, LOD-ы используются для переключения между следующими парами:
- высокополигональная поверхность меша — низкополигональная поверхность меша;
- поверхность со сложными для рендеринга материалами — поверхность с упрощенными оптимизированными материалами;
- несколько высокополигональных поверхностей меша — одна низкополигональная упрощенная поверхность меша;
- с одного типа ноды на другой, например, высокополигональный меш — биллборд (объект из двух полигонов, который всегда повернут лицом к камере).
Переключение между LOD-ами может быть связано с расстоянием не только от камеры, но и от какого-либо объекта.
В UNIGINE предусмотрено два механизма смены LOD-ов:
- Выключение одного LOD-а и включение другого на указанном расстоянии, которое задается двумя значениями: конец видимости первого LOD-а (Max Visibility) и начало видимости второго LOD-а (Min Visibility).
- Плавный переход (fade) между LOD-ами в указанном интервале, который задается двумя значениями: расстояние плавного появления первого LOD-а (Min Fade) и расстояние плавного исчезновения первого LOD-а / расстояние плавного появления второго LOD-а (Max Fade).
Более подробно об этом рассказывается в статье Setting up object LODs.
Механизм битовых масок#
Механизм битовых масок (bit mask) определяет, будут ли две сущности воздействовать друг на друга. Он может использоваться для того, чтобы:
- отображать определенные объекты в окне просмотра (viewport) и не отображать другие;
- применять коллизию для одних тел и не учитывать ее для других;
- отображать тени для одних объектов и не отображать для других;
- обеспечивать физическое воздействие на одни объекты и игнорировать другие.
Алгоритм битовых масок сравнивает 32-битные маски каждой пары нод, используя бинарный оператор и. Если маски совпадают, то один объект воздействует на другой; если не совпадают, то объекты взаимодействовать не будут.
Маски считаются совпадающими, если хотя бы один бит совпадает. Например, в иллюстрации ниже маски совпадают, поскольку у них них есть четыре совпадающих бита:
Более подробная информация об оптимизации контента представлена в нашем обучающем видеоролике:
Пора приступать к работе над своим первым проектом в UNIGINE.