C# 检测控制器在与VR按钮相同方向上的移动

C# 检测控制器在与VR按钮相同方向上的移动,c#,unity3d,quaternions,vectormath,C#,Unity3d,Quaternions,Vectormath,我正在做一个虚拟现实项目,我正在努力做一些不应该那么难的事情,但我的数学真的很差:x 我想做的是,在这个世界上有一个“物理”按钮,我可以用我的手指按下/取消按下它,这部分工作非常好,感觉非常完美,但是: 目前,要“按下”按钮,我使用控制器的z增量位置,因此我不能从顶部按下按钮,例如,因为我需要y增量 我试图让按钮朝向任何方向,并且能够使用控制器的右轴来推动它们,但是我的头无法绕过它:x 我需要能够根据它的位置/旋转来按下按钮 我不知道这是否真的可以理解(可能不是),也许我只是错过了一些非常明显的

我正在做一个虚拟现实项目,我正在努力做一些不应该那么难的事情,但我的数学真的很差:x

我想做的是,在这个世界上有一个“物理”按钮,我可以用我的手指按下/取消按下它,这部分工作非常好,感觉非常完美,但是:

目前,要“按下”按钮,我使用控制器的z增量位置,因此我不能从顶部按下按钮,例如,因为我需要y增量

我试图让按钮朝向任何方向,并且能够使用控制器的右轴来推动它们,但是我的头无法绕过它:x

我需要能够根据它的位置/旋转来按下按钮

我不知道这是否真的可以理解(可能不是),也许我只是错过了一些非常明显的东西

这是我的按钮代码,枚举部分可能没用,我只是在尝试一些东西

using System;
using UnityEngine;

public class JVRButton : MonoBehaviour, IJVRFingerInteract
{

    [SerializeField] private Vector3 pressedPosition;
    [SerializeField] private Vector3 defaultPosition;
    [SerializeField] private Vector3 unpressPosition;

    [SerializeField] private LinearDragNormal direction;

    public bool Pressed { get; private set; }
    public event Action<bool> OnStateChange;

    private bool _changedState;
    private Transform _transform;
    private Vector3 _tmp;
    private float _delay;

    private float _delta; 

    private void Awake()
    {
        _transform = transform;
        _transform.localPosition = Pressed ? pressedPosition : defaultPosition;
    }

    private void Update()
    {
        _delay += Time.deltaTime;
        if (_delay < 0.1f) return;

        // "Spring" effect
        _transform.localPosition = Vector3.MoveTowards(_transform.localPosition, Pressed ? pressedPosition : defaultPosition, Time.deltaTime / 2);
    }

    public void JVRFingerInteract(JVRFinger jvrFinger)
    {
        Vector3 test = Quaternion.FromToRotation(jvrFinger.transform.forward, _transform.forward).eulerAngles;

        Debug.Log(test);

        switch(direction)
        {
            case LinearDragNormal.XPositive:
                _delta = Mathf.Min(jvrFinger.JVRController.DeltaPositionLocal.z, 0);
                break;
            case LinearDragNormal.XNegative:
                _delta = Mathf.Max(jvrFinger.JVRController.DeltaPositionLocal.z, 0);
                break;
            case LinearDragNormal.YPositive:
                _delta = Mathf.Max(jvrFinger.JVRController.DeltaPositionLocal.y, 0);
                break;
            case LinearDragNormal.YNegative:
                _delta = Mathf.Min(jvrFinger.JVRController.DeltaPositionLocal.y, 0);
                break;
             case LinearDragNormal.ZPositive:
                _delta = Mathf.Min(jvrFinger.JVRController.DeltaPositionLocal.x, 0);
                break;
            case LinearDragNormal.ZNegative:
                _delta = Mathf.Max(jvrFinger.JVRController.DeltaPositionLocal.x, 0);
                break;
            default:
                throw new ArgumentOutOfRangeException();
        }

        MoveButton(Pressed ? unpressPosition : pressedPosition);
    }

    private void MoveButton(Vector3 position)
    {
        if (_changedState && _delay < 0.5f) return;
        _delay = 0;
        _changedState = false;            
        _tmp = _transform.localPosition;
        _tmp = Vector3.MoveTowards(_tmp, position, _delta);
        if (_tmp.x < position.x) _tmp.x = position.x;
        if (_tmp.y < position.y) _tmp.y = position.y;
        if (_tmp.z < position.z) _tmp.z = position.z;
        _transform.localPosition = _tmp;

        if (_transform.localPosition == pressedPosition)
        {
            Pressed = true;
            _changedState = true;
            OnStateChange?.Invoke(Pressed);
        }
        else if (_transform.localPosition == unpressPosition)
        {
            Pressed = false;
            _changedState = true;
            OnStateChange?.Invoke(Pressed);
        }
    }    
}

public enum LinearDragNormal
{
    XPositive,
    XNegative,
    YPositive,
    YNegative,
    ZPositive,
    ZNegative
}
使用系统;
使用UnityEngine;
公共类JVRButton:MonoBehavior,IJVR
{
[Serialized Field]专用向量3按位置;
[SerializeField]私有向量3默认位置;
[SerializeField]私有向量3取消定位;
[SerializeField]专用线RagNormal方向;
公共bool{get;private set;}
针对国家变化的公共事件行动;
私有布尔-变更状态;
私有变换_变换;
私有向量3_tmp;
私人浮动延迟;
私人浮动三角洲;
私人空间
{
_变换=变换;
_transform.localPosition=按下?按下位置:默认位置;
}
私有void更新()
{
_延迟+=时间延迟时间;
如果(_延迟<0.1f)返回;
//“春天”效应
_transform.localPosition=Vector3.movetoward(_transform.localPosition,按下?按下位置:defaultPosition,Time.deltaTime/2);
}
公共无效JVRFinger交互(JVRFinger JVRFinger)
{
Vector3测试=四元数.FromToRotation(jvrFinger.transform.forward,_transform.forward).euleranges;
调试日志(test);
开关(方向)
{
大小写行RagNormal.XPositive:

_delta=Mathf.Min(jvrFinger.JVRController.DeltaPositionLocal.z,0); 打破 大小写行RagNormal.x负值:
_delta=Mathf.Max(jvrFinger.JVRController.DeltaPositionLocal.z,0); 打破 大小写行RagNormal.y正:
_delta=Mathf.Max(jvrFinger.JVRController.DeltaPositionLocal.y,0); 打破 大小写行RagNormal.YNegative:
_delta=Mathf.Min(jvrFinger.JVRController.DeltaPositionLocal.y,0); 打破 大小写行RagNormal.ZPositive:
_delta=Mathf.Min(jvrFinger.JVRController.DeltaPositionLocal.x,0); 打破 案例线性rRagNormal.ZNegative:
_delta=Mathf.Max(jvrFinger.JVRController.DeltaPositionLocal.x,0); 打破 违约: 抛出新ArgumentOutOfRangeException(); } 移动按钮(按下?取消按下位置:按下位置); } 专用无效移动按钮(矢量3位置) { 如果(_changedState&&u delay<0.5f)返回; _延迟=0; _changedState=false; _tmp=_transform.localPosition; _tmp=矢量3.向(tmp,位置,δ)移动; 如果(_tmp.x
JVRFingerInteract被称为我手指触摸按钮的每一帧,我只是在手指上做一个重叠球体来获得可交互的对象


按钮的推动轴是按钮的局部Z轴,正Z轴指向按钮表面。

好的,我通过尝试找到了解决方案,我不明白它是如何工作的,为什么工作的,但它确实

_delta = (_forward.x * jvrPos.z + _forward.y * -jvrPos.y + _forward.z * -jvrPos.x);
if (_delta < 0) _delta = 0;

_delta=(_forward.x*jvrPos.z+_forward.y*-jvrPos.y+_forward.z*-jvrPos.x);
如果(_δ<0)_δ=0;

_forward是按钮forward,jvrPos是控制器/手指的本地增量

假设按钮表面朝向按钮的本地
向上
方向:

Vector3 worldFingerDelta;
Transform buttonTransform;

float deltaInButtonDown = Vector3.Dot(worldFingerDelta, 
        -buttonTransform.up);

// when deltainButtonDown is positive, the finger is moving in the 
// same direction as "pushing the button" 
// When it is negative, the finger is moving in the opposite direction.
// The magnitude of deltaInButtonDown is how much the finger is 
// moving in that direction.

然后,您可以使用世界空间中按钮的
向上
和世界空间中的增量之间的点积来确定手指逆该方向移动的程度:

Vector3 worldFingerDelta;
Transform buttonTransform;

float deltaInButtonDown = Vector3.Dot(worldFingerDelta, 
        -buttonTransform.up);

// when deltainButtonDown is positive, the finger is moving in the 
// same direction as "pushing the button" 
// When it is negative, the finger is moving in the opposite direction.
// The magnitude of deltaInButtonDown is how much the finger is 
// moving in that direction.

如果一个不同的局部方向指向按钮的表面外,例如它的负数
向前
,则只需在世界空间中使用相应的局部向量:

此外,如果按钮所在的曲面在世界空间中移动,则需要使用
Vector3.Dot(worldFingerDelta-worldButtonSurfaceDelta,buttonTransform.forward)以允许按钮通过移动到静止的手指中而自动按下


关于你的答案

正如我们在您答案的注释中所发现的,基于控制器父级的世界旋转的转换将本地增量转换为世界增量的负数。所以取向量的负数,在
D中取负数
_delta = (_forward.x * jvrPos.z + _forward.y * -jvrPos.y 
        + _forward.z * -jvrPos.x);
if (_delta < 0) _delta = 0; 
new Vector3 vec = new Vector3(jvrPos.z, -jvrPos.y, -jvrPos.x);
_delta = Vector3.Dot(vec, buttonTransform.forward);
new Vector3 calculatedWorldFingerDelta = new Vector3(-jvrPos.z, jvrPos.y, jvrPos.x);
_delta = Vector3.Dot(-calculatedWorldFingerDelta, buttonTransform.forward);
new Vector3 calculatedWorldFingerDelta = new Vector3(-jvrPos.z, jvrPos.y, jvrPos.x);
_delta = Vector3.Dot(calculatedWorldFingerDelta, -buttonTransform.forward);