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