This page has been translated automatically.
视频教程
界面
要领
高级
实用建议
基础
专业(SIM)
UnigineEditor
界面概述
资源工作流程
Version Control
设置和首选项
项目开发
调整节点参数
Setting Up Materials
设置属性
照明
Sandworm
使用编辑器工具执行特定任务
如何擴展編輯器功能
嵌入式节点类型
Nodes
Objects
Effects
Decals
光源
Geodetics
World Nodes
Sound Objects
Pathfinding Objects
Players
编程
基本原理
搭建开发环境
使用范例
C++
C#
UnigineScript
统一的Unigine着色器语言 UUSL (Unified UNIGINE Shader Language)
Plugins
File Formats
材质和着色器
Rebuilding the Engine Tools
GUI
双精度坐标
应用程序接口
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
Tutorials

VR入门

注意
本文仅回顾了C++VR项目的创建。 您可以在页面右上角切换到C#版本。

本文适用于任何想要开始在UNIGINE中开发虚拟现实项目的人,强烈建议所有新用户阅读本文。 我们将研究 VR Sample 演示,看看里面有什么,并学习如何使用它来创建我们自己的VR项目。 我们还将考虑一些简单的示例,用于修改和扩展此示例的基本功能。

那么,我们开始吧!

VR Sample#

考虑到VR开发人员,我们创建了 VR Sample 演示,使您能够直接进入并开始创建自己的项目。 我们建议使用此演示作为您的VR项目的基础.

该演示基于支持所有开箱即用的 SteamVR 兼容设备的 VR Template。 它在运行时提供控制器模型的自动加载。 此外,该模板还包括基本机制的实现,如抓取和投掷物体,按下按钮,打开/关上桌子抽屉等等。

注意
此示例项目中的世界已针对VR中的最佳性能进行了优化,其中包括一个*.render资源,只需在资源浏览器中双击它即可随时加载该资源,以重置对默认优化值所做的任何更改。

示例项目是使用组件系统创建的,因此每个对象的功能由附加的组件决定。

您可以通过添加更多组件来扩展对象的功能。 例如,激光指示器对象具有附加的以下组件:

1、制作模板项目#

那么,我们有一个很酷的演示,里面有一些东西,但是我们如何使用它作为模板? 这很简单,只需打开SDK浏览器,转到Samples选项卡,然后选择Demos

Available部分找到VR Sample,然后单击Install。 安装后,演示将出现在Installed部分,您可以单击 Copy as Project 基于此示例创建项目。

在打开的Create New Project窗口中,在相应字段中输入新VR项目的名称,然后单击Create New Project

2、设置设备和配置项目#

假设您已成功安装所选的头戴式显示器(HMD)。

了解有关为不同 VR 平台设置设备的详细信息。 如果您遇到任何困难,请访问 Steam 支持。 对于 Vive 设备,此故障排除指南可能会有所帮助。

注意
对于Mixed Reality应用程序开发,除了SteamVR之外,您还需要下载并安装Varjo Base

所有SteamVR兼容的设备都支持开箱即用。

默认情况下,VR未初始化。 因此,您需要执行以下操作之一:

  • 如果通过UNIGINE SDK浏览器运行应用程序,请在Global Options选项卡中将Stereo 3D选项设置为与已安装HMD(OpenVRVarjo)相对应的值,然后单击Apply

  • 如果从命令行运行应用程序,请在应用程序启动时指定-vr_app命令行选项。 对于OpenVR和Oculus,它应该如下所示:

    命令行
    your_app_name -vr_app openvr

    对于Varjo:

    命令行
    your_app_name -vr_app varjo

    或者,您可以在通过SDK浏览器运行应用程序时在Customize Run Options窗口中指定此命令行选项:

注意
在UNIGINE VR系统中集成OpenVR功能,可以实现 Oculus HMD 的应用程序。 这就是为什么在使用Oculus设备时应该指定OpenVR的原因。

3、开放项目的源代码#

要在IDE中打开VR项目,请在UNIGINE SDK浏览器的Projects选项卡上选择它,然后单击Open Code IDE

当IDE打开时,您可以看到该项目包含许多不同的类。 这个简短的概述将给您一个关于它们是什么的提示。

Visual Studio中编译代码之前,不要忘记为项目设置适当的平台和配置设置。

现在,我们可以第一次尝试构建我们的应用程序。

Visual StudioBuild -> Build Solution)或其他方式构建应用程序,并通过在UNIGINE SDK浏览器的Projects选项卡上选择项目并单击Run来启动它。

在通过UNIGINE SDK浏览器运行应用程序之前,请确保通过单击Run按钮下的省略号来选择适当的Customize Run Options(在我们的例子中为Debug版本)。

4、将对象附加到HMD#

有时可能需要将一些对象附加到HMD以跟随它(例如帽子)。 所有可移动对象(已分配movable.prop属性并启用Dynamic标志)都有一个启用此选项的切换。

例如,如果要使桌子上的圆柱体可附加到HMD,只需在 Reference 部分的 World Hierarchy单击Edit中选择名为 "cylinder" 的相应节点,然后启用 Can Attach to Head 选项。

然后选择父 Node Reference,并单击Apply

同样的事情可以通过代码在运行时完成:

源代码 (C++)
#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、访问混合现实功能(可选)#

注意
Mixed Reality功能可用于使用Varjo耳机,Varjo XR-3Varjo XR-4,运行的应用程序。 UNIGINE VR系统支持的Varjo混合现实功能在这里列出

要开始在UNIGINE中开发混合现实应用程序,您应该按照上面的所述设置环境。 不要忘记安装Varjo Base并确保VR成功初始化。

VR Template提供分配给head_menu GUI节点的MixedRealityMenuGui属性。 它演示了可用的混合现实设置的操作:您可以调整它们以查看它们如何影响渲染的图像。

通过此菜单,您可以从真实世界视图切换视频信号,调整相机的不同设置,如白平衡校正,ISO等。 菜单的小部件在运行时初始化,但节点是通过UnigineEditor创建的。

要管理混合现实,请使用UNIGINE API的VRMixedRealityVRMarkerObject类的方法。

6、访问眼动追踪功能(可选)#

注意
对于使用Varjo耳机运行的应用程序,Eye-tracking也是开箱即用的。

VR Sample中,有分配给同名节点的eyetracking_pointer属性。 它显示凝视指向的节点的名称。 该属性的实现在vr_sample/Demo/Global文件夹中可用。 您可以通过修改EyetrackingPointer组件来扩展或更改功能。

7、将对象附加到控制器#

如果您需要将一些在运行时加载的对象附加到控制器(例如菜单),则可以将AttachToHand属性分配给此对象。

例如,如果您有一个GUI对象并希望将其附加到控制器,请在World Hierarchy中选择此对象,在Parameters窗口中单击添加新属性,并指定AttachToHand属性。

属性设置允许指定对象应附加到的控制器(左或右),以及对象的转换。

VR Sample中,该组件附加到hand_menu节点,并在运行时初始化小部件。

8、通过手势切换节点(可选)#

当使用Ultraleap集成插件启动应用程序时,您可以用手控制对象。

注意
VR中的手跟踪可用于Varjo VRXR耳机。

VR Template提供了分配给vr_layer -> VR -> Ultraleap虚拟节点的NodeSwitchEnableByGesture属性,并且在使用支持手跟踪的VR设备时可用。 属性设置允许指定可以在其中切换的节点数量、要切换的节点以及切换的手势类型。

当您用右手握住左手腕时,菜单就会出现:

9、添加新交互#

假设我们想在我们的项目中扩展激光指示器的功能,我们可以通过添加一个替代的使用动作(当按下某个按钮时,改变被指向的对象的材质)来扩展激光指示器的功能。

因此,我们将为这个新动作在VRInteractable类中添加一个新的altUseIt()方法,并将其映射到某个控制器按钮的状态。

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

分别在ObjLaserPointer.hObjLaserPointer.cpp文件中声明并实现对激光笔的altUseIt()方法的重写:

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

// ...

现在,我们将此操作映射到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();
}

// ...

10、添加新的可交互对象#

扩展VR Sample功能的下一步是添加一个新的可交互对象。

让我们添加一个新类型的可交互对象,我们可以抓取,握在手里,和扔出一个额外的功能:当我们抓住它时,对象会改变它的形式(到某个预设),并在我们释放它时恢复它的初始状态。 如果启用了相应的选项,它还将在控制台中显示某些文本。

因此,我们将使用以下组件:

  • ObjMovable 启用基本的抓取和投掷功能
  • 新的ObjTransformer组件,以启用形状更改和日志消息打印功能

要执行以下步骤:

  1. 添加从VRInteractable继承的新ObjTransformer类。 在Visual Studio中,我们可以通过从主菜单中选择Project -> Add Class,单击Add,在打开的窗口中指定类名和基类,然后单击Finish

  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中打开世界,创建一个新的box图元(Create -> Primitive -> Box),并将其放置在桌子附近的某个地方,创建一个球体图元(Create -> Primitive -> Sphere)用于转换。
  5. 要将组件添加到box对象,请选择它并在Node Properties部分中单击Add New Property,然后将movable.prop属性拖到出现的新空字段中。 对transformer.prop属性重复相同的操作,并将球体从World Hierarchy窗口拖到Target Object字段。

  6. 保存您的世界并关闭UnigineEditor。
  7. 启动应用程序。

11、限制传送#

默认情况下,可以瞬移到现场的任何点。 为了避免VR中的用户交互错误(例如,传送到墙壁或天花板),您可以将传送限制在某些区域。 为此,请执行以下操作:

  1. 创建一个网格,定义要限制用户传送到的区域。
  2. 在UnigineEditor中或使用setIntersectionMask()方法为该网格的所需表面设置一个intersection mask

    源代码 (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);
  3. 使用以下方法为传送射线设置相同的相交掩码:VRPlayerVR::setTeleportationMask(teleport_mask)
注意
多个网格可用于定义传送区域。

下一步可以做什么#

祝贺您! 现在,您知道如何在VR Sample演示的基础上创建自己的VR项目,并扩展其功能。 所以,您可以继续自己开发它。 有一些建议给您,可能是有用的:

  • 尝试进一步分析示例的源代码并弄清楚它是如何工作的,用它来编写自己的代码。
  • 阅读VR最佳实践文章,了解有关为VR准备内容并改善用户体验的更多信息和有用提示。
  • 阅读组件系统文章,了解有关使用组件系统的更多信息。
  • 查看组件系统使用示例了解有关使用组件系统实现逻辑的更多详细信息。
注意
您可以在通过SDK浏览器创建新应用程序时选择VR项目模板,从头开始创建一个空的VR应用程序(与演示内容和代码从它删除)。
最新更新: 2024-12-13
Build: ()