HTC Vive小场地与大场景空间的解决方案

2016年11月24日 12:01 0 点赞 0 评论 更新于 2025-11-21 13:36

HTC Vive具备出色的运动追踪功能,这是其一大亮点。该功能让许多适配HTC Vive的游戏能够引导用户进行身体活动,无论是听起来还是实际体验,都十分酷炫。在小范围移动(1:1范围内活动)或固定位置的游戏中,HTC Vive定位精确,延迟极低,优点众多。

然而,空间问题却将想要在小空间体验大场景游戏的玩家拒之门外。HTC官方建议消费者使用全套装备时,游戏空间至少要有20平米,这意味着玩家需要有足够大的游戏房。当然,如果您是土豪,拥有宽敞的游戏场地,那么后续内容可能就无需关注了。但对于大多数想要拓展游戏体验的用户来说,实际场地大小往往成为了限制因素。玩家常常面临游戏场景过大,而自身场地过小的问题,该如何解决呢?

此外,如果使用1:1的场地,玩家会感觉游戏场景非常局促,仿佛没走多远就到达了边界,这种体验会让玩家十分不爽。

因此,本文将给出针对HTC头盔变比空间移动问题的解决方案。当然,如果您有更好的办法,欢迎一起讨论。

下面我们重点探讨游戏场景过大,而实际场地较小,需要对位移进行比例加速的问题。我们需要解决三个关键问题:

  1. 边界放大
  2. 起点位置平移
  3. 游戏空间与场地非等比空间速度缩放

一、边界放大

首先,我们来看官方SteamVR给出的预制体的顶视图。在HTC头盔的游戏中,玩家通常处于蓝色框的中间位置。对于那些需要从(0,0)作为起点,玩家需要在房间内四处移动,并且根据游戏剧情需要进行空间移动的游戏来说,原本的场地只能利用其1/4,这造成了场地的严重浪费。

我们首先要解决的是位置偏移问题。其次,我们可以看到蓝色边框的范围很小。以下是相关代码:

public enum Size
{
Calibrated,
_400x300,
_300x225,
_200x150
}

由于这个面积无法满足需求,我们可以自行扩大场地。我自己制作了一个区域标识,小的蓝色框是原本400300的区域,大的则是我自己缩放后的区域。选择Size为Calibrated这个选项进行缩放,为了防止在直接节点上缩放出问题,特地添加了一个父节点,将xz轴均缩放为4,Y轴仍旧为1。经过这样的操作,这个标识基本可以满足游戏中99米的大场地需求。

二、起点位置平移

接下来我们讨论起点的平移问题,这需要分两步进行:

视觉上的平移

在游戏编辑器模式下,我们要让玩家处于蓝色区域的起点角点位置。这其实很简单,就是对蓝色区域进行平移。我们将刚才缩放的预制体的父节点进行平移,在项目中的平移位置设置为(4.2,0,4.2)即可完成这部分操作。

代码层面的处理

在详细说明这部分内容之前,我们需要先了解一下SteamVR插件在运行时和编辑状态下相机的差别。在编辑器模式下,相机处于一种特定的状态。但在运行时,相机的层级结构会发生较大变化,此时eye作为父节点,ears作为子节点,而head则被隐藏。

具体的代码处理是在SteamVR_Camera.cs中的OnEnable方法中进行,部分代码如下:

if (head != t)
{
Expand();
t.parent = origin;
while (head.childCount > 0)
head.GetChild(0).parent = t;
// Keep the head around, but parent to the camera now since it moves with the hmd
// but existing content may still have references to this object.
head.parent = t;
head.localPosition = Vector3.zero;
head.localRotation = Quaternion.identity;
head.localScale = Vector3.one;
head.gameObject.SetActive(false);
_head = t;
}

此外,还有关于ears的处理代码,用于设置ears的相机参数:

if (ears == null)
{
var e = transform.GetComponentInChildren<SteamVR_Ears>();
if (e != null)
_ears = e.transform;
}
if (ears != null)
ears.GetComponent<SteamVR_Ears>().vrcam = this;

为什么要详细介绍这些结构呢?因为它们会影响玩家起点平移的算法和处理。具体的处理方法其实并不复杂,我们在相机的父节点初始化时,重置一个与相机初始化相反的参数。这样做的目的是为了抵消相机在场景中从(0,0)点作为起点的变化。以下是具体代码:

using UnityEngine;
using System.Collections;

public class PlayerPosIntitial : MonoBehaviour
{
private bool bUseOnce = false;
public Transform eye;

private float starttime;
private float delaytime = 4.0f;

// Use this for initialization
void Start ()
{
starttime = Time.time;
}

// Update is called once per frame
void Update ()
{
if (!bUseOnce && (Input.GetMouseButton(0) || Input.GetKey(KeyCode.JoystickButton0) || Time.time - starttime >= delaytime))
{
bUseOnce = true;
if (null != eye)
{
this.transform.localPosition = new Vector3(-eye.transform.localPosition.x, 0,-eye.transform.localPosition.z);
Debug.Log ("set player initila position");
}
}
}
}