Движение в VR с Unity для Oculus Go - PullRequest
       29

Движение в VR с Unity для Oculus Go

0 голосов
/ 24 октября 2018

Я пытаюсь создать приложение VR для Oculus go.Я пытаюсь переместить OVRPlayerContoller, указывая на позицию на земле, щелкая, чтобы установить целевую позицию, а затем ваш персонаж движется к ней.Контроллер плеера не движется к указанной точке, даже если объект создан на этой позиции. Я написал для него этот скрипт, прикрепил и прикрепил его к OVRPlayerController.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ClickToMove : MonoBehaviour
{

private Vector3 targetPos; //This Vector3 will store the position where we click to move.

private bool Moving = false; //This bool keeps track of whether we are in the process of moving or not.

private GameObject targetInstance;

//The variables we want to customize. Added info headers to these for the Unity Editor.

[Header("Our Go controller object")]

public GameObject goController;

[Header("Movement Speed")]

public float speed = 1;

[Header("Stop When This Far Away From Target")]

public float haltDistance = 0;

[Header("Optional Target Object")]

public GameObject targetObj;

void Update()

{

    MoveToTarget(); //Here we simply run our MoveToTarget method in the Update method.

    //That way we don't clutter up the Update method with too much code.

}

void MoveToTarget() //Here we do the cluttering instead.

{

    var ray = new Ray(goController.transform.position, goController.transform.forward); //Create a ray going from the goController position and in the Forward direction of the goController.

    RaycastHit hitInfo; //Store info about what the ray hits.

    Physics.Raycast(ray, out hitInfo, 100);

    if (OVRInput.GetUp(OVRInput.Button.PrimaryIndexTrigger)) //If we release the trigger..

    {

        targetPos = hitInfo.point; //Make our targetPos assume the positional value of the hit point.

        if (targetObj) //If we have specified a Target Object to mark where we click.

        //If we didn't, then we don't want to try to instantiate it.

        {

            if (targetInstance) //If there is already a Target Object in the scene.

            {

                Destroy(targetInstance); //Destroy it.

            }

            targetInstance = Instantiate(targetObj, targetPos, transform.rotation); //Create our Target object at the position we clicked.

        }

        Moving = true; //And finally we set Moving to True.

    }

    if (Moving == true) //Since Moving is now true

    {

        transform.position = Vector3.MoveTowards(transform.position, new Vector3(targetPos.x, transform.position.y, targetPos.z), speed * Time.deltaTime); //Transform our x and z position to move towards the targetPos.

        //Note that our y position is kept at default transform position since we only want to move along the ground plane.

    }

    if (Vector3.Distance(transform.position, targetPos) <= haltDistance + 1) //Check proximity to targetPos. Mainly useful to keep your player from setting a target position right next to say a building and then end up clipping through half of it.

    {

        if (targetInstance) //If we created a Target Object..

        {

            Destroy(targetInstance); //Then we want to destroy it when we reach it.

        }

        Moving = false; //Since we have now arrived at our target destination.

    }

}

}

Я создал префаб куба для целевого объекта и перетащил префаб TrackedRemote (который содержит модель контроллера Go и скрипт) в слот Go Contoller.

Затем я создал луч из моего контроллера, используя приведенный ниже скрипт, и подключил его к OVRCameraRig.

using UnityEngine;
using UnityEngine.Events;
public class VRRaycaster : MonoBehaviour
{

[System.Serializable]
public class Callback : UnityEvent<Ray, RaycastHit> { }

public Transform leftHandAnchor = null;
public Transform rightHandAnchor = null;
public Transform centerEyeAnchor = null;
public LineRenderer lineRenderer = null;
public float maxRayDistance = 500.0f;
public LayerMask excludeLayers;
public VRRaycaster.Callback raycastHitCallback;

void Awake()
{
    if (leftHandAnchor == null)
    {
        Debug.LogWarning("Assign LeftHandAnchor in the inspector!");
        GameObject left = GameObject.Find("LeftHandAnchor");
        if (left != null)
        {
            leftHandAnchor = left.transform;
        }
    }
    if (rightHandAnchor == null)
    {
        Debug.LogWarning("Assign RightHandAnchor in the inspector!");
        GameObject right = GameObject.Find("RightHandAnchor");
        if (right != null)
        {
            rightHandAnchor = right.transform;
        }
    }
    if (centerEyeAnchor == null)
    {
        Debug.LogWarning("Assign CenterEyeAnchor in the inspector!");
        GameObject center = GameObject.Find("CenterEyeAnchor");
        if (center != null)
        {
            centerEyeAnchor = center.transform;
        }
    }
    if (lineRenderer == null)
    {
        Debug.LogWarning("Assign a line renderer in the inspector!");
        lineRenderer = gameObject.AddComponent<LineRenderer>();
        lineRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
        lineRenderer.receiveShadows = false;
        lineRenderer.widthMultiplier = 0.02f;
    }
}

Transform Pointer
{
    get
    {
        OVRInput.Controller controller = OVRInput.GetConnectedControllers();
        if ((controller & OVRInput.Controller.LTrackedRemote) != OVRInput.Controller.None)
        {
            return leftHandAnchor;
        }
        else if ((controller & OVRInput.Controller.RTrackedRemote) != OVRInput.Controller.None)
        {
            return rightHandAnchor;
        }
        // If no controllers are connected, we use ray from the view camera. 
        // This looks super ackward! Should probably fall back to a simple reticle!
        return centerEyeAnchor;
    }
}

void Update()
{
    Transform pointer = Pointer;
    if (pointer == null)
    {
        return;
    }

    Ray laserPointer = new Ray(pointer.position, pointer.forward);

    if (lineRenderer != null)
    {
        lineRenderer.SetPosition(0, laserPointer.origin);
        lineRenderer.SetPosition(1, laserPointer.origin + laserPointer.direction * maxRayDistance);
    }


    RaycastHit hit;
    if (Physics.Raycast(laserPointer, out hit, maxRayDistance, ~excludeLayers))
    {
        if (lineRenderer != null)
        {
            lineRenderer.SetPosition(1, hit.point);
        }

        if (raycastHitCallback != null)
        {
            raycastHitCallback.Invoke(laserPointer, hit);
        }
    }
}

}

Проблема в том, что когда я нажимаю на триггер, GameObject создается в этой точке на полу, но OVRPlayerController не движется к нему.

Я также прикрепил свой скрипт OVRPlayerController.cs ниже:

using System;
using UnityEngine;

/// <summary>
/// Controls the player's movement in virtual reality.
/// </summary>
[RequireComponent(typeof(CharacterController))]
public class OVRPlayerController : MonoBehaviour
{
/// <summary>
/// The rate acceleration during movement.
/// </summary>
public float Acceleration = 0.1f;

/// <summary>
/// The rate of damping on movement.
/// </summary>
public float Damping = 0.3f;

/// <summary>
/// The rate of additional damping when moving sideways or backwards.
/// </summary>
public float BackAndSideDampen = 0.5f;

/// <summary>
/// The force applied to the character when jumping.
/// </summary>
public float JumpForce = 0.3f;

/// <summary>
/// The rate of rotation when using a gamepad.
/// </summary>
public float RotationAmount = 1.5f;

/// <summary>
/// The rate of rotation when using the keyboard.
/// </summary>
public float RotationRatchet = 45.0f;

/// <summary>
/// The player will rotate in fixed steps if Snap Rotation is enabled.
/// </summary>
[Tooltip("The player will rotate in fixed steps if Snap Rotation is enabled.")]
public bool SnapRotation = true;

/// <summary>
/// How many fixed speeds to use with linear movement? 0=linear control
/// </summary>
[Tooltip("How many fixed speeds to use with linear movement? 0=linear control")]
public int FixedSpeedSteps;

/// <summary>
/// If true, reset the initial yaw of the player controller when the Hmd pose is recentered.
/// </summary>
public bool HmdResetsY = true;

/// <summary>
/// If true, tracking data from a child OVRCameraRig will update the direction of movement.
/// </summary>
public bool HmdRotatesY = true;

/// <summary>
/// Modifies the strength of gravity.
/// </summary>
public float GravityModifier = 0.379f;

/// <summary>
/// If true, each OVRPlayerController will use the player's physical height.
/// </summary>
public bool useProfileData = true;

/// <summary>
/// The CameraHeight is the actual height of the HMD and can be used to adjust the height of the character controller, which will affect the
/// ability of the character to move into areas with a low ceiling.
/// </summary>
[NonSerialized]
public float CameraHeight;

/// <summary>
/// This event is raised after the character controller is moved. This is used by the OVRAvatarLocomotion script to keep the avatar transform synchronized
/// with the OVRPlayerController.
/// </summary>
public event Action<Transform> TransformUpdated;

/// <summary>
/// This bool is set to true whenever the player controller has been teleported. It is reset after every frame. Some systems, such as 
/// CharacterCameraConstraint, test this boolean in order to disable logic that moves the character controller immediately 
/// following the teleport.
/// </summary>
[NonSerialized] // This doesn't need to be visible in the inspector.
public bool Teleported;

/// <summary>
/// This event is raised immediately after the camera transform has been updated, but before movement is updated.
/// </summary>
public event Action CameraUpdated;

/// <summary>
/// This event is raised right before the character controller is actually moved in order to provide other systems the opportunity to 
/// move the character controller in response to things other than user input, such as movement of the HMD. See CharacterCameraConstraint.cs
/// for an example of this.
/// </summary>
public event Action PreCharacterMove;

/// <summary>
/// When true, user input will be applied to linear movement. Set this to false whenever the player controller needs to ignore input for
/// linear movement.
/// </summary>
public bool EnableLinearMovement = true;

/// <summary>
/// When true, user input will be applied to rotation. Set this to false whenever the player controller needs to ignore input for rotation.
/// </summary>
public bool EnableRotation = true;

protected CharacterController Controller = null;
protected OVRCameraRig CameraRig = null;

private float MoveScale = 1.0f;
private Vector3 MoveThrottle = Vector3.zero;
private float FallSpeed = 0.0f;
private OVRPose? InitialPose;
public float InitialYRotation { get; private set; }
private float MoveScaleMultiplier = 1.0f;
private float RotationScaleMultiplier = 1.0f;
private bool SkipMouseRotation = true; // It is rare to want to use mouse movement in VR, so ignore the mouse by default.
private bool HaltUpdateMovement = false;
private bool prevHatLeft = false;
private bool prevHatRight = false;
private float SimulationRate = 60f;
private float buttonRotation = 0f;
private bool ReadyToSnapTurn; // Set to true when a snap turn has occurred, code requires one frame of centered thumbstick to enable another snap turn.

void Start()
{
    // Add eye-depth as a camera offset from the player controller
    var p = CameraRig.transform.localPosition;
    p.z = OVRManager.profile.eyeDepth;
    CameraRig.transform.localPosition = p;
}

void Awake()
{
    Controller = gameObject.GetComponent<CharacterController>();

    if (Controller == null)
        Debug.LogWarning("OVRPlayerController: No CharacterController attached.");

    // We use OVRCameraRig to set rotations to cameras,
    // and to be influenced by rotation
    OVRCameraRig[] CameraRigs = gameObject.GetComponentsInChildren<OVRCameraRig>();

    if (CameraRigs.Length == 0)
        Debug.LogWarning("OVRPlayerController: No OVRCameraRig attached.");
    else if (CameraRigs.Length > 1)
        Debug.LogWarning("OVRPlayerController: More then 1 OVRCameraRig attached.");
    else
        CameraRig = CameraRigs[0];

    InitialYRotation = transform.rotation.eulerAngles.y;
}

void OnEnable()
{
    OVRManager.display.RecenteredPose += ResetOrientation;

    if (CameraRig != null)
    {
        CameraRig.UpdatedAnchors += UpdateTransform;
    }
}

void OnDisable()
{
    OVRManager.display.RecenteredPose -= ResetOrientation;

    if (CameraRig != null)
    {
        CameraRig.UpdatedAnchors -= UpdateTransform;
    }
}

void Update()
{
    //Use keys to ratchet rotation
    if (Input.GetKeyDown(KeyCode.Q))
        buttonRotation -= RotationRatchet;

    if (Input.GetKeyDown(KeyCode.E))
        buttonRotation += RotationRatchet;
}

protected virtual void UpdateController()
{
    if (useProfileData)
    {
        if (InitialPose == null)
        {
            // Save the initial pose so it can be recovered if useProfileData
            // is turned off later.
            InitialPose = new OVRPose()
            {
                position = CameraRig.transform.localPosition,
                orientation = CameraRig.transform.localRotation
            };
        }

        var p = CameraRig.transform.localPosition;
        if (OVRManager.instance.trackingOriginType == OVRManager.TrackingOrigin.EyeLevel)
        {
            p.y = OVRManager.profile.eyeHeight - (0.5f * Controller.height) + Controller.center.y;
        }
        else if (OVRManager.instance.trackingOriginType == OVRManager.TrackingOrigin.FloorLevel)
        {
            p.y = -(0.5f * Controller.height) + Controller.center.y;
        }
        CameraRig.transform.localPosition = p;
    }
    else if (InitialPose != null)
    {
        // Return to the initial pose if useProfileData was turned off at runtime
        CameraRig.transform.localPosition = InitialPose.Value.position;
        CameraRig.transform.localRotation = InitialPose.Value.orientation;
        InitialPose = null;
    }

    CameraHeight = CameraRig.centerEyeAnchor.localPosition.y;

    if (CameraUpdated != null)
    {
        CameraUpdated();
    }

    UpdateMovement();

    Vector3 moveDirection = Vector3.zero;

    float motorDamp = (1.0f + (Damping * SimulationRate * Time.deltaTime));

    MoveThrottle.x /= motorDamp;
    MoveThrottle.y = (MoveThrottle.y > 0.0f) ? (MoveThrottle.y / motorDamp) : MoveThrottle.y;
    MoveThrottle.z /= motorDamp;

    moveDirection += MoveThrottle * SimulationRate * Time.deltaTime;

    // Gravity
    if (Controller.isGrounded && FallSpeed <= 0)
        FallSpeed = ((Physics.gravity.y * (GravityModifier * 0.002f)));
    else
        FallSpeed += ((Physics.gravity.y * (GravityModifier * 0.002f)) * SimulationRate * Time.deltaTime);

    moveDirection.y += FallSpeed * SimulationRate * Time.deltaTime;


    if (Controller.isGrounded && MoveThrottle.y <= transform.lossyScale.y * 0.001f)
    {
        // Offset correction for uneven ground
        float bumpUpOffset = Mathf.Max(Controller.stepOffset, new Vector3(moveDirection.x, 0, moveDirection.z).magnitude);
        moveDirection -= bumpUpOffset * Vector3.up;
    }

    if (PreCharacterMove != null)
    {
        PreCharacterMove();
        Teleported = false;
    }

    Vector3 predictedXZ = Vector3.Scale((Controller.transform.localPosition + moveDirection), new Vector3(1, 0, 1));

    // Move contoller
    Controller.Move(moveDirection);
    Vector3 actualXZ = Vector3.Scale(Controller.transform.localPosition, new Vector3(1, 0, 1));

    if (predictedXZ != actualXZ)
        MoveThrottle += (actualXZ - predictedXZ) / (SimulationRate * Time.deltaTime);
}





public virtual void UpdateMovement()
{
    if (HaltUpdateMovement)
        return;

    if (EnableLinearMovement)
    {
        bool moveForward = Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow);
        bool moveLeft = Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow);
        bool moveRight = Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow);
        bool moveBack = Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow);

        bool dpad_move = false;

        if (OVRInput.Get(OVRInput.Button.DpadUp))
        {
            moveForward = true;
            dpad_move = true;

        }

        if (OVRInput.Get(OVRInput.Button.DpadDown))
        {
            moveBack = true;
            dpad_move = true;
        }

        MoveScale = 1.0f;

        if ((moveForward && moveLeft) || (moveForward && moveRight) ||
            (moveBack && moveLeft) || (moveBack && moveRight))
            MoveScale = 0.70710678f;

        // No positional movement if we are in the air
        if (!Controller.isGrounded)
            MoveScale = 0.0f;

        MoveScale *= SimulationRate * Time.deltaTime;

        // Compute this for key movement
        float moveInfluence = Acceleration * 0.1f * MoveScale * MoveScaleMultiplier;

        // Run!
        if (dpad_move || Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
            moveInfluence *= 2.0f;

        Quaternion ort = transform.rotation;
        Vector3 ortEuler = ort.eulerAngles;
        ortEuler.z = ortEuler.x = 0f;
        ort = Quaternion.Euler(ortEuler);

        if (moveForward)
            MoveThrottle += ort * (transform.lossyScale.z * moveInfluence * Vector3.forward);
        if (moveBack)
            MoveThrottle += ort * (transform.lossyScale.z * moveInfluence * BackAndSideDampen * Vector3.back);
        if (moveLeft)
            MoveThrottle += ort * (transform.lossyScale.x * moveInfluence * BackAndSideDampen * Vector3.left);
        if (moveRight)
            MoveThrottle += ort * (transform.lossyScale.x * moveInfluence * BackAndSideDampen * Vector3.right);



        moveInfluence = Acceleration * 0.1f * MoveScale * MoveScaleMultiplier;

#if !UNITY_ANDROID // LeftTrigger not avail on Android game pad
        moveInfluence *= 1.0f + OVRInput.Get(OVRInput.Axis1D.PrimaryIndexTrigger);
#endif

        Vector2 primaryAxis = OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick);

        // If speed quantization is enabled, adjust the input to the number of fixed speed steps.
        if (FixedSpeedSteps > 0)
        {
            primaryAxis.y = Mathf.Round(primaryAxis.y * FixedSpeedSteps) / FixedSpeedSteps;
            primaryAxis.x = Mathf.Round(primaryAxis.x * FixedSpeedSteps) / FixedSpeedSteps;
        }

        if (primaryAxis.y > 0.0f)
            MoveThrottle += ort * (primaryAxis.y * transform.lossyScale.z * moveInfluence * Vector3.forward);

        if (primaryAxis.y < 0.0f)
            MoveThrottle += ort * (Mathf.Abs(primaryAxis.y) * transform.lossyScale.z * moveInfluence *
                                   BackAndSideDampen * Vector3.back);

        if (primaryAxis.x < 0.0f)
            MoveThrottle += ort * (Mathf.Abs(primaryAxis.x) * transform.lossyScale.x * moveInfluence *
                                   BackAndSideDampen * Vector3.left);

        if (primaryAxis.x > 0.0f)
            MoveThrottle += ort * (primaryAxis.x * transform.lossyScale.x * moveInfluence * BackAndSideDampen *
                                   Vector3.right);
    }

    if (EnableRotation)
    {
        Vector3 euler = transform.rotation.eulerAngles;
        float rotateInfluence = SimulationRate * Time.deltaTime * RotationAmount * RotationScaleMultiplier;

        bool curHatLeft = OVRInput.Get(OVRInput.Button.PrimaryShoulder);

        if (curHatLeft && !prevHatLeft)
            euler.y -= RotationRatchet;

        prevHatLeft = curHatLeft;

        bool curHatRight = OVRInput.Get(OVRInput.Button.SecondaryShoulder);

        if (curHatRight && !prevHatRight)
            euler.y += RotationRatchet;

        prevHatRight = curHatRight;

        euler.y += buttonRotation;
        buttonRotation = 0f;


#if !UNITY_ANDROID || UNITY_EDITOR
        if (!SkipMouseRotation)
            euler.y += Input.GetAxis("Mouse X") * rotateInfluence * 3.25f;
#endif

        if (SnapRotation)
        {

            if (OVRInput.Get(OVRInput.Button.SecondaryThumbstickLeft))
            {
                if (ReadyToSnapTurn)
                {
                    euler.y -= RotationRatchet;
                    ReadyToSnapTurn = false;
                }
            }
            else if (OVRInput.Get(OVRInput.Button.SecondaryThumbstickRight))
            {
                if (ReadyToSnapTurn)
                {
                    euler.y += RotationRatchet;
                    ReadyToSnapTurn = false;
                }
            }
            else
            {
                ReadyToSnapTurn = true;
            }
        }
        else
        {
            Vector2 secondaryAxis = OVRInput.Get(OVRInput.Axis2D.SecondaryThumbstick);
            euler.y += secondaryAxis.x * rotateInfluence;
        }

        transform.rotation = Quaternion.Euler(euler);
    }
}


/// <summary>
/// Invoked by OVRCameraRig's UpdatedAnchors callback. Allows the Hmd rotation to update the facing direction of the player.
/// </summary>
public void UpdateTransform(OVRCameraRig rig)
{
    Transform root = CameraRig.trackingSpace;
    Transform centerEye = CameraRig.centerEyeAnchor;

    if (HmdRotatesY && !Teleported)
    {
        Vector3 prevPos = root.position;
        Quaternion prevRot = root.rotation;

        transform.rotation = Quaternion.Euler(0.0f, centerEye.rotation.eulerAngles.y, 0.0f);

        root.position = prevPos;
        root.rotation = prevRot;
    }

    UpdateController();
    if (TransformUpdated != null)
    {
        TransformUpdated(root);
    }
}

/// <summary>
/// Jump! Must be enabled manually.
/// </summary>
public bool Jump()
{
    if (!Controller.isGrounded)
        return false;

    MoveThrottle += new Vector3(0, transform.lossyScale.y * JumpForce, 0);

    return true;
}

/// <summary>
/// Stop this instance.
/// </summary>
public void Stop()
{
    Controller.Move(Vector3.zero);
    MoveThrottle = Vector3.zero;
    FallSpeed = 0.0f;
}

/// <summary>
/// Gets the move scale multiplier.
/// </summary>
/// <param name="moveScaleMultiplier">Move scale multiplier.</param>
public void GetMoveScaleMultiplier(ref float moveScaleMultiplier)
{
    moveScaleMultiplier = MoveScaleMultiplier;
}

/// <summary>
/// Sets the move scale multiplier.
/// </summary>
/// <param name="moveScaleMultiplier">Move scale multiplier.</param>
public void SetMoveScaleMultiplier(float moveScaleMultiplier)
{
    MoveScaleMultiplier = moveScaleMultiplier;
}

/// <summary>
/// Gets the rotation scale multiplier.
/// </summary>
/// <param name="rotationScaleMultiplier">Rotation scale multiplier.</param>
public void GetRotationScaleMultiplier(ref float rotationScaleMultiplier)
{
    rotationScaleMultiplier = RotationScaleMultiplier;
}

/// <summary>
/// Sets the rotation scale multiplier.
/// </summary>
/// <param name="rotationScaleMultiplier">Rotation scale multiplier.</param>
public void SetRotationScaleMultiplier(float rotationScaleMultiplier)
{
    RotationScaleMultiplier = rotationScaleMultiplier;
}

/// <summary>
/// Gets the allow mouse rotation.
/// </summary>
/// <param name="skipMouseRotation">Allow mouse rotation.</param>
public void GetSkipMouseRotation(ref bool skipMouseRotation)
{
    skipMouseRotation = SkipMouseRotation;
}

/// <summary>
/// Sets the allow mouse rotation.
/// </summary>
/// <param name="skipMouseRotation">If set to <c>true</c> allow mouse rotation.</param>
public void SetSkipMouseRotation(bool skipMouseRotation)
{
    SkipMouseRotation = skipMouseRotation;
}

/// <summary>
/// Gets the halt update movement.
/// </summary>
/// <param name="haltUpdateMovement">Halt update movement.</param>
public void GetHaltUpdateMovement(ref bool haltUpdateMovement)
{
    haltUpdateMovement = HaltUpdateMovement;
}

/// <summary>
/// Sets the halt update movement.
/// </summary>
/// <param name="haltUpdateMovement">If set to <c>true</c> halt update movement.</param>
public void SetHaltUpdateMovement(bool haltUpdateMovement)
{
    HaltUpdateMovement = haltUpdateMovement;
}

/// <summary>
/// Resets the player look rotation when the device orientation is reset.
/// </summary>
public void ResetOrientation()
{
    if (HmdResetsY && !HmdRotatesY)
    {
        Vector3 euler = transform.rotation.eulerAngles;
        euler.y = InitialYRotation;
        transform.rotation = Quaternion.Euler(euler);
    }
}

}

...