Skip to content
Permalink
Browse files

VR tracker support (#213)

  • Loading branch information
joreg authored and xen2 committed Jan 25, 2019
1 parent 0dde714 commit 7e41209357c9abeb45cdba1ff212409e74730d49
@@ -0,0 +1,35 @@
// Copyright (c) Xenko contributors (https://xenko.com)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
namespace Xenko.VirtualReality
{
/// <summary>
/// Describes what kind of object is being tracked at a given ID
/// </summary>
public enum DeviceClass
{
/// <summary>
/// There is no device at this index
/// </summary>
Invalid,
/// <summary>
/// The device at this index is an HMD
/// </summary>
HMD,
/// <summary>
/// The device is a controller
/// </summary>
Controller,
/// <summary>
/// The device is a tracker
/// </summary>
GenericTracker,
/// <summary>
/// The device is a camera, Lighthouse base station, or other device that supplies tracking ground truth.
/// </summary>
TrackingReference,
/// <summary>
/// Accessories that aren't necessarily tracked themselves, but may redirect video output from other tracked devices
/// </summary>
DisplayRedirect
}
}
@@ -43,6 +43,8 @@ public class DummyDevice : VRDevice

public override TouchController RightHand => null;

public override TrackedItem[] TrackedItems => new TrackedItem[0];

public override bool CanInitialize => true;

/// <summary>
@@ -136,6 +136,8 @@ public override void Draw(GameTime gameTime)

public override TouchController RightHand => null;

public override TrackedItem[] TrackedItems => new TrackedItem[0];

public override bool CanInitialize => Fove.Startup() && Fove.IsHardwareReady();
}
}
@@ -137,6 +137,8 @@ public override DeviceState State

public override TouchController RightHand => rightHandController;

public override TrackedItem[] TrackedItems => new TrackedItem[0];

public override bool CanInitialize
{
get
@@ -3,6 +3,7 @@
#if XENKO_GRAPHICS_API_DIRECT3D11

using System;
using System.Text;
using SharpDX.Direct3D11;
using Valve.VR;
using Xenko.Core;
@@ -150,6 +151,46 @@ public void Update()
}
}

public class TrackedDevice
{
public TrackedDevice(int trackerIndex)
{
TrackerIndex = trackerIndex;
}

const int StringBuilderSize = 64;
StringBuilder serialNumberStringBuilder = new StringBuilder(StringBuilderSize);
internal string SerialNumber
{
get
{
var error = ETrackedPropertyError.TrackedProp_Success;
serialNumberStringBuilder.Clear();
Valve.VR.OpenVR.System.GetStringTrackedDeviceProperty((uint)TrackerIndex, ETrackedDeviceProperty.Prop_SerialNumber_String, serialNumberStringBuilder, StringBuilderSize, ref error);
if (error == ETrackedPropertyError.TrackedProp_Success)
return serialNumberStringBuilder.ToString();
else
return "";
}
}

internal float BatteryPercentage
{
get
{
var error = ETrackedPropertyError.TrackedProp_Success;
var value = Valve.VR.OpenVR.System.GetFloatTrackedDeviceProperty((uint)TrackerIndex, ETrackedDeviceProperty.Prop_DeviceBatteryPercentage_Float, ref error);
if (error == ETrackedPropertyError.TrackedProp_Success)
return value;
else
return 0;
}
}

internal int TrackerIndex;
internal ETrackedDeviceClass DeviceClass => Valve.VR.OpenVR.System.GetTrackedDeviceClass((uint)TrackerIndex);
}

private static readonly TrackedDevicePose_t[] DevicePoses = new TrackedDevicePose_t[Valve.VR.OpenVR.k_unMaxTrackedDeviceCount];
private static readonly TrackedDevicePose_t[] GamePoses = new TrackedDevicePose_t[Valve.VR.OpenVR.k_unMaxTrackedDeviceCount];

@@ -226,6 +267,11 @@ public static void Recenter()
Valve.VR.OpenVR.System.ResetSeatedZeroPose();
}

public static void SetTrackingSpace(ETrackingUniverseOrigin space)
{
Valve.VR.OpenVR.Compositor.SetTrackingSpace(space);
}

public static DeviceState GetControllerPose(int controllerIndex, out Matrix pose, out Vector3 velocity, out Vector3 angVelocity)
{
return GetControllerPoseUnsafe(controllerIndex, out pose, out velocity, out angVelocity);
@@ -268,6 +314,35 @@ private static unsafe DeviceState GetControllerPoseUnsafe(int controllerIndex, o
return DeviceState.Invalid;
}

public static DeviceState GetTrackerPose(int trackerIndex, out Matrix pose, out Vector3 velocity, out Vector3 angVelocity)
{
return GetTrackerPoseUnsafe(trackerIndex, out pose, out velocity, out angVelocity);
}

private static unsafe DeviceState GetTrackerPoseUnsafe(int trackerIndex, out Matrix pose, out Vector3 velocity, out Vector3 angVelocity)
{
pose = Matrix.Identity;
velocity = Vector3.Zero;
angVelocity = Vector3.Zero;
var index = trackerIndex;

Utilities.CopyMemory((IntPtr)Interop.Fixed(ref pose), (IntPtr)Interop.Fixed(ref DevicePoses[index].mDeviceToAbsoluteTracking), Utilities.SizeOf<HmdMatrix34_t>());
Utilities.CopyMemory((IntPtr)Interop.Fixed(ref velocity), (IntPtr)Interop.Fixed(ref DevicePoses[index].vVelocity), Utilities.SizeOf<HmdVector3_t>());
Utilities.CopyMemory((IntPtr)Interop.Fixed(ref angVelocity), (IntPtr)Interop.Fixed(ref DevicePoses[index].vAngularVelocity), Utilities.SizeOf<HmdVector3_t>());

var state = DeviceState.Invalid;
if (DevicePoses[index].bDeviceIsConnected && DevicePoses[index].bPoseIsValid)
{
state = DeviceState.Valid;
}
else if (DevicePoses[index].bDeviceIsConnected && !DevicePoses[index].bPoseIsValid && DevicePoses[index].eTrackingResult == ETrackingResult.Running_OutOfRange)
{
state = DeviceState.OutOfRange;
}

return state;
}

public static DeviceState GetHeadPose(out Matrix pose, out Vector3 linearVelocity, out Vector3 angularVelocity)
{
return GetHeadPoseUnsafe(out pose, out linearVelocity, out angularVelocity);
@@ -18,6 +18,7 @@ internal class OpenVRHmd : VRDevice
private DeviceState state;
private OpenVRTouchController leftHandController;
private OpenVRTouchController rightHandController;
private OpenVRTrackedDevice[] trackedDevices;
private bool needsMirror;
private Matrix currentHead;
private Vector3 currentHeadPos;
@@ -55,6 +56,10 @@ public override void Enable(GraphicsDevice device, GraphicsDeviceManager graphic

leftHandController = new OpenVRTouchController(TouchControllerHand.Left);
rightHandController = new OpenVRTouchController(TouchControllerHand.Right);

trackedDevices = new OpenVRTrackedDevice[Valve.VR.OpenVR.k_unMaxTrackedDeviceCount];
for (int i=0; i<trackedDevices.Length; i++)
trackedDevices[i] = new OpenVRTrackedDevice(i);
}

public override VROverlay CreateOverlay(int width, int height, int mipLevels, int sampleCount)
@@ -75,6 +80,8 @@ public override void Update(GameTime gameTime)
{
LeftHand.Update(gameTime);
RightHand.Update(gameTime);
foreach (var tracker in trackedDevices)
tracker.Update(gameTime);
}

public override void ReadEyeParameters(Eyes eye, float near, float far, ref Vector3 cameraPosition, ref Matrix cameraRotation, bool ignoreHeadRotation, bool ignoreHeadPosition, out Matrix view, out Matrix projection)
@@ -122,6 +129,11 @@ public override void Recenter()
OpenVR.Recenter();
}

public override void SetTrackingSpace(TrackingSpace space)
{
OpenVR.SetTrackingSpace((Valve.VR.ETrackingUniverseOrigin)space);
}

public override DeviceState State => state;

public override Vector3 HeadPosition => currentHeadPos;
@@ -136,6 +148,8 @@ public override void Recenter()

public override TouchController RightHand => rightHandController;

public override TrackedItem[] TrackedItems => trackedDevices;

public override Texture MirrorTexture { get; protected set; }

public override float RenderFrameScaling { get; set; } = 1.4f;
@@ -0,0 +1,63 @@
// Copyright (c) Xenko contributors (https://xenko.com)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
#if XENKO_GRAPHICS_API_DIRECT3D11

using System;
using Xenko.Core.Mathematics;
using Xenko.Games;

namespace Xenko.VirtualReality
{
internal class OpenVRTrackedDevice : TrackedItem
{
private readonly int id;
private OpenVR.TrackedDevice trackedDevice;
private DeviceState internalState;
private Vector3 currentPos;
private Vector3 currentLinearVelocity;
private Vector3 currentAngularVelocity;
private Quaternion currentRot;

internal OpenVRTrackedDevice(int index)
{
trackedDevice = new OpenVR.TrackedDevice(index);
}

public override void Update(GameTime gameTime)
{
if (trackedDevice != null)
{
Matrix mat;
Vector3 vel, angVel;
internalState = OpenVR.GetTrackerPose(trackedDevice.TrackerIndex, out mat, out vel, out angVel);
if (internalState != DeviceState.Invalid)
{
Vector3 scale;
mat.Decompose(out scale, out currentRot, out currentPos);
currentLinearVelocity = vel;
currentAngularVelocity = new Vector3(MathUtil.DegreesToRadians(angVel.X), MathUtil.DegreesToRadians(angVel.Y), MathUtil.DegreesToRadians(angVel.Z));
}
}

base.Update(gameTime);
}

public override Vector3 Position => currentPos;

public override Quaternion Rotation => currentRot;

public override Vector3 LinearVelocity => currentLinearVelocity;

public override Vector3 AngularVelocity => currentAngularVelocity;

public override DeviceState State => internalState;

public override DeviceClass Class => (DeviceClass)trackedDevice.DeviceClass;

public override string SerialNumber => trackedDevice.SerialNumber;

public override float BatteryPercentage => trackedDevice.BatteryPercentage;
}
}

#endif
@@ -0,0 +1,35 @@
// Copyright (c) Xenko contributors (https://xenko.com)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using System;
using Xenko.Core.Mathematics;
using Xenko.Games;

namespace Xenko.VirtualReality
{
public abstract class TrackedItem : IDisposable
{
public abstract Vector3 Position { get; }

public abstract Quaternion Rotation { get; }

public abstract Vector3 LinearVelocity { get; }

public abstract Vector3 AngularVelocity { get; }

public abstract DeviceState State { get; }

public abstract DeviceClass Class { get; }

public abstract string SerialNumber { get; }

public abstract float BatteryPercentage { get; }

public virtual void Update(GameTime time)
{
}

public virtual void Dispose()
{
}
}
}
@@ -0,0 +1,23 @@
// Copyright (c) Xenko contributors (https://xenko.com)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
namespace Xenko.VirtualReality
{
/// <summary>
/// Identifies which style of tracking origin the application wants to use for the poses it is requesting
/// </summary>
public enum TrackingSpace
{
/// <summary>
/// Poses are provided relative to the seated zero pose
/// </summary>
Seated,
/// <summary>
/// Poses are provided relative to the safe bounds configured by the user
/// </summary>
Standing,
/// <summary>
/// Poses are provided in the coordinate system defined by the driver. It has Y up and is unified for devices of the same driver. You usually don't want this one.
/// </summary>
RawAndUncalibrated
}
}
@@ -38,6 +38,8 @@ protected VRDevice()

public abstract TouchController RightHand { get; }

public abstract TrackedItem[] TrackedItems { get; }

public VRApi VRApi { get; protected set; }

/// <summary>
@@ -65,6 +67,10 @@ public virtual void Recenter()
{
}

public virtual void SetTrackingSpace(TrackingSpace space)
{
}

public abstract void ReadEyeParameters(Eyes eye, float near, float far, ref Vector3 cameraPosition, ref Matrix cameraRotation, bool ignoreHeadRotation, bool ignoreHeadPosition, out Matrix view, out Matrix projection);

public abstract void Commit(CommandList commandList, Texture renderFrame);

0 comments on commit 7e41209

Please sign in to comment.
You can’t perform that action at this time.