Обнаружение движения контроллера в том же направлении, что и кнопка VR - PullRequest
0 голосов
/ 25 сентября 2019

Я работаю над проектом VR и изо всех сил пытаюсь сделать что-то, что не должно быть таким сложным, но я действительно плохо разбираюсь в математике: x

То, что я хочу сделать, это иметь "физические "кнопки в мире, которые я могу нажимать пальцем, чтобы нажимать / отжимать его, эта часть работает очень хорошо, и ощущение прекрасное, НО:

В настоящее время, чтобы" нажать "кнопку, яиспользуя положение z дельты моего контроллера, поэтому я не могу нажать кнопку сверху, например, потому что мне нужна была бы дельта y.

Я пытаюсь, чтобы кнопки были направлены в любом направлении,и смогу толкать их, используя правую ось моего контроллера, но не могу обойти это: x

Мне нужно было бы нажимать кнопку в зависимости от ее положения / вращения.

Я не знаю, действительно ли это понятно (возможно, нет), возможно, я просто пропустил что-то действительно очевидное.

Вот мой код для моей кнопки, перечисление, вероятно, бесполезно, яЯ просто пробую вещи LOL

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
}

JVRFingerInteract вызывается каждый кадр, которым мой палец касается кнопки, я просто делаю перекрытие в своем пальце, чтобы получить интерактивные объекты.

Ось нажатия кнопки - это локальная ось Z кнопки и положительные точки Z из поверхность кнопки.

Ответы [ 2 ]

1 голос
/ 25 сентября 2019

Хорошо, я нашел решение, попробовав, я не понимаю, КАК и ПОЧЕМУ оно работает, но оно работает ...

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

_forward - кнопка вперед, а jvrPos - локальная дельта.моего контроллера / палец

0 голосов
/ 25 сентября 2019

Предполагая, что поверхность вашей кнопки обращена к локальному направлению up кнопки:

local axes of button

Тогда вы можете использовать точечное произведение между кнопками up в мировом пространстве и дельта в мировом пространстве, чтобы определить, насколько палец движется против этого направления:

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.

local axes of button

Если другойЛокальное направление указывает на поверхность кнопки, например, ее отрицательный forward, вы просто используете соответствующий локальный вектор в мировом пространстве:

negative forward is pointing out of the button

float deltaInButtonDown = Vector3.Dot(worldFingerDelta, 
        buttonTransform.forward); // negatives cancel out

Кроме того, если поверхность, на которой находится кнопка, перемещается в мировом пространстве, вы можете использовать Vector3.Dot(worldFingerDelta - worldButtonSurfaceDelta, buttonTransform.forward);, чтобы такие вещи, как нажатие самой кнопки, перемещались в неподвижный палец.


О вашем ответе ....

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

_forward - кнопка вперед, а jvrPos - локальная дельта моего контроллера / finger

Что касается векторной математики, вы делаете точечное произведение междувперёд Уттона и локальная дельта после некоторого преобразования инверсии / отражения применяются к нему.Итак, еще один способ написать свой ответ таков:

new Vector3 vec = new Vector3(jvrPos.z, -jvrPos.y, -jvrPos.x);
_delta = Vector3.Dot(vec, buttonTransform.forward);

Как мы обнаружили в комментариях к вашему ответу, это преобразование, основанное на вращении мира родителя контроллера,превращает вашу локальную дельту в негатив мировой дельты.Итак, взяв отрицательное значение, которое вы имеете для вектора, и сделав его отрицательным в вызове Dot, вы можете написать еще один способ:

new Vector3 calculatedWorldFingerDelta = new Vector3(-jvrPos.z, jvrPos.y, jvrPos.x);
_delta = Vector3.Dot(-calculatedWorldFingerDelta, buttonTransform.forward);

И так какскалярное произведение A и -B равно скалярному произведению -A и B, ваш ответ эквивалентен:

new Vector3 calculatedWorldFingerDelta = new Vector3(-jvrPos.z, jvrPos.y, jvrPos.x);
_delta = Vector3.Dot(calculatedWorldFingerDelta, -buttonTransform.forward);

Что, если calculatedWorldFingerDelta равно worldFingerDelta, равнота же самая формула выше для кнопки с положительным направлением z, указывающим вне поверхности кнопки.

Я бы использовал worldFingerDelta напрямую, потому что, если поворот мира или положение родителя пальца изменится, топреобразование, которое вы используете сейчас, не гарантированно даст вам calculatedWorldFingerDelta, что равно worldFingerDelta, и ваш ответ больше не будет работать.

...