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
Animations-Related Classes
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
VR-Related Classes
Работа с контентом
Оптимизация контента
Материалы
Визуальный редактор материалов
Material Nodes Library
Miscellaneous
Input
Math
Matrix
Textures
Art Samples
Учебные материалы

Начало работы с VR

Примечание
В статье рассматривается создание VR проекта на C++. Переключиться на версию для C# можно в правом верхнем углу страницы.

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

Итак, приступим!

VR Sample#

Думая о разработчиках виртуальной реальности, мы создали демо-версию VR Sample, позволяющую сразу приступить к созданию собственных проектов. Он поддерживает Oculus Rift, HTC Vive / Vive Pro "из коробки".

Рекомендуем использовать эту демонстрацию как основу для вашего VR-проекта. Здесь вы найдете набор 3D-моделей всех популярных контроллеров VR, а также реализацию основных механик, таких как захват и толкание объектов, нажатие кнопок, открытие / закрытие ящиков и многое другое.

Примечание
Мир в этом образце проекта имеет свои настройки, оптимизированные для лучшей производительности в VR, и включает ресурс .render, который можно загрузить в любое время, просто дважды щелкнув его в Asset Browser для сброса любые изменения, внесенные вами в оптимизированные значения по умолчанию.

Пример проекта создается с использованием Component System , поэтому функциональность каждого объекта определяется присоединенными компонентами.

Вы можете расширить функциональность объекта, просто добавив к нему дополнительные компоненты. Например, к объекту лазерной указки прикреплены следующие компоненты:

  • ObjMovable - позволяет хватать и бросать объект
  • ObjLaserPointer - позволяет отбрасывать луч света на объект.

1. Создание шаблонного проекта#

Итак, у нас есть классная демонстрация с некоторыми вещами внутри, но как нам использовать ее в качестве шаблона? Это просто - просто откройте свой SDK Browser, перейдите на вкладку Примеры и выберите Демо .

Найдите VR Sample в разделе Available и щелкните Install. После установки демоверсия появится в разделе Installed, и вы можете нажать Copy as Project, чтобы создать проект на основе этого образца.

В открывшемся окне Create New Project введите имя вашего нового проекта VR в соответствующее поле и нажмите Create New Project.

2. Настройка устройства и настройка проекта.#

Предположим, вы успешно установили выбранный головной дисплей (HMD) (пожалуйста, посетите Oculus Rift Setup или HTC Vive Setup , если вы этого не сделали). Если у вас возникли проблемы с началом работы HTC Vive, может оказаться полезным это руководство по устранению неполадок .

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

HTC Vive Oculus Rift

Если вы запускаете приложение через UNIGINE SDK Browser, установите для параметра Stereo 3D значение HTC Vive на вкладке Global Options и нажмите Apply:

Для запуска плагина укажите extern_plugin параметр командной строки при запуске приложения:

Shell-команды
your_app_name -extern_plugin "UnigineOpenVR"

Если вы запускаете приложение через UNIGINE SDK Browser, установите для параметра Stereo 3D значение Oculus Rift на вкладке Global Options и нажмите Apply:

Для запуска плагина укажите extern_plugin параметр командной строки при запуске приложения:

Shell-команды
your_app_name -extern_plugin "UnigineOculus"
Примечание
Вы также можете указать плагин, который будет загружен для вашего приложения, через Customize Run Options.

3. Откройте исходный код проекта.#

Чтобы открыть проект VR в среде IDE, выберите его на вкладке Projects в браузере UNIGINE SDK и нажмите Open Code IDE.

Когда откроется IDE, вы увидите, что проект содержит много разных классов. Этот краткий обзор даст вам представление о каждом из них.

Не забудьте установить соответствующую платформу и параметры конфигурации для вашего проекта перед компиляцией кода в Visual Studio.

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

Создайте свое приложение на Visual Studio (BUILD -> Build Solution) или другом языке и запустите его, выбрав проект на вкладке Projects в браузере UNIGINE SDK и нажав Run.

Перед запуском вашего приложения через браузер UNIGINE SDK убедитесь, что выбран соответствующий Customize Run Options (версия Debug и архитектура x64 в нашем случае), щелкнув многоточие под кнопкой Run.

4. Присоединение объектов к HMD#

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

Например, если вы хотите сделать цилиндр на столе, присоединяемым к HMD, просто выберите соответствующий узел с именем "цилиндр" в поле World Hierarchy, щелкните Edit в разделе Reference и включите параметр Can Attach to Head.

Затем выберите ссылку на родительский узел и нажмите Apply.

То же самое можно сделать с помощью кода во время выполнения:

Исходный код (C++)
// 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. Добавление нового взаимодействия#

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

Итак, мы собираемся добавить новый метод altUseIt() в класс VRInteractable для этого нового действия и сопоставить его с состоянием определенной кнопки контроллера.

VRInteractable.h

Исходный код (C++)
#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) {}
};

Объявите и реализуйте переопределение метода altUseIt() для нашей лазерной указки в файлах ObjLaserPointer.h и ObjLaserPointer.cpp соответственно:

ObjLaserPointer.h

Исходный код (C++)
#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

Исходный код (C++)
// ...

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->setMaterial("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;
}

// ...

Теперь мы собираемся сопоставить это действие с состоянием кнопки контроллера YB . Для этого мы должны изменить класс VRPlayer (который является базовым классом для всех VR-плееров), добавив следующий код к его методу postUpdate():

VRPlayer.cpp

Исходный код (C++)
// ...

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();
}

// ...

6. Изменение внешнего вида контроллеров VR по умолчанию#

В своем приложении VR вы можете захотеть отображать руки вместо стандартных контроллеров, включенных в образец (например, для HTC Vive).

Это просто - выполните следующие действия:

  1. Откройте мир в UnigineEditor
  2. Выберите VR -> spawn_point (узел Dummy Player с компонентом VRPlayerSpawner) в окне World Hierarchy и перейдите в раздел Node Properties в окне Parameters.
    Примечание
    Основные настройки VR Player (внешний вид контроллеров и точек телепорта, цвет луча телепорта, множитель силы рук для физических взаимодействий, местоположение точки появления и т. д.) можно настроить с помощью компонента VRPlayerSpawner или полей соответствующего свойства vr_player_spawner.prop.
  3. Перетащите требуемый узел для каждой руки из окна иерархии World Nodes или Editor Viewport в соответствующее поле свойства vr_player_spawner.prop. Например, мы можем сделать контроллеры Vive похожими наOculus Touchперетаскивая ноды oculus_touch_left и oculus_touch_right в поля Vive Left Controller и Vive Right Controller соответственно.

  4. Сохраните мир и запустите свое приложение VR, ваши контроллеры Vive будут выглядеть как Oculus Touch в VR.

То же самое можно сделать с помощью кода во время выполнения:

Примечание
Этот код должен быть выполнен перед созданием VR Player. Значит, его следует поместить в AppWorldLogic::init().
Исходный код (C++)
// AppWorldLogic.cpp

NodeReferencePtr left_hand_node; // node reference to be used for the left controller
NodeReferencePtr right_hand_node; // node reference to be used for the right controller

// ...

int AppWorldLogic::init()
{

	// getting the "spawn_point" node
	NodePtr player_node = World::getNodeByName("spawn_point");

	// creating nodes to replace default Vive controllers (you can use custom *.node files for left and right hand)
	left_hand_node = NodeReference::create("/vr_template/oculus/oculus_touch_left.node");
	right_hand_node = NodeReference::create("/vr_template/oculus/oculus_touch_right.node");
	

	// checking if this node is a spawn point by trying to get its VRPlayerSpawner component
	VRPlayerSpawner *player_spawner = ComponentSystem::get()->getComponent<VRPlayerSpawner>(player_node);
	if (player_spawner != nullptr)
	{
		// setting new nodes to visualize Vive controllers
		player_spawner->vive_controller_0 = left_hand_node->getNode();
		player_spawner->vive_controller_1 = right_hand_node->getNode();
	}

// ...

}

7. Добавление нового интерактивного объекта#

Следующим шагом в расширении функциональности нашего VR Sample является добавление нового интерактивного объекта.

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

Итак, мы собираемся использовать следующие компоненты:

  • ObjMovable - для включения основных функций захвата и метания
  • новый компонент ObjTransformer для включения функции изменения формы и печати сообщений журнала

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

  1. Добавьте новый класс ObjTransformer, унаследованный отVRInteractable. ВVisual Studioмы можем сделать это, выбрав Проект → Добавить класс в главном меню, нажав Добавить , указав имя класса и базовый класс в в открывшемся окне и нажав Готово :

  2. Реализовать функциональность преобразования в указанный узел при захвате и восстановление предыдущей формы при освобождении узла

    Ниже вы найдете файлы заголовков и реализации для нашего нового класса ObjTransformer:

    ObjTransformer.h

    Исходный код (C++)
    #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

    Исходный код (C++)
    #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());
    }
  3. Создайте приложение и запустите его, как мы это делали ранее , для нашего нового компонента будет создан новый файл свойств (transformer.prop).
  4. Откройте мир в UnigineEditor , создайте новый примитив блока (Create -> Primitive -> Box) и поместите его где-нибудь рядом с таблицей, создайте примитив сферы (Create -> Primitive -> Box), который будет использоваться для преобразования.
  5. Чтобы добавить компоненты к объекту коробки, выберите его и щелкните Add New Property в разделе Node Properties, затем перетащите свойство movable.prop в появившееся новое пустое поле. Повторите то же самое для свойства transformer.prop и перетащите сферу из окна World Hierarchy в поле Target Object.

  6. Сохраните свой мир и закройте UnigineEditor.
  7. Запустите приложение.

8. Ограничение телепортации.#

По умолчанию можно телепортироваться в любую точку сцены. Чтобы избежать ошибок взаимодействия с пользователем в VR (например, телепортации в стены или потолок), вы можете ограничить телепортацию только определенными областями. Для этого выполните следующие действия:

  • Создайте сетку, определяющую область, в которую вы хотите ограничить телепортацию пользователя;
  • Установитьintersection maskк желаемой поверхности (ям) этой сетки либо в UnigineEditor, либо с помощьюsetIntersectionMask()метод:
    Исходный код (C++)
    // 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);
  • Установите такую ​​же маску пересечения для луча телепорта, используя следующий метод: VRPlayerVR::setTeleportationMask(teleport_mask).
Примечание
Для определения области телепортации можно использовать несколько сеток.

Что дальше?#

Поздравляю! Теперь вы знаете, как создать свой собственный VR-проект на основе демо VR Sample и расширить его функциональность. Так что вы можете продолжить разработку самостоятельно. Вот несколько рекомендаций, которые могут быть полезны:

  • Попытайтесь проанализировать исходный код примера и выяснить, как он работает, используйте его, чтобы написать свой собственный.
  • Прочтите статью Virtual Reality Best Practices для получения дополнительной информации и полезных советов по подготовке контента для VR и улучшению взаимодействия с пользователем.
  • Прочтите статью Component System для получения дополнительной информации о работе с Component System.
  • Ознакомьтесь с Примером использования системы компонентов для получения более подробной информации о реализации логики с использованием системы компонентов.
Примечание
Вы можете выбрать шаблон проекта VR при создании нового приложения через SDK Browser , чтобы создать пустое VR-приложение с нуля (с удаленным демонстрационным контентом и кодом).
Последнее обновление: 12.01.2024
Build: ()