要想用代码控制射线,首先要搞清楚射线是怎么形成的,射线有主要是组件vrtk_pointer和组件vrtk_UIPoinrer, 组件vrtk_pointer是发射一条可见的渲染射线并不能点击UI,就是给你看的,实际与UI产生交互的是vrtk_UIPoinrer组件,组件vrtk_UIPoinrer是发射一条不可见但可与UI交互的射线,SteamVR Home的射线效果就是由一条不可见但可与UI交互的射线实时检测,射线是否在UI上,是在UI上则显示一条可见的渲染射线,否则隐藏。
以下是vrtk_UIPoinrer组件源码,则可调用PointerActive()函数判断是否发射一条不可见但可UI交互的射线:
以下是vrtk_pointer组件源码,则可调用IsPointerActive()函数判断是否发射一条可见但不可UI交互的渲染射线及用Toggle()函数控制射线开启与关闭:
则可如下设置:
不用手柄的按钮来改变射线的状态,两个的ActivationButton都设为Undefined,这样vrtk_UIPoinrer组件只要将ActivationMode在HoldButton与AlwaysOn的切换,就可以让这不可见的射线是启用或关闭,组件vrtk_pointer则用IsPointerActive()函数和Toggle()函数,来控制这渲染射线的开启或关闭。
核心代码,如下:
//当前射线组件
static VRTK_Pointer vRTK_Pointer;
//实际UI射线组件
static VRTK_UIPointer vRTK_UIPointer;
//右手控制器
VRTK_ControllerEvents controllerEvents;
void OnEnable()
{
//获取射线组件
vRTK_Pointer = GetComponent<VRTK_Pointer>();
//实际UI射线
vRTK_UIPointer = GetComponent<VRTK_UIPointer>();
//获取手柄控制器
controllerEvents = GetComponent<VRTK_ControllerEvents>();
}
/// <summary>
/// 开启或关闭射线
/// </summary>
/// <param name="isBool">是否开启射线</param>
public static void vRTKPointer(bool isBool)
{
bool b = vRTK_Pointer.IsPointerActive();
//实际射线模式切换
vRTK_UIPointer.activationMode=isBool? VRTK_UIPointer.ActivationMethods.AlwaysOn: VRTK_UIPointer.ActivationMethods.HoldButton;
//已经开启则返回,未开启则继续
if (isBool ? b : !b) return;
//渲染射线状态切换操作
vRTK_Pointer.Toggle(true);
vRTK_Pointer.Toggle(false);
}
只要挂载脚本,则可以控制射线的开启和关闭。
完整的脚本:
using UnityEngine;
using VRTK;
public class rightControllerEvent : MonoBehaviour
{
//当前射线组件
static VRTK_Pointer vRTK_Pointer;
//当前射线渲染组件
static VRTK_StraightPointerRenderer vRTK_StraightRenderer;
//实际UI射线组件
static VRTK_UIPointer vRTK_UIPointer;
//右手控制器
VRTK_ControllerEvents controllerEvents;
//若该键被禁用,则返回
public static bool isDisableTouch;
//当前是否有其它UI占用
public static bool isOccupyUI;
//记录菜单键
public static bool isPressed;
public GameObject[] gameObjects;
void OnEnable()
{
isPressed = true;
//获取射线组件
vRTK_Pointer = GetComponent<VRTK_Pointer>();
//获取射线渲染组件
vRTK_StraightRenderer = GetComponent<VRTK_StraightPointerRenderer>();
//实际UI射线
vRTK_UIPointer = GetComponent<VRTK_UIPointer>();
//获取手柄控制器
controllerEvents = GetComponent<VRTK_ControllerEvents>();
//防止有UI时,手柄断开射线失效
foreach (GameObject go in gameObjects)
{
if (go.activeSelf)
{
vRTK_Pointer.activateOnEnable = true;
break;
}
}
if (controllerEvents == null)
return;
controllerEvents.ButtonTwoPressed += DoButtonTwoPressed;
controllerEvents.TriggerPressed += DoTriggerPressed;
}
void OnDisable()
{
vRTK_Pointer.activateOnEnable = false;
if (controllerEvents == null)
return;
controllerEvents.ButtonTwoPressed -= DoButtonTwoPressed;
controllerEvents.TriggerPressed -= DoTriggerPressed;
}
public static void setvRTK_StraightRenderer(int n=0)
{
float[] raySizeArr = { 0.0012f, 0.0008f };
vRTK_StraightRenderer.scaleFactor = raySizeArr[n];
}
/// <summary>
/// 开启或关闭射线
/// </summary>
/// <param name="isBool">是否开启射线</param>
public static void vRTKPointer(bool isBool)
{
bool b = vRTK_Pointer.IsPointerActive();
//实际射线模式切换
vRTK_UIPointer.activationMode=isBool? VRTK_UIPointer.ActivationMethods.AlwaysOn: VRTK_UIPointer.ActivationMethods.HoldButton;
//已经开启则返回,未开启则继续
if (isBool ? b : !b) return;
//渲染射线状态切换操作
vRTK_Pointer.Toggle(true);
vRTK_Pointer.Toggle(false);
}
//菜单
void DoButtonTwoPressed(object sender, ControllerInteractionEventArgs e)
{
//UI是否被占用,是则返回
if (isOccupyUI) return;
//菜单UI与射线的启用
UIManager.Instance.setUI(1, isPressed);
vRTKPointer(isPressed);
isPressed = !isPressed;
}
public static void EnableButtonTwo(bool isBool)
{
if (isBool)
{
//不给调用菜单UI
isOccupyUI = true;
//关闭菜单UI
UIManager.Instance.setUI(1, false);
}
else
{
//射线关闭
vRTKPointer(false);
//设为可触发
isPressed = true;
//给调用菜单UI
isOccupyUI = false;
}
}
//Trigger键
void DoTriggerPressed(object sender, ControllerInteractionEventArgs e)
{
//若该键被禁用,则返回
if (isDisableTouch) return;
switch (Manager.controllerStruct.interactObjectType)
{
case InteractObjectType.Touch:
Manager.manageInvoke();
break;
}
}
}