通过头显实现凝视效果,可以对场景内的物体和UI进行交互
要点:
1.凝视效果主要实现方法:通过声明Ray类对象,发射射线,通过射线与交互物体的碰撞反馈信息
2.凝视效果的光圈转动:光圈UI为两层,上层通过调整fillAmount实现填充效果,下层作为背景浅色显示,具体调整RGBA参数
3.需要保证光圈在视角中不会产生“近大远小”效果:将光圈scale和距离相乘
4.使光圈贴在交互物体表面,不会穿过物体:使光圈和交点的法线保持垂直。
5.防止光圈发生闪烁:为光圈赋予材质,从而减少光圈面片和物体表面面片距离过近产生的闪烁现象。
复习:
1.构造射线对象,具体参照官网解释,此处由于需要,构造以摄像机向正前方发射的射线。
2.射线反馈,一般构造RaycastHit对象作为反馈值,使用Physics.Raycast(射线参数,反馈值,射线距离)方法探查射线是否发生碰撞。
3.射线反馈的一些参数:distance距离、point正交点、normal法线
示例代码:
/*为方便阅读,解释如下,VRTarget为自主编写的具体激活后的相应处理功能类
包含OnGazeat()、OnGazein()、OnGazeout()方法分别为交互彻底激活,进入交互区域,离开交互区域*/
public class StareControll : MonoBehaviour {
#region 准星变量
/// <summary>
/// 准星容器
/// </summary>
public Canvas _canvas;
/// <summary>
/// 准星图片
/// </summary>
public Image reticalImage;
/// <summary>
/// 准星初始位置
/// </summary>
private Vector3 startPosition;
/// <summary>
/// 初始缩放
/// </summary>
private Vector3 startScale;
/// <summary>
/// 倒计时时间
/// </summary>
private float lateTime=3;
/// <summary>
/// 当前逝去时间
/// </summary>
private float nowTime=0;
#endregion
#region 凝视效果
//凝视的物体
private GameObject target = null;
#endregion
// Use this for initialization
void Start () {
#region 调整光圈
//隐藏倒计时光圈
reticalImage.fillAmount = 0;
//获取准星初始位置和初始缩放
startPosition = _canvas.transform.position;
startScale = _canvas.transform.localScale;
#endregion
}
// Update is called once per frame
void Update () {
//摄像机射线
Ray ray = new Ray(transform.position,transform.forward);
//射线碰撞信息
RaycastHit hit;
#region 射线碰撞
//射线碰撞,改变准星中心
if (Physics.Raycast(ray,out hit,100)) {
#region 控制准线位置
_canvas.transform.position = hit.point;
_canvas.transform.localScale = startScale * hit.distance;
//准线与物体击中点法线方向一致
_canvas.transform.forward = hit.normal;
#endregion
//对上一个目标是否也属于规定目标,若属于,则首先执行视线移开上一个目标的状态,将其调整为关闭激活
if (target != null)
{
VRTarget old_vrtarget = target.GetComponent<VRTarget>();
old_vrtarget.OnGazeout();
}
//当前所看目标属于规定目标之一
if (hit.transform.gameObject.tag=="Finish"|| hit.transform.gameObject.tag == "Player")
{
//将目标切换为当前所看到的物体,并未当前物体执行激活处理
target = hit.transform.gameObject;
VRTarget new_vrtarget = target.GetComponent<VRTarget>();
new_vrtarget.OnGazeat();
nowTime += Time.deltaTime;
//视线是否在此停留,并且没有达到激活持续时间
if (lateTime - nowTime > 0)
{
//激活光圈倒数计时
reticalImage.fillAmount = nowTime / lateTime;
}
//视线达到激活持续时间
else
{
new_vrtarget.OnGazein(hit);
nowTime = 0;
}
}
else {
target = null;
reticalImage.fillAmount = 0;
}
}
else
{
_canvas.transform.position = startPosition;
_canvas.transform.localScale = startScale;
_canvas.transform.forward = Camera.main.transform.forward;
}
#endregion
}
}