diff --git a/sources/engine/Xenko.Graphics/Texture.cs b/sources/engine/Xenko.Graphics/Texture.cs
index 0b8fbeaa15..49e65a83aa 100644
--- a/sources/engine/Xenko.Graphics/Texture.cs
+++ b/sources/engine/Xenko.Graphics/Texture.cs
@@ -382,6 +382,9 @@ public bool IsMultisample
}
}
+
+
+
///
/// Gets a boolean indicating whether this is a using a block compress format (BC1, BC2, BC3, BC4, BC5, BC6H, BC7).
///
diff --git a/sources/engine/Xenko.VirtualReality/DeviceClass.cs b/sources/engine/Xenko.VirtualReality/DeviceClass.cs
new file mode 100644
index 0000000000..6b83f12d1d
--- /dev/null
+++ b/sources/engine/Xenko.VirtualReality/DeviceClass.cs
@@ -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
+{
+ ///
+ /// Describes what kind of object is being tracked at a given ID
+ ///
+ public enum DeviceClass
+ {
+ ///
+ /// There is no device at this index
+ ///
+ Invalid,
+ ///
+ /// The device at this index is an HMD
+ ///
+ HMD,
+ ///
+ /// The device is a controller
+ ///
+ Controller,
+ ///
+ /// The device is a tracker
+ ///
+ GenericTracker,
+ ///
+ /// The device is a camera, Lighthouse base station, or other device that supplies tracking ground truth.
+ ///
+ TrackingReference,
+ ///
+ /// Accessories that aren't necessarily tracked themselves, but may redirect video output from other tracked devices
+ ///
+ DisplayRedirect
+ }
+}
diff --git a/sources/engine/Xenko.VirtualReality/DeviceEnums.cs b/sources/engine/Xenko.VirtualReality/DeviceEnums.cs
new file mode 100644
index 0000000000..696a3c2eec
--- /dev/null
+++ b/sources/engine/Xenko.VirtualReality/DeviceEnums.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
+// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
+namespace Xenko.VirtualReality
+{
+ public enum DeviceState
+ {
+ Invalid,
+ OutOfRange,
+ Valid,
+ }
+
+ public enum DeviceClass
+ {
+ Invalid, //There is no device at this index
+ HMD, //The device at this index is an HMD
+ Controller, //The device is a controller
+ GenericTracker, //The device is a tracker
+ TrackingReference, //The device is a camera, Lighthouse base station, or other device that supplies tracking ground truth.
+ DisplayRedirect //Accessories that aren't necessarily tracked themselves, but may redirect video output from other tracked devices
+ }
+
+ public enum TrackingSpace
+ {
+ Seated,
+ Standing,
+ RawAndUncalibrated
+ }
+}
diff --git a/sources/engine/Xenko.VirtualReality/DeviceState.cs b/sources/engine/Xenko.VirtualReality/DeviceState.cs
deleted file mode 100644
index 020abd8e52..0000000000
--- a/sources/engine/Xenko.VirtualReality/DeviceState.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
-// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
-namespace Xenko.VirtualReality
-{
- public enum DeviceState
- {
- Invalid,
- OutOfRange,
- Valid,
- }
-}
diff --git a/sources/engine/Xenko.VirtualReality/DummyDevice.cs b/sources/engine/Xenko.VirtualReality/DummyDevice.cs
index 8cd3096524..d006d2f706 100644
--- a/sources/engine/Xenko.VirtualReality/DummyDevice.cs
+++ b/sources/engine/Xenko.VirtualReality/DummyDevice.cs
@@ -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;
///
diff --git a/sources/engine/Xenko.VirtualReality/Fove/FoveHmd.cs b/sources/engine/Xenko.VirtualReality/Fove/FoveHmd.cs
index 207039e4b1..60589ffeda 100644
--- a/sources/engine/Xenko.VirtualReality/Fove/FoveHmd.cs
+++ b/sources/engine/Xenko.VirtualReality/Fove/FoveHmd.cs
@@ -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();
}
}
diff --git a/sources/engine/Xenko.VirtualReality/OculusOVR/OculusOvrHmd.cs b/sources/engine/Xenko.VirtualReality/OculusOVR/OculusOvrHmd.cs
index 185aa0b985..dc3724b703 100644
--- a/sources/engine/Xenko.VirtualReality/OculusOVR/OculusOvrHmd.cs
+++ b/sources/engine/Xenko.VirtualReality/OculusOVR/OculusOvrHmd.cs
@@ -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
diff --git a/sources/engine/Xenko.VirtualReality/OpenVR/OpenVR.cs b/sources/engine/Xenko.VirtualReality/OpenVR/OpenVR.cs
index 7705adfbc5..e94477d656 100644
--- a/sources/engine/Xenko.VirtualReality/OpenVR/OpenVR.cs
+++ b/sources/engine/Xenko.VirtualReality/OpenVR/OpenVR.cs
@@ -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());
+ Utilities.CopyMemory((IntPtr)Interop.Fixed(ref velocity), (IntPtr)Interop.Fixed(ref DevicePoses[index].vVelocity), Utilities.SizeOf());
+ Utilities.CopyMemory((IntPtr)Interop.Fixed(ref angVelocity), (IntPtr)Interop.Fixed(ref DevicePoses[index].vAngularVelocity), Utilities.SizeOf());
+
+ 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);
diff --git a/sources/engine/Xenko.VirtualReality/OpenVR/OpenVrHmd.cs b/sources/engine/Xenko.VirtualReality/OpenVR/OpenVrHmd.cs
index ded6517c4d..f4af4949c6 100644
--- a/sources/engine/Xenko.VirtualReality/OpenVR/OpenVrHmd.cs
+++ b/sources/engine/Xenko.VirtualReality/OpenVR/OpenVrHmd.cs
@@ -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 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;
diff --git a/sources/engine/Xenko.VirtualReality/OpenVR/OpenVrTrackedDevice.cs b/sources/engine/Xenko.VirtualReality/OpenVR/OpenVrTrackedDevice.cs
new file mode 100644
index 0000000000..972c4ef18f
--- /dev/null
+++ b/sources/engine/Xenko.VirtualReality/OpenVR/OpenVrTrackedDevice.cs
@@ -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
diff --git a/sources/engine/Xenko.VirtualReality/TrackedItem.cs b/sources/engine/Xenko.VirtualReality/TrackedItem.cs
new file mode 100644
index 0000000000..ffa32f266c
--- /dev/null
+++ b/sources/engine/Xenko.VirtualReality/TrackedItem.cs
@@ -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()
+ {
+ }
+ }
+}
diff --git a/sources/engine/Xenko.VirtualReality/TrackingSpace.cs b/sources/engine/Xenko.VirtualReality/TrackingSpace.cs
new file mode 100644
index 0000000000..30942b7981
--- /dev/null
+++ b/sources/engine/Xenko.VirtualReality/TrackingSpace.cs
@@ -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
+{
+ ///
+ /// Identifies which style of tracking origin the application wants to use for the poses it is requesting
+ ///
+ public enum TrackingSpace
+ {
+ ///
+ /// Poses are provided relative to the seated zero pose
+ ///
+ Seated,
+ ///
+ /// Poses are provided relative to the safe bounds configured by the user
+ ///
+ Standing,
+ ///
+ /// 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.
+ ///
+ RawAndUncalibrated
+ }
+}
diff --git a/sources/engine/Xenko.VirtualReality/VRDevice.cs b/sources/engine/Xenko.VirtualReality/VRDevice.cs
index 8d4b2e4ac2..28bcae58b2 100644
--- a/sources/engine/Xenko.VirtualReality/VRDevice.cs
+++ b/sources/engine/Xenko.VirtualReality/VRDevice.cs
@@ -38,6 +38,8 @@ protected VRDevice()
public abstract TouchController RightHand { get; }
+ public abstract TrackedItem[] TrackedItems { get; }
+
public VRApi VRApi { get; protected set; }
///
@@ -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);
diff --git a/sources/shaders/Xenko.Core.Shaders/Ast/TypeBase.cs b/sources/shaders/Xenko.Core.Shaders/Ast/TypeBase.cs
index 2c87308d5d..4ae2f9e3f7 100644
--- a/sources/shaders/Xenko.Core.Shaders/Ast/TypeBase.cs
+++ b/sources/shaders/Xenko.Core.Shaders/Ast/TypeBase.cs
@@ -215,7 +215,7 @@ public override bool Equals(object obj)
///
public override int GetHashCode()
{
- return Name.GetHashCode();
+ return Name?.GetHashCode() ?? 0;
}
///
@@ -226,7 +226,7 @@ public override int GetHashCode()
///
public override string ToString()
{
- return Name.ToString();
+ return Name?.ToString();
}
#endregion