Начало работы с виртуальной реальностью
This article is for anyone who wants to start developing Virtual Reality projects in UNIGINE and is highly recommended for all new users. We're going to look into the VR Sample demo to see what's inside and learn how to use it to create our own project for VR. We're also going to consider some simple examples of making modifications and extending the basic functionality of this sample.Эта статья предназначена для тех, кто хочет начать разрабатывать проекты виртуальной реальности в UNIGINE, и настоятельно рекомендуется всем новым пользователям. Мы рассмотрим демо-проект VR Sample, чтобы понять, что находится внутри, и научимся использовать его для создания собственного проекта виртуальной реальности. Мы также рассмотрим несколько простых способов того, как внести изменения и расширить базовую функциональность этого демо-проекта.
So, let's get started!Итак, давайте начнем!
VR SampleVR Sample#
Thinking about VR developers, we created the VR Sample demo, enabling you to jump straight in and start creating projects of your own. We recommend using this demo as a basis for your VR project.Думая о разработчиках виртуальной реальности, мы создали демо-проект VR Sample, который позволит вам сразу приступить к созданию собственных проектов. Мы рекомендуем использовать этот демо-проект в качестве основы для вашего VR-проекта.
The demo is based on the VR Template that supports all SteamVR-compatible devices out-of-the-box. It provides automatic loading of controller models in run-time. Additionally, the template includes the implementation of basic mechanics such as grabbing and throwing objects, pressing buttons, opening/closing drawers, and a lot more.Демо-проект основан на шаблоне VR Template, который поддерживает все устройства, совместимые со SteamVR, из коробки. Он обеспечивает автоматическую загрузку моделей контроллеров во время выполнения. Кроме того, шаблон включает в себя реализацию основных механик, таких как захват и бросание предметов, нажатие кнопок, открывание/закрывание ящиков и многое другое.
The sample project is created using the Component System, so the functionality of each object is determined by the components attached.Проект создан с использованием Компонентной системы, поэтому функциональность каждого объекта определяется подключенными компонентами.
You can extend an object's functionality simply by adding more components. For example, the laser pointer object has the following components attached:Вы можете расширить функциональность объекта, просто добавив дополнительные компоненты. Например, на объект "лазерная указка" назначены следующие компоненты:
- ObjMovable - enables grabbing and throwing an objectObjMovable - позволяет захватывать и бросать объект
- ObjLaserPointer - enables casting a ray of light by the objectObjLaserPointer - позволяет направить луч света на объект
1. Making a Template Project1. Создание шаблонного проекта#
So, well, we have a cool demo with some stuff inside, but how do we use it as a template? It's simple – just open your SDK Browser, go to the Samples tab, and select Demos.Итак, у нас есть классный демо-проект с некоторым наполнением, но как использовать его в качестве шаблона? Всё просто - откройте SDK Browser, перейдите на вкладку Samples и выберите Demos.
Find the VR Sample in the Available section and click Install. After installation, the demo will appear in the Installed section, and you can click Copy as Project to create a project based on this sample.Найдите VR Sample в разделе Available и нажмите Install. После установки демо-проект появится в разделе Installed, и вы можете нажать Copy as Project, чтобы создать проект на основе этого демо-проекта.
In the Create New Project window that opens, enter the name for your new VR project in the corresponding field and click Create New Project.В открывшемся окне Create New Project введите название вашего нового VR-проекта в соответствующее поле и нажмите Create New Project.
2. Setting Up a Device and Configuring Project2. Подключение устройства и настройка проекта#
Suppose you have successfully installed your Head-Mounted Display (HMD) of choice.Предположим, вы установили нужный вам VR-шлем (HMD).
Learn more on setting up devices for diffent VR platforms. If you have any difficulties, please visit the Steam Support. In case of Vive devices, this Troubleshooting guide might be helpful.Более подробную информацию о настройке устройств для различных платформ VR вы можете найти по этой ссылке. Если у вас возникли трудности, обратитесь в службу поддержки Steam. В случае с устройствами Vive может быть полезно это руководство по устранению неполадок.
All SteamVR-compatible devices are supported out-of-the-box.Все устройства, совместимые со SteamVR, поддерживаются «из коробки».
By default, VR is not initialized. So, you need to perform one of the following:По умолчанию VR не инициализирован. Поэтому вам необходимо выполнить одно из следующих действий:
-
If you run the application via UNIGINE SDK Browser, set the Stereo 3D option to the value that corresponds to the installed HMD (OpenVR or Varjo) in the Global Options tab and click Apply.Если вы запускаете приложение через UNIGINE SDK Browser, установите для параметра Stereo 3D значение, соответствующее установленному HMD (OpenVR или Varjo) на вкладке Global Options и нажмите Apply.
-
If you run the application from the command line, specify the -vr_app command line option on the application start-up. For OpenVR and Oculus it should be as follows:Если вы запускаете приложение из командной строки, укажите параметр командной строки -vr_app при запуске приложения. Для OpenVR и Oculus это делается следующим образом:
your_app_name -vr_app openvr
For Varjo:Для Varjo:
your_app_name -vr_app varjo
Alternatively, you can specify this command-line option in the Customize Run Options window when running the application via the SDK Browser:Как вариант, можно указать этот параметр командной строки в окне Customize Run Options при запуске приложения через браузер SDK:
3. Open Project's Source3. Начало работы с исходным кодом проекта#
To open your VR project in an IDE, select it on the Projects tab of the UNIGINE SDK Browser and click Open Code IDE.Чтобы открыть свой VR-проект в среде IDE, выберите его на вкладке Projects в браузере UNIGINE SDK и нажмите Open Code IDE.
As the IDE opens, you can see, that the project contains a lot of different classes. This brief overview will give you a hint on what are they all about.Открыв IDE, вы увидите, что проект содержит множество различных классов. Этот краткий обзор даст вам общее представление о них.
Don't forget to set the appropriate platform and configuration settings for your project before compiling your code in Visual Studio.Не забудьте установить соответствующую платформу и параметры конфигурации для вашего проекта, прежде чем компилировать код в Visual Studio.
Now, we can try and build our application for the first time.Теперь мы можем попробовать собрать наше приложение в первый раз.
Build your application in Visual Studio (Build -> Build Solution) or otherwise, and launch it by selecting the project on the Projects tab of the UNIGINE SDK Browser and clicking Run.Соберите свое приложение в Visual Studio (Build -> Build Solution) или иным способом и запустите его, выбрав проект на вкладке Projects в браузере UNIGINE SDK и нажав Run.
Before running your application via the UNIGINE SDK Browser make sure, that appropriate Customize Run Options (Debug version in our case) are selected, by clicking an ellipsis under the Run button.Перед запуском приложения через браузер UNIGINE SDK убедитесь, что выбрана соответствующая опция в Customize Run Options (в нашем случае Debug), нажав многоточие под кнопкой Run.
4. Attaching Objects to HMD4. Прикрепление объектов к HMD#
Sometimes it might be necessary to attach some object to the HMD to follow it (e.g. a hat). All movable objects (having the movable.prop property assigned and the Dynamic flag enabled) have a switch enabling this option.Иногда может потребоваться прикрепить к HMD какой-либо объект, чтобы он следовал за камерой (например, шляпа). У всех подвижных объектов (на которые назначено свойство movable.prop и включен флаг Dynamic) есть переключатель, включающий эту опцию.
For example, if you want to make a cylinder on the table attachable to the HMD, just select the corresponding node named "cylinder" in the World Hierarchy click Edit in the Reference section and enable the Can Attach to Head option.Например, если вы хотите, чтобы цилиндр на столе был прикреплен к HMD, просто выберите соответствующую ноду с именем "cylinder" в разделе World Hierarchy, нажмите Edit в разделе Reference и включите опцию Can Attach to Head.
Then select the parent node reference, and click Apply.Затем выберите ссылку на родительскую ноду и нажмите Apply.
The same thing can be done via code at run time:То же самое можно сделать с помощью кода во время выполнения:
#include "Framework/Components/Objects/ObjMovable.h"
#include <UnigineWorld.h>
using namespace Unigine;
...
// retrieving a NodeReference named "cylinder" and getting its reference node
NodePtr node = checked_ptr_cast<NodeReference>(World::getNodeByName("cylinder"))->getReference();
// checking if this node is a movable object by trying to get its ObjMovable component
ObjMovable *obj = ComponentSystem::get()->getComponent<ObjMovable>(node);
if (obj != nullptr)
{
// making the object attachable to the HMD
obj->can_attach_to_head = 1;
}
5. Accessing Mixed Reality Features (Optional)5. Доступ к функциям смешанной реальности (опционально)#
To start developing a mixed reality application in UNIGINE, you should set up the environment as described above. Do not forget to install Varjo Base and ensure that VR is initialized successfully.Чтобы начать разработку приложения смешанной реальности в UNIGINE, вам необходимо настроить окружение, как описано выше. Не забудьте установить Varjo Base и убедиться, что VR успешно инициализирован.
The VR Template provides the MixedRealityMenuGui property assigned to the head_menu GUI node. It demonstrates the operation of the available Mixed Reality settings: you can tweak them to see how they affect the rendered image.Параметр VR Template содержит свойство MixedRealityMenuGui, назначенное на ноду графического интерфейса head_menu. Оно демонстрирует работу доступных настроек смешанной реальности: вы можете настроить их, чтобы увидеть, как они влияют на визуализируемое изображение.
Via this menu, you can toggle the video signal from the real-world view, adjust different settings for the camera, such as white balance correction, ISO, and others. The widgets for the menu are initialized in run-time, but the node is created via UnigineEditor.С помощью этого меню вы можете переключать видеосигнал в режиме реального времени, настраивать различные настройки камеры, такие как коррекция баланса белого, ISO и другие. Виджеты для меню инициализируются во время выполнения, но нода создается с помощью UnigineEditor.
To manage mixed reality, use methods of the VRMixedReality and VRMarkerObject classes of UNIGINE API.Для управления смешанной реальностью используйте методы классов VRMixedReality и VRMarkerObject из UNIGINE API.
6. Accessing Eye-Tracking Feature (Optional)6. Доступ к функции отслеживания движения глаз (опционально)#
In the VR Sample, there is the eyetracking_pointer property assigned to the node of the same name. It shows the name of the node towards which the gaze is directed. The implementation of the property is available in the vr_sample/Demo/Global folder. You can extend or change the functionality by modifying the EyetrackingPointer component.В VR Sample есть свойство eyetracking_pointer, назначенное на ноду с таким же именем. Оно показывает название ноды, на которую направлен взгляд. Реализация свойства доступна в папке vr_sample/Demo/Global. Вы можете расширить или изменить функциональность, изменив компонент EyetrackingPointer.
7. Attaching Objects to Controllers7. Прикрепление объектов к контроллерам#
If you need to attach some object loaded in run-time to a controller (e.g., a menu), you can assign the AttachToHand property to this object.Если вам нужно прикрепить к контроллеру какой-либо объект, загруженный во время выполнения (например, меню), вы можете присвоить этому объекту свойство AttachToHand.
For example, if you have a GUI object and want to attach it to the controller, select this object in the World Hierarchy, click Add New Property in the Parameters window, and specify the AttachToHand property.Например, если у вас есть объект GUI и вы хотите подключить его к контроллеру, выберите этот объект в окне World Hierarchy, нажмите Add New Property в окне Parameters и укажите свойство AttachToHand.
The property settings allow specifying the controller to which the object should be attached (either left or right), as well as the object's transformation.Настройки свойств позволяют указать контроллер, к которому должен быть подключен объект (левый или правый), а также способ преобразования объекта.
In the VR Sample, this component is attached to the hand_menu node and initializes widgets in run-time.В VR Sample этот компонент назначен на ноду hand_menu и инициализирует виджеты во время выполнения.
8. Switching Nodes by Gesture (Optional)8. Переключение нод жестом (опционально)#
When the application is launched with the Ultraleap integration plugin, you can control the objects with your hands.Когда приложение запущено с помощью интеграционного плагина Ultraleap, вы можете управлять объектами при помощи рук.
The VR Template provides the NodeSwitchEnableByGesture property assigned to the vr_layer -> VR -> Ultraleap dummy node and is available when using a VR device with hand-tracking support. The property settings allow specifying the number of nodes you can switch between, the nodes to switch, and the gesture type for switching.В шаблоне VR Template есть свойство NodeSwitchEnableByGesture, назначенное на Node Dummy vr_layer -> VR -> Ultraleap, оно доступно при использовании устройства виртуальной реальности с поддержкой отслеживания движения рук. Настройки свойств позволяют указать количество нод, между которыми вы можете переключаться, ноды для переключения и тип жеста для переключения.
When you hold your left wrist with your right hand, the menu appears:Когда вы возьметесь правой рукой за левое запястье, появится меню:
9. Adding a New Interaction9. Добавление нового взаимодействия#
Suppose we want to extend the functionality of the laser pointer in our project, that we can grab, throw, and use (turn on) for now, by adding an alternative use action (change material of the object being pointed at, when certain button is pressed).Предположим, мы хотим расширить функциональность лазерной указки в нашем проекте, чтобы можно было захватывать, бросать и использовать (включать) объекты, добавив альтернативное действие использования (изменить материал объекта, на который направлена указка, при нажатии определенной кнопки).
So, we're going to add a new altUseIt() method to the VRInteractable class for this new action and map it to the state of a certain controller button.Итак, мы собираемся добавить новый метод altUseIt() в класс VRInteractable для этого нового действия и связать его с состоянием определенной кнопки контроллера.
VRInteractable.h
#pragma once
#include <UnigineNode.h>
#include <UniginePhysics.h>
#include "../Framework/ComponentSystem.h"
#include "Players/VRPlayer.h"
using namespace Unigine;
using namespace Math;
class VRPlayer;
class VRInteractable : public ComponentBase
{
public:
// ...
// interact methods
virtual void grabIt(VRPlayer* player, int hand_num) {}
virtual void holdIt(VRPlayer* player, int hand_num) {}
virtual void useIt(VRPlayer* player, int hand_num) {}
virtual void altuseIt(VRPlayer* player, int hand_num) {} //<-- method for new alternative use action
virtual void throwIt(VRPlayer* player, int hand_num) {}
};
Declare and implement an override of the altUseIt() method for our laser pointer in the ObjLaserPointer.h and ObjLaserPointer.cpp files respectively:Объявите и реализуйте переопределение метода altUseIt() для лазерной указки в файлах ObjLaserPointer.h и ObjLaserPointer.cpp соответственно:
ObjLaserPointer.h
#pragma once
#include <UnigineWorld.h>
#include "../VRInteractable.h"
class ObjLaserPointer : public VRInteractable
{
public:
// ...
// interact methods
// ...
// alternative use method override
void altuseIt(VRPlayer* player, int hand_num) override;
// ...
private:
// ...
int change_material; //<-- "change material" state
// ...
};
ObjLaserPointer.cpp
// ...
void ObjLaserPointer::init()
{
// setting the "change material" state to 0
change_material = 0;
// ...
}
void ObjLaserPointer::update()
{
if (laser->isEnabled())
{
// ...
// show text
if (hit_obj && hit_obj->getProperty() && grabbed)
{
//---------CODE TO BE ADDED TO PERFORM MATERIAL SWITCHING--------------------
if (change_material)// if "alternative use" button was pressed
{
// change object's material to mesh_base
hit_obj->setMaterialPath("Unigine::mesh_base", "*");
}
//---------------------------------------------------------------------------
// ...
}
else
obj_text->setEnabled(0);
}
// unsetting the "change material" state
change_material = 0;
}
// ...
// alternative use method override
void ObjLaserPointer::altuseIt(VRPlayer* player, int hand_num)
{
// setting the "change material" state
change_material = 1;
}
// ...
Now, we're going to map this action to the state of the YB controller button. For this purpose we should modify the VRPlayer class (which is the base class for all VR players) by adding the following code to its postUpdate() method:Теперь свяжем это действие с состоянием кнопки YB контроллера. Для этого мы должны изменить класс VRPlayer (который является базовым классом для всех VR-плееров), добавив следующий код в его метод postUpdate():
VRPlayer.cpp
// ...
void VRPlayer::postUpdate()
{
for (int i = 0; i < getNumHands(); i++)
{
int hand_state = getHandState(i);
if (hand_state != HAND_FREE)
{
auto &components = getGrabComponents(i);
// ...
//-------------CODE TO BE ADDED--------------------------
// alternative use of the grabbed object
if (getControllerButtonDown(i, BUTTON::YB))
{
for (int j = 0; j < components.size(); j++)
components[j]->altuseIt(this, i);
// add callback processing if necessary
}
//--------------------------------------------------------
}
}
update_button_states();
}
// ...
10. Adding a New Interactable Object10. Добавление нового интерактивного объекта#
The next step in extending the functionality of our VR Sample is adding a new interactable object.Следующим шагом в расширении функциональности демо-проекта VR Sample является добавление нового интерактивного объекта.
Let's add a new type of interactable object, that we can grab, hold and throw with an additional feature: object will change its form (to a certain preset) when we grab it, and restore it back, when we release it. It will also display certain text in the console, if the corresponding option is enabled.Давайте добавим новый тип интерактивного объекта, который можно взять, удержать и бросить, с дополнительной функцией: объект изменит свою форму (на заранее предустановленную), когда мы его захватим, и вернет ее обратно, когда мы его отпустим. Также будет отображаться определенный текст в консоли, если включена соответствующая опция.
So, we're going to use the following components:Итак, мы собираемся использовать следующие компоненты:
- ObjMovable - to enable basic grabbing and throwing functionalityObjMovable - для включения базовых функций захвата и бросания
- new ObjTransformer component to enable form changing and log message printing functionalityновый компонент ObjTransformer для реализации функционала изменения формы и печати сообщения в лог
The following steps are to be performed:Необходимо выполнить следующие действия:
-
Add a new ObjTransformer class inherited from the VRInteractable. In Visual Studio we can do it by choosing Project -> Add Class from the main menu, clicking Add, specifying class name and base class in the window that opens, and clicking Finish:Добавьте новый класс ObjTransformer, унаследованный от VRInteractable. В Visual Studio это можно сделать так: выбираем Project -> Add Class в главном меню, нажимаем Add, указываем название класса и базовый класс в открывшемся окне и нажимаем Finish:
-
Implement functionality of transformation to the specified node on grabbing, and restoring previous form on releasing a node.Реализуйте функциональность преобразования в указанную ноду при захвате и восстановления предыдущей формы, когда ноду отпускают.
Below you'll find header and implementation files for our new ObjTransformer class:Ниже вы найдете заголовочные файлы и файлы реализации для нашего нового класса ObjTransformer:
ObjTransformer.h
#pragma once #include <UnigineNode.h> #include "Components/VRInteractable.h" #include "Framework/Utils.h" class ObjTransformer : public VRInteractable { public: ObjTransformer(const NodePtr &node, int num) : VRInteractable(node, num) {} virtual ~ObjTransformer() {} // property name UNIGINE_INLINE static const char* getPropertyName() { return "transformer"; } // parameters PROPERTY_PARAMETER(Toggle, show_text, 1); // Flag indicating if messages are to be printed to the console PROPERTY_PARAMETER(String, text, "TRANSFORMATION"); // Text to be printed to the console when grabbing or releasing the node PROPERTY_PARAMETER(Node, target_object); // Node to be displayed instead of the transformer-node, when it is grabbed // interact methods void grabIt(VRPlayer* player, int hand_num) override; // override grab action handler void throwIt(VRPlayer* player, int hand_num) override; // override trow action handler void holdIt(VRPlayer* player, int hand_num) override; // override hold action handler protected: void init() override; };
ObjTransformer.cpp
#include "ObjTransformer.h" REGISTER_COMPONENT( ObjTransformer ); // macro for component registration by the Component System // initialization void ObjTransformer::init(){ // hiding the target object (if any) if (target_object){ target_object->setEnabled(0); } } // grab action handler void ObjTransformer::grabIt(VRPlayer* player, int hand_num) { // if a target object is assigned, showing it, hiding the original object and displaying a message in the log if (target_object){ target_object->setEnabled(1); // hide original object's surfaces without disabling components ObjectPtr obj = checked_ptr_cast<Object>(node); for (int i = 0; i < obj->getNumSurfaces(); i++) obj->setEnabled(0, i); if (show_text) Log::message("\n Transformer's message: %s", text.get()); } } // throw action handler void ObjTransformer::throwIt(VRPlayer* player, int hand_num) { // if a target object is assigned, hiding it, and showing back the original object if (target_object){ target_object->setEnabled(0); // show original object's surfaces back ObjectPtr obj = checked_ptr_cast<Object>(node); for (int i = 0; i < obj->getNumSurfaces(); i++) obj->setEnabled(1, i); } } // hold action handler void ObjTransformer::holdIt(VRPlayer* player, int hand_num) { // changing the position of the target object target_object->setWorldPosition(player->getHandNode(hand_num)->getWorldPosition()); }
- Build your application and launch it as we did earlier, a new property file (transformer.prop) will be generated for our new component.Создайте свое приложение и запустите его, как мы делали ранее — для нашего нового компонента будет создан новый файл свойств (transformer.prop).
- Open the world in the UnigineEditor, create a new box primitive (Create -> Primitive -> Box), and place it somewhere near the table, create a sphere primitive (Create -> Primitive -> Sphere) to be used for transformation.Откройте сцену в UnigineEditor, создайте новый прямоугольный примитив (Create -> Primitive -> Box) и поместите его где-нибудь рядом со столом, создайте сферический примитив (Create -> Primitive -> Sphere), который будет использоваться для преобразования.
-
To add components to the box object select it and click Add New Property in the Node Properties section, then drag the movable.prop property to the new empty field that appears. Repeat the same for the transformer.prop property, and drag the sphere from the World Hierarchy window to the Target Object field.Чтобы добавить компоненты к объекту box, выберите его и нажмите Add New Property в разделе Node Properties, затем перетащите свойство movable.prop в появившееся новое пустое поле. Повторите то же самое для свойства transformer.prop и перетащите сферу из окна World Hierarchy в поле Target Object.
- Save your world and close the UnigineEditor.Сохраните мир и закройте UnigineEditor.
- Launch your application.Запустите приложение.
11. Restricting Teleportations11. Ограничение телепортации#
By default, it is possible to teleport to any point on the scene. To avoid user interaction errors in VR (e.g., teleporting into walls or ceilings), you can restrict teleportation to certain areas. To do so, perform the following:По умолчанию можно телепортироваться в любую точку сцены. Чтобы избежать ошибок при взаимодействии пользователей с объектами в виртуальной реальности (например, при телепортации в стену или потолок), можно указать области, в пределах которых телепортация возможна. Для этого выполните следующие действия:
- Create a mesh defining the area you want to restrict user teleportation to.Создайте меш, определяющий область, которая будет ограничивать телепортацию пользователя.
-
Set an intersection mask to the desired surface(s) of this mesh either in the UnigineEditor or using the setIntersectionMask() method:Установите значение intersection mask для желаемой поверхности (поверхностей) этого меша либо в UnigineEditor, либо с помощью метода setIntersectionMask():
// defining the teleportation mask as a hexadecimal value (e.g. with only the last bit enabled) int teleport_mask = 0x80000000; // setting the teleportation mask to the MyAreaMesh object's surface with the num index MyAreaMesh->setIntersectionMask(num, teleport_mask);
- Set the same intersection mask for the teleport ray using the following method: VRPlayerVR::setTeleportationMask(teleport_mask). Установите такую же маску пересечения для луча телепорта, используя следующий метод: VRPlayerVR::setTeleportationMask(teleport_mask).
Where to Go From HereКуда идти дальше#
Congratulations! Now, you know how to create your own VR project on the basis of the VR Sample demo, and extend its functionality. So, you can continue developing it on your own. There are some recommendations for you, that might be useful:Поздравляю! Теперь вы знаете, как создать свой собственный VR-проект на основе демо-проекта VR Sample и расширить его функциональность. Так что можете продолжить разработку самостоятельно. Вот несколько рекомендаций, которые могут оказаться полезными:
- Try to analyse the source code of the sample further and figure out how it works, use it to write your own.Попробуйте еще раз проанализировать исходный код примера и выяснить, как он работает, используйте его для написания своего собственного.
- Read the Virtual Reality Best Practices article for more information and useful tips on preparing content for VR and making user experience better.Прочтите статью Лучшие практики VR для получения дополнительной информации и полезных советов по подготовке контента для виртуальной реальности и улучшению пользовательского опыта.
- Read the Component System article for more information on working with the Component System.Прочтите статью Система компонентов для получения дополнительной информации о работе с системой компонентов.
- Check out the Component System Usage Example for more details on implementing logic using the Component System.Ознакомьтесь с Примерами использования компонентной системы для получения более подробной информации о реализации логики с использованием компонентной системы.