赞
踩
鉴于该文章点赞和收藏那么高,我推荐一款插件 VR Interaction Framework
该插件适配大部分的vr硬件,未来应该也超级兼容,而且UI事件这块兼容UGUI,单单这点就很亮眼。兼容UGUI,不用再下那么大功夫再搞按钮事件这块了。
* 我们只做VR内容时,如果要用到例如HTC手柄类的硬件的话,可能就需要一个射线点击的功能,如,点击某一个图标,按下手柄,触发点击按钮事件,那么这个类就是解决这类问题的一步
* 射线碰撞事件的类,可以移植到大多数VR SDK上,因为每个平台都封装有了自己的注视管理,但这个引擎自身的拓展开发,方便拓展和维护,下面会有一个Debug的注释代码,可以注释掉来测试效果,如果需要有碰撞效果,必须给物体加上碰撞体,并且标签要对应,碰撞层也要对应,其实这么麻烦的原因也是为了后期的拓展开发,基础层的条件触发牢固后,上层才会安稳,舒服。
碰撞逻辑我是放在LateUpdate里的,因为Input类放在Update里处理,解决完输入后逻辑后再处理碰撞逻辑。
这是个抽象类,你必须新建一个类来继承他,实现获取射线的方法
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- namespace CameraFixationManager
- {
- public abstract class CameraFixationManager : MonoBehaviour
- {
- /// <summary>
- /// 射线是否撞到了有触发事件的碰撞体
- /// </summary>
- public static bool IsImpactCollider = false;
- /// <summary>
- /// 撞击点的位置
- /// </summary>
- public Vector3 HitPosition = Vector3.zero;
- /// <summary>
- /// 射线可以碰撞到的层
- /// </summary>
- public int RayColliderLayer = 5;
-
- #region 事件回调
- /// <summary>
- /// 射线进入回调
- /// </summary>
- public Action<GameObject> RayEnter;
- /// <summary>
- /// 射线离开的回调
- /// </summary>
- public Action<GameObject> RayLeave;
- /// <summary>
- /// 射线正在射中的回调
- /// </summary>
- public Action<GameObject> RayEntering;
- #endregion
-
-
- /// <summary>
- /// 响应的标签层,所有的交互事件都需要放到该层
- /// </summary>
- public string ResponseTag;
- /// <summary>
- /// 是否播放音乐特效
- /// </summary>
- public bool IsPlayAudio = true;
- /// <summary>
- /// 射线缓冲,意思就是射线当前碰撞套的物体
- /// </summary>
- private Transform _transform = null;
- /// <summary>
- /// 是否碰撞到
- /// </summary>
- protected bool IsCollider = true;
-
-
- protected virtual void Awake()
- {
-
- }
- /// <summary>
- /// 放在延迟更新是因为,输入事件一般是在Update之前,所以,处理完输入逻辑后,在 Update里判断输入状态,再在延迟更新里判断碰撞状态,这样就不用手动
- /// edit/ProjectSettings/ScriptExecutionOrder的编排脚本的方法执行顺序
- /// </summary>
- void LateUpdate()
- {
- if (!IsCollider) return;
- RaycastHit hit;
- //只能向屏幕中点发射线
- var ray = GetRay();//这里进一步抽象,因为有相机注视,还有手柄射线注视
-
- if (Physics.Raycast(ray, out hit,2000f,1<< RayColliderLayer))//这里把5层设置为可碰撞层,其他层都要忽略掉
- {
- // Debug.Log("碰撞到的物体名字是:" + hit.transform.name);
- HitPosition = hit.point;//碰撞点事世界位置,切记 切记
-
- if (!hit.transform.CompareTag(ResponseTag) )//如果不属于ResponseTag标签,则不进行消息触发
- {
- IsImpactCollider = false;
-
-
- if (_transform != null)//物体离开回调
- {
- if (RayLeave != null)
- RayLeave(_transform.gameObject);
- // Debug.Log("离开了" + _transform.name);
- }
- _transform = null;
-
- return;
- }
- IsImpactCollider = true;
- //被碰撞的物体第一次进入触发回调,第二个逻辑是射线从一个物体移动到另外一个物体的判断
- if (_transform == null || (_transform != hit.transform && _transform != null))
- {
- if (RayEnter != null)
- RayEnter(hit.transform.gameObject);
- // if (IsPlayAudio)
- // AudioManager.Instance.PlayAudio(AudioType.RayPass);
- // Debug.Log("进入了" + hit.transform.name);
-
- if(_transform!=null)
- {
- if (RayLeave != null)
- RayLeave(_transform.gameObject);
- // Debug.Log("离开了" + _transform.name);
- }
- _transform = hit.transform;
- }
- else if(_transform == hit.transform)//在进入物体的第二帧以上
- {
- if (RayEntering != null)
- RayEntering(hit.transform.gameObject);
- // Debug.Log("持续碰撞物体:" + hit.transform.name);
- _transform = hit.transform;
- }
- }
- else
- {
- IsImpactCollider = false;
-
- HitPosition = Vector3.zero;
-
- if ( _transform!= null)//物体离开回调
- {
- if (RayLeave != null)
- RayLeave(_transform.gameObject);
- // Debug.Log("离开了" + _transform.name);
- }
- _transform = null;
- }
- }
-
- protected abstract Ray GetRay();
-
-
-
- protected virtual void OnDestroy()
- {
-
- }
- }
- }
-
好了,如果你新建一个类来继承他了,我这里实现方法是
protected override Ray GetRay()
{
Ray ray = new Ray(RayStartingPoint.transform.position, RayStartingPoint.transform.forward);
return ray;
}
RayStartingPoint为射线的发射点 这样就可以试着运行看看了,写到了这里,你会发现看不到射线,那我们这里再给你继承CameraFixationManager 的类实现一个射线显示的方法,这个射线是有宽度的,这个方法是Unity提供的接口
- public void OnRenderObject()
- {
- GL.PushMatrix();
-
- mat.SetPass(0);
-
- GL.Begin(GL.QUADS);
-
- GL.Color(Color.cyan);
-
-
-
- //该面片是以逆时针画线,第一个点是在物体右边开始
- //右边开始的第一个点
- Vector3 position1 = RayStartingPoint.transform.position + RayStartingPoint. transform.right * Width;
- //右边远方的第二个点
- Vector3 position2 = RayStartingPoint.transform.position;
- //远方没有偏移的第三个点
- Vector3 position3 = RayStartingPoint. transform.position;
- //物体的原点为第四个点
- Vector3 position4 = RayStartingPoint.transform.position;
-
- //设置射线
- Ray rayer = new Ray(RayStartingPoint.transform.position, RayStartingPoint.transform.forward);
- RaycastHit rayhit;
- //当射线与物体碰撞时,获取rayhit(rayhit.point射线与物体的接触点,rayhit.distance向量方向,rayhit.collider.gameobject获取物体的所有信息)
- if (Physics.Raycast(rayer, out rayhit))
- {
- //右边远方的第二个点
- position2 = rayhit.point + RayStartingPoint.transform.right * Width;
- //远方没有偏移的第三个点
- position3 = rayhit.point;
- //把球体放在射线与物体的接触点
- _sphere.transform.position = new Vector3(rayhit.point.x, rayhit.point.y, rayhit.point.z);
- }
- else
- {
- position2 = position1 + RayStartingPoint.transform.forward * Lenght;
- position3 = RayStartingPoint. transform.position + RayStartingPoint.transform.forward * Lenght;
- _sphere.transform.position = new Vector3(100000f, 0f, 0f);
- }
-
-
- //1
- GL.Vertex(position1);
- //2
- GL.Vertex(position2);
- //3
- GL.Vertex(position3);
- //4
- GL.Vertex(position4);
-
- GL.End();
-
- GL.PopMatrix();
-
- }
_sphere是一个小球体模型,作用是在碰撞点显示为一个球体,这个就需要你自己把他手动拖进去了,到了这一步,大概就把射线碰撞这块给处理好了。下一步我们处理手柄输入的问题
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。