Cardboard VR开发,Gaze操作实现VR的目选效果
发表于2018-05-12
CardBoard应该是目前VR市场上最廉价的”VR头显”,虽然它廉价,但并不会阻碍大家针对Cardboard开发相应的VR应用,下面就来看看通过Gaze操作实现VR的目选效果。


由于Cardboard没什么按键,所以选择之类的事情只能用目选来进行,那怎么实现目选呢?可以想象一下,目选无非就是两部分,a:旋转读条;b、确认选择。
但是有一点,两部分分开来做那很简单啦,但是怎么放到一起呢?
首先,我们先来看看该部分原本给你提供的代码:Teleport.cs
// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// [url=http://www.apache.org/licenses/LICENSE-2.0]http://www.apache.org/licenses/LICENSE-2.0[/url]
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(Collider))]
public class Teleport : MonoBehaviour, ICardboardGazeResponder {
private Vector3 startingPosition;
void Start() {
startingPosition = transform.localPosition;
SetGazedAt(false);
}
void LateUpdate() {
Cardboard.SDK.UpdateState();
if (Cardboard.SDK.BackButtonPressed) {
Application.Quit();
}
}
public void SetGazedAt(bool gazedAt) {
GetComponent<Renderer>().material.color = gazedAt ? Color.green : Color.red;
}
public void Reset() {
transform.localPosition = startingPosition;
}
public void ToggleVRMode() {
Cardboard.SDK.VRModeEnabled = !Cardboard.SDK.VRModeEnabled;
}
public void ToggleDistortionCorrection() {
switch(Cardboard.SDK.DistortionCorrection) {
case Cardboard.DistortionCorrectionMethod.Unity:
Cardboard.SDK.DistortionCorrection = Cardboard.DistortionCorrectionMethod.Native;
break;
case Cardboard.DistortionCorrectionMethod.Native:
Cardboard.SDK.DistortionCorrection = Cardboard.DistortionCorrectionMethod.None;
break;
case Cardboard.DistortionCorrectionMethod.None:
default:
Cardboard.SDK.DistortionCorrection = Cardboard.DistortionCorrectionMethod.Unity;
break;
}
}
public void ToggleDirectRender() {
Cardboard.Controller.directRender = !Cardboard.Controller.directRender;
}
public void TeleportRandomly() {
Vector3 direction = Random.onUnitSphere;
direction.y = Mathf.Clamp(direction.y, 0.5f, 1f);
float distance = 2 * Random.value + 1.5f;
transform.localPosition = direction * distance;
}
#region ICardboardGazeResponder implementation
/// Called when the user is looking on a GameObject with this script,
/// as long as it is set to an appropriate layer (see CardboardGaze).
public void OnGazeEnter() {
SetGazedAt(true);
}
/// Called when the user stops looking on the GameObject, after OnGazeEnter
/// was already called.
public void OnGazeExit() {
SetGazedAt(false);
}
// Called when the Cardboard trigger is used, between OnGazeEnter
/// and OnGazeExit.
public void OnGazeTrigger() {
TeleportRandomly();
}
#endregion
}
其实大部分代码我都从头到尾稍稍读了一遍,其实接口已经清楚地给我们放出来了,就是这块代码。代码中有一个SetGazedAt的方法,该方法就是当你水平目视前方的物体算作你选中的物体,官方demo里是当你目视一个cube时把该cube的颜色由红色换为绿色。
二、好的,突破口已经找到了,我们来看看怎么实现旋转读条的效果:

其实很简单,研究过UI的人应该都明白,就是一个很简单的遮罩。
放一个画布canvas,然后创建一个image命名为imageBg作为背景,再创建一个image命名为imageFill作为内容,然后复制一个imageFill,选color属性调成半透明,颜色改成灰色,image Type选择Filled,大小都调合适了。然后就做成了,如图:
三、把Teleport.cs拖到imageBg上,我们再来看刚刚的代码部分,按常理来说,点击选中面板中可以直接添加一个button属性就可以实现,但是我们现在要的是目选,所以就要自己来判断了,其实也不难,也就是一个触发器的问题。
public void SetGazedAt(bool gazedAt) {
isStartTime = gazedAt ? true : false;
}
上面这个函数前面加上public
在imageBg下添加一个Event Trigger,添加Pointer Enter和Pointer Exit,分别对应SetGazeAt方法的两个值
在初始化里获取imageFill的image组件,设置fillAmount的初始值为零。
在update里利用计时器来控制旋转读条的快慢,并在读完时刻判断目选的选中状态。
修改后的全部代码如下:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class TeleportGUI : MonoBehaviour, ICardboardGazeResponder {
public float coldTime = 1;
private Image imagefill;
private float timer = 0;
private bool isStartTime = false;
private double minNum = 0.01;
private double maxNum = 0.02;
private bool isNext = false;
public Text index;
int IndexInt = 0;
string IndexStr = "";
// Use this for initialization
void Start () {
imagefill = transform.Find ("Imagefill").GetComponent<Image> ();
imagefill.fillAmount = 0;
SetGazedAt (false);
}
void LateUpdate() {
Cardboard.SDK.UpdateState();
if (Cardboard.SDK.BackButtonPressed) {
Application.Quit();
}
}
public void SetGazedAt(bool gazedAt) {
isStartTime = gazedAt ? true : false;
}
// Update is called once per frame
void Update () {
if (isStartTime) {
timer += Time.deltaTime;
imagefill.fillAmount = (coldTime - timer) / coldTime;//从1到0减小
if (timer >= coldTime) {
imagefill.fillAmount = 0;
timer = 0;
isStartTime = false;
}
}
if(!isStartTime) {
timer = 0;
imagefill.fillAmount = 0;
}
if (imagefill.fillAmount < maxNum && imagefill.fillAmount >minNum) {
isNext = true;
}
if (isNext) {
ChooseManageScript.Instance.A_Btn ();
index = GameObject.Find("IndexBackground").transform.Find ("Index").GetComponent<Text> ();
IndexInt = int.Parse(index.text);
IndexInt += 1;
IndexStr = IndexInt.ToString();
index.text = IndexStr;
isNext = false;
}
}
public void TeleportRandomly() {
Vector3 direction = Random.onUnitSphere;
direction.y = Mathf.Clamp(direction.y, 0.5f, 1f);
float distance = 2 * Random.value + 1.5f;
transform.localPosition = direction * distance;
}
#region ICardboardGazeResponder implementation
/// Called when the user is looking on a GameObject with this script,
/// as long as it is set to an appropriate layer (see CardboardGaze).
public void OnGazeEnter() {
SetGazedAt(true);
}
/// Called when the user stops looking on the GameObject, after OnGazeEnter
/// was already called.
public void OnGazeExit() {
SetGazedAt(false);
}
// Called when the Cardboard trigger is used, between OnGazeEnter
/// and OnGazeExit.
public void OnGazeTrigger() {
TeleportRandomly();
}
#endregion
}
来自:https://blog.csdn.net/yushengqi12345/article/details/77569658
