VR 开发中遇到的问题、解决方案、技巧等

1. VR 手柄按键绑定

在 Unity 顶部菜单栏选择 Window -> SteamVR_Input,打开 SteamVR Input 窗口。

Action 标签页中,选择 Create New Action Set,创建一个新的 Action Set,命名为 Menu,点击 Save and Generate 保存。

SteamVR Input

在 SteamVR Input 窗口中,选择 Open Binding UI,打开 SteamVR Input 窗口,选择当前项目,进入按键绑定界面。

SteamVR Input

选择要自定义的按键,点击编辑,找到 Menu,最后 替换默认绑定 即可,

2. 设置游戏中手持手柄

在目录中找到如下预制体:SteamVR -> Prefabs -> vr_glove_left_model_slim,设置绑定脚本中的 Range Of MotionWith controller

3. SteamVR的按钮交互与抓取

3.1 Button

  • Interactable脚本:/SteamVR/InteractionSystem/Core/Scripts/Interactable.cs

  • HoverButton脚本:/SteamVR/InteractionSystem/Core/Scripts/HoverButton.cs

    此脚本需要一个可进行Hover的对象 <MovingPart> 该脚本有三个函数调用需要进行脚本编写实现:OnButtonUp、OnButtonDown、OnButtonIsPressed

3.1 Throwable

  • Interactable脚本:/SteamVR/InteractionSystem/Core/Scripts/Interactable.cs

  • Throwable脚本:/SteamVR/InteractionSystem/Core/Scripts/Throwable.cs

  • InteractableHoverEvents脚本:

    /SteamVR/InteractionSystem/Core/Scripts/InteractableHoverEvents.cs

    此脚本需要一个可进行Hover的对象 <MovingPart>

    该脚本有四个函数调用需要进行脚本编写实现:OnHandHoverBegin、OnAttachedToHand(Handhand)、OnDetachedFromHand(Handhand)

    Hand类型来自:using Valve.VR.InteractionSystem;

4. 读取Resources文件夹下的json文件

public class YourType { public string name; public List<string> things; } // 读取json文件,获取json字符串 string jsonStr = Resources.Load<TextAsset>("fileName").text; // 将json字符串转换为对象 YourType jsonObj = JsonUtility.FromJson<YourType>(jsonStr);

5. 打开streamingAssets下的exe程序

string path = Application.streamingAssetsPath + "/sceneTwo/AdministrativeHall.exe"; Application.OpenURL(path);

6. VR场景黑屏过渡

VR Camera上添加SteamVR_Fade脚本组件,调用SteamVR_Fade.Start方法即可。

using Valve.VR; // 第一个参数为渐变到的颜色,第二个参数为渐变的时间 SteamVR_Fade.Start(Color.clear, 0); // 渐变到透明 SteamVR_Fade.Start(Color.black, 1f); // 渐变到黑色

7. VR手柄提示

// 设置手柄提示 void SetGrabPinchHint(bool isBoth, string text = null) { for (int actionIndex = 0; actionIndex < SteamVR_Input.actionsIn.Length; actionIndex++) { ISteamVR_Action_In action = SteamVR_Input.actionsIn[actionIndex]; if (action.GetShortName() == "GrabPinch") { // 循环Hands,设置手柄提示 foreach (var hand in Hands) { if (action.GetActive(hand.handType)) { hand.TriggerHapticPulse(0); // 判断左右手 if (hand.handType == SteamVR_Input_Sources.LeftHand) { // 左手 ControllerButtonHints.ShowTextHint(hand, action, text ?? "左手按钮"); } else { // 右手 ControllerButtonHints.ShowTextHint(hand, action, text ?? "右手按钮"); } } } break; } } }

8. 编辑器运行时

编辑器运行时运行代码,可以使用ExecuteInEditMode特性,该特性可以让脚本在编辑器运行时运行。

using UnityEngine; [ExecuteInEditMode] public class Env_FlashPointCtrl : Controller { [Header("点位名称")] public string pointName = "FlashPoint"; // 当pointName变化时,更新点位名称 void OnValidate() { gameObject.name = pointName; } }

9. UI追踪玩家

using UnityEngine; public class VR_FollowCamCtrl : Controller { [Header("追踪空物体"), SerializeField] Transform followMainCam_TF; [Header("追踪速度"), SerializeField] float followSpeed = 3f; [Header("追踪距离"), SerializeField] float distance = 0.8f; void Update() { followMainCam_TF.position = Camera.main.transform.position + Vector3.ProjectOnPlane(Camera.main.transform.forward, Vector3.up).normalized * distance; followMainCam_TF.LookAt(Camera.main.transform); transform.position = Vector3.Lerp(transform.position, followMainCam_TF.position, Time.deltaTime * followSpeed); // 使物体的朝向与相机的朝向相反 transform.rotation = Quaternion.LookRotation(transform.position - Camera.main.transform.position); } }

10. VR手柄按键按下

using UnityEngine; public class VR_ControllerCtrl : Controller { SteamVR_Action_Boolean point; void Start() { point = SteamVR_Input.GetBooleanAction("Point"); } void Update() { if (actionBoolean.GetStateDown(SteamVR_Input_Sources.Any)) { Debug.Log("按下 Point"); } } }

11. 游戏对象Y轴面朝相机

using UnityEngine; public class VR_FaceCameraCtrl : Controller { void Update() { // 获取摄像机的位置 Vector3 cameraPosition = Camera.main.transform.position; // 计算物体需要朝向的方向向量 Vector3 targetDirection = new Vector3(cameraPosition.x - transform.position.x, 0, cameraPosition.z - transform.position.z); // 使用LookRotation函数计算出旋转角度 Quaternion targetRotation = Quaternion.LookRotation(targetDirection, Vector3.up); // 将物体的旋转角度设置为目标角度 transform.rotation = Quaternion.Euler(0, targetRotation.eulerAngles.y, 0); } }