clean project

This commit is contained in:
Helar Jaadla
2022-03-07 17:52:41 +02:00
parent a174b45bd2
commit cbeb10ec35
5100 changed files with 837159 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 96dc2ac9879a2ae409623a72b39f8340
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,119 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using UnityEngine;
namespace Oculus.Interaction.Input
{
public class Controller :
DataModifier<ControllerDataAsset, ControllerDataSourceConfig>,
IController
{
public Handedness Handedness => Config.Handedness;
public bool IsConnected
{
get
{
var currentData = GetData();
return currentData.IsDataValid && currentData.IsConnected;
}
}
public bool IsPoseValid
{
get
{
var currentData = GetData();
return currentData.IsDataValid &&
currentData.RootPoseOrigin != PoseOrigin.None;
}
}
public bool IsPointerPoseValid
{
get
{
var currentData = GetData();
return currentData.IsDataValid &&
currentData.PointerPoseOrigin != PoseOrigin.None;
}
}
public event Action ControllerUpdated = delegate { };
public bool IsButtonUsageAnyActive(ControllerButtonUsage buttonUsage)
{
var currentData = GetData();
return
currentData.IsDataValid &&
(buttonUsage & currentData.ButtonUsageMask) != 0;
}
public bool IsButtonUsageAllActive(ControllerButtonUsage buttonUsage)
{
var currentData = GetData();
return currentData.IsDataValid &&
(buttonUsage & currentData.ButtonUsageMask) == buttonUsage;
}
/// <summary>
/// Retrieves the current controller pose, in world space.
/// </summary>
/// <param name="pose">Set to current pose if `IsPoseValid`; Pose.identity otherwise</param>
/// <returns>Value of `IsPoseValid`</returns>
public bool TryGetPose(out Pose pose)
{
if (!IsPoseValid)
{
pose = Pose.identity;
return false;
}
pose = Config.TrackingToWorldTransformer.ToWorldPose(GetData().RootPose);
return true;
}
/// <summary>
/// Retrieves the current controller pointer pose, in world space.
/// </summary>
/// <param name="pose">Set to current pose if `IsPoseValid`; Pose.identity otherwise</param>
/// <returns>Value of `IsPoseValid`</returns>
public bool TryGetPointerPose(out Pose pose)
{
if (!IsPointerPoseValid)
{
pose = Pose.identity;
return false;
}
pose = Config.TrackingToWorldTransformer.ToWorldPose(GetData().PointerPose);
return true;
}
public override void MarkInputDataRequiresUpdate()
{
base.MarkInputDataRequiresUpdate();
if (Started)
{
ControllerUpdated();
}
}
protected override void Apply(ControllerDataAsset data)
{
// Default implementation does nothing, to allow instantiation of this modifier directly
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4ae60cfa43388e449a7518f36418f81c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,47 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using UnityEngine;
namespace Oculus.Interaction.Input
{
[Serializable]
public class ControllerDataAsset : ICopyFrom<ControllerDataAsset>
{
public bool IsDataValid;
public bool IsConnected;
public bool IsTracked;
public ControllerButtonUsage ButtonUsageMask;
public Pose RootPose;
public PoseOrigin RootPoseOrigin;
public Pose PointerPose;
public PoseOrigin PointerPoseOrigin;
public void CopyFrom(ControllerDataAsset source)
{
IsDataValid = source.IsDataValid;
IsConnected = source.IsConnected;
IsTracked = source.IsTracked;
CopyPosesAndStateFrom(source);
}
public void CopyPosesAndStateFrom(ControllerDataAsset source)
{
ButtonUsageMask = source.ButtonUsageMask;
RootPose = source.RootPose;
RootPoseOrigin = source.RootPoseOrigin;
PointerPose = source.PointerPose;
PointerPoseOrigin = source.PointerPoseOrigin;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fe4ca944e80140841985b0f273793641
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,24 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
namespace Oculus.Interaction.Input
{
/// <summary>
/// A set of constants that are passed to each child of a Controller modifier tree from the root DataSource.
/// </summary>
public class ControllerDataSourceConfig
{
public Handedness Handedness { get; set; }
public ITrackingToWorldTransformer TrackingToWorldTransformer { get; set; }
public IDataSource<HmdDataAsset, HmdDataSourceConfig> HmdData { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a1675de914d203a4a910d701ade05ce3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,33 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
namespace Oculus.Interaction.Input
{
// Enum containing all values of Unity.XR.CommonUsage.
[Flags]
public enum ControllerButtonUsage
{
None = 0,
PrimaryButton = 1 << 0,
PrimaryTouch = 1 << 1,
SecondaryButton = 1 << 2,
SecondaryTouch = 1 << 3,
GripButton = 1 << 4,
TriggerButton = 1 << 5,
MenuButton = 1 << 6,
Primary2DAxisClick = 1 << 7,
Primary2DAxisTouch = 1 << 8,
Thumbrest = 1 << 9,
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8489868b0a7582e43890f869877224e8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,86 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using UnityEngine;
using UnityEngine.Assertions;
namespace Oculus.Interaction.Input
{
/// <summary>
/// ControllerRef is a utility component that delegates all of its IController implementation
/// to the provided Controller object.
/// </summary>
public class ControllerRef : MonoBehaviour, IController, IActiveState
{
[SerializeField, Interface(typeof(IController))]
private MonoBehaviour _controller;
private IController Controller;
protected virtual void Awake()
{
Controller = _controller as IController;
}
protected virtual void Start()
{
Assert.IsNotNull(Controller);
}
public Handedness Handedness => Controller.Handedness;
public bool IsConnected => Controller.IsConnected;
public bool IsPoseValid => Controller.IsPoseValid;
public event Action ControllerUpdated
{
add => Controller.ControllerUpdated += value;
remove => Controller.ControllerUpdated -= value;
}
public bool Active => IsConnected;
public bool TryGetPose(out Pose pose)
{
return Controller.TryGetPose(out pose);
}
public bool TryGetPointerPose(out Pose pose)
{
return Controller.TryGetPointerPose(out pose);
}
public bool IsButtonUsageAnyActive(ControllerButtonUsage buttonUsage)
{
return Controller.IsButtonUsageAnyActive(buttonUsage);
}
public bool IsButtonUsageAllActive(ControllerButtonUsage buttonUsage)
{
return Controller.IsButtonUsageAllActive(buttonUsage);
}
#region Inject
public void InjectAllControllerRef(IController controller)
{
InjectController(controller);
}
public void InjectController(IController controller)
{
_controller = controller as MonoBehaviour;
Controller = controller;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3673df66324d8f34d9433049c54de631
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,29 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using UnityEngine;
namespace Oculus.Interaction.Input
{
public interface IController
{
Handedness Handedness { get; }
bool IsConnected { get; }
bool IsPoseValid { get; }
bool TryGetPose(out Pose pose);
bool TryGetPointerPose(out Pose pose);
bool IsButtonUsageAnyActive(ControllerButtonUsage buttonUsage);
bool IsButtonUsageAllActive(ControllerButtonUsage buttonUsage);
event Action ControllerUpdated;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 77db11dffd48abd4cb96a6076a2a2545
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,19 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
namespace Oculus.Interaction.Input
{
public interface IControllerDataModifier
{
void Apply(ControllerDataAsset controllerDataAsset, Handedness handedness);
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b392af6b92984f2887f80975b07141ba
timeCreated: 1629344165

View File

@@ -0,0 +1,118 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using UnityEngine;
using UnityEngine.Assertions;
namespace Oculus.Interaction.Input
{
public abstract class
DataModifier<TData, TConfig> : DataSource<TData, TConfig>
where TData : class, ICopyFrom<TData>, new()
{
[Header("Data Modifier")]
[SerializeField, Interface(nameof(_modifyDataFromSource))]
protected MonoBehaviour _iModifyDataFromSourceMono;
private IDataSource<TData, TConfig> _modifyDataFromSource;
[SerializeField]
[Tooltip("If this is false, then this modifier will simply pass through " +
"data without performing any modification. This saves on memory " +
"and computation")]
private bool _applyModifier = true;
private static TData InvalidAsset { get; } = new TData();
private TData _thisDataAsset;
private TData _currentDataAsset = InvalidAsset;
private TConfig _configCache;
protected override TData DataAsset => _currentDataAsset;
public virtual IDataSource<TData, TConfig> ModifyDataFromSource => _modifyDataFromSource == null
? (_modifyDataFromSource = _iModifyDataFromSourceMono as IDataSource<TData, TConfig>)
: _modifyDataFromSource;
public override int CurrentDataVersion
{
get
{
return _applyModifier
? base.CurrentDataVersion
: ModifyDataFromSource.CurrentDataVersion;
}
}
public void ResetSources(IDataSource<TData, TConfig> modifyDataFromSource, IDataSource updateAfter, UpdateModeFlags updateMode)
{
ResetUpdateAfter(updateAfter, updateMode);
_modifyDataFromSource = modifyDataFromSource;
_currentDataAsset = InvalidAsset;
_configCache = default;
}
protected override void UpdateData()
{
if (_applyModifier)
{
if (_thisDataAsset == null)
{
_thisDataAsset = new TData();
}
_thisDataAsset.CopyFrom(ModifyDataFromSource.GetData());
_currentDataAsset = _thisDataAsset;
Apply(_currentDataAsset);
}
else
{
_currentDataAsset = ModifyDataFromSource.GetData();
}
}
protected abstract void Apply(TData data);
protected override void Start()
{
base.Start();
Assert.IsNotNull(ModifyDataFromSource);
}
public override TConfig Config
{
get
{
return _configCache != null
? _configCache
: (_configCache = ModifyDataFromSource.Config);
}
}
#region Inject
public void InjectAllDataModifier(UpdateModeFlags updateMode, IDataSource updateAfter, IDataSource<TData, TConfig> modifyDataFromSource, bool applyModifier)
{
base.InjectAllDataSource(updateMode, updateAfter);
InjectModifyDataFromSource(modifyDataFromSource);
InjectApplyModifier(applyModifier);
}
public void InjectModifyDataFromSource(IDataSource<TData, TConfig> modifyDataFromSource)
{
_modifyDataFromSource = modifyDataFromSource;
}
public void InjectApplyModifier(bool applyModifier)
{
_applyModifier = applyModifier;
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 12efd6a9760b4bcaafd9cefbe1db0bad
timeCreated: 1630526111

View File

@@ -0,0 +1,202 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Serialization;
namespace Oculus.Interaction.Input
{
public interface IDataSource
{
int CurrentDataVersion { get; }
void MarkInputDataRequiresUpdate();
event Action InputDataAvailable;
}
public interface IDataSource<TData, TConfig> : IDataSource
{
TData GetData();
TConfig Config { get; }
}
public abstract class DataSource<TData, TConfig> : MonoBehaviour, IDataSource<TData, TConfig>
where TData : class, ICopyFrom<TData>, new()
{
public bool Started { get; private set; }
protected bool _started = false;
private bool _requiresUpdate = true;
[Flags]
public enum UpdateModeFlags
{
Manual = 0,
UnityUpdate = 1 << 0,
UnityFixedUpdate = 1 << 1,
UnityLateUpdate = 1 << 2,
AfterPreviousStep = 1 << 3
}
[Header("Update")]
[SerializeField]
private UpdateModeFlags _updateMode;
public UpdateModeFlags UpdateMode => _updateMode;
[SerializeField, Interface(typeof(IDataSource)), Optional]
private MonoBehaviour _updateAfter;
private IDataSource UpdateAfter;
private int _currentDataVersion;
protected bool UpdateModeAfterPrevious => (_updateMode & UpdateModeFlags.AfterPreviousStep) != 0;
// Notifies that new data is available for query via GetData() method.
// Do not use this event if you are reading data from a `Oculus.Interaction.Input.Hand` object,
// instead, use the `Updated` event on that class.
public event Action InputDataAvailable = delegate { };
public virtual int CurrentDataVersion => _currentDataVersion;
#region Unity Lifecycle
protected virtual void Start()
{
this.BeginStart(ref _started);
if (_updateAfter != null)
{
UpdateAfter = _updateAfter as IDataSource;
Assert.IsNotNull(UpdateAfter);
}
Started = true;
this.EndStart(ref _started);
}
protected virtual void OnEnable()
{
if (_started)
{
if (Started && UpdateModeAfterPrevious && UpdateAfter != null)
{
UpdateAfter.InputDataAvailable += MarkInputDataRequiresUpdate;
}
}
}
protected virtual void OnDisable()
{
if (_started)
{
if (UpdateAfter != null)
{
UpdateAfter.InputDataAvailable -= MarkInputDataRequiresUpdate;
}
}
}
protected virtual void Update()
{
if ((_updateMode & UpdateModeFlags.UnityUpdate) != 0)
{
MarkInputDataRequiresUpdate();
}
}
protected virtual void FixedUpdate()
{
if ((_updateMode & UpdateModeFlags.UnityFixedUpdate) != 0)
{
MarkInputDataRequiresUpdate();
}
}
protected virtual void LateUpdate()
{
if ((_updateMode & UpdateModeFlags.UnityLateUpdate) != 0)
{
MarkInputDataRequiresUpdate();
}
}
#endregion
protected void ResetUpdateAfter(IDataSource updateAfter, UpdateModeFlags updateMode)
{
bool wasActive = isActiveAndEnabled;
if (isActiveAndEnabled) { OnDisable(); }
_updateMode = updateMode;
UpdateAfter = updateAfter;
_requiresUpdate = true;
_currentDataVersion += 1;
if (wasActive) { OnEnable(); }
}
public TData GetData()
{
if (RequiresUpdate())
{
UpdateData();
_requiresUpdate = false;
}
return DataAsset;
}
protected bool RequiresUpdate()
{
return Started && _requiresUpdate && isActiveAndEnabled;
}
/// <summary>
/// Marks the DataAsset stored as outdated, which means it will be
/// re-processed JIT during the next call to GetData.
/// </summary>
public virtual void MarkInputDataRequiresUpdate()
{
_requiresUpdate = true;
_currentDataVersion += 1;
InputDataAvailable();
}
protected abstract void UpdateData();
/// <summary>
/// Returns the current DataAsset, without performing any updates.
/// </summary>
/// <returns>
/// Null if no call to GetData has been made since this data source was initialized.
/// </returns>
protected abstract TData DataAsset { get; }
public abstract TConfig Config { get; }
#region Inject
public void InjectAllDataSource(UpdateModeFlags updateMode, IDataSource updateAfter)
{
InjectUpdateMode(updateMode);
InjectUpdateAfter(updateAfter);
}
public void InjectUpdateMode(UpdateModeFlags updateMode)
{
_updateMode = updateMode;
}
public void InjectUpdateAfter(IDataSource updateAfter)
{
_updateAfter = updateAfter as MonoBehaviour;
UpdateAfter = updateAfter;
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5e3eaa7f7e074674929b88928616f063
timeCreated: 1630527498

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b30e59c0241c28d46b6f42afca0d444d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,53 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using UnityEngine;
namespace Oculus.Interaction.Input
{
public class Hmd : DataModifier<HmdDataAsset, HmdDataSourceConfig>, IHmd
{
public ITrackingToWorldTransformer TrackingToWorldTransformer =>
Config.TrackingToWorldTransformer;
public event Action HmdUpdated = delegate { };
protected override void Apply(HmdDataAsset data)
{
// Default implementation does nothing, to allow instantiation of this modifier directly
}
public override void MarkInputDataRequiresUpdate()
{
base.MarkInputDataRequiresUpdate();
if (Started)
{
HmdUpdated();
}
}
public bool GetRootPose(out Pose pose)
{
var currentData = GetData();
if (!currentData.IsTracked)
{
pose = Pose.identity;
return false;
}
pose = TrackingToWorldTransformer.ToWorldPose(currentData.Root);
return true;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2606bf2f0c914a7aba4390f29ba2eb6e
timeCreated: 1629334585

View File

@@ -0,0 +1,32 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using UnityEngine;
namespace Oculus.Interaction.Input
{
[Serializable]
public class HmdDataAsset : ICopyFrom<HmdDataAsset>
{
public Pose Root;
public bool IsTracked;
public int FrameId;
public void CopyFrom(HmdDataAsset source)
{
Root = source.Root;
IsTracked = source.IsTracked;
FrameId = source.FrameId;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 332eb9fb3feb493aa2632f2739bf3d41
timeCreated: 1629321466

View File

@@ -0,0 +1,22 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
namespace Oculus.Interaction.Input
{
/// <summary>
/// A set of constants that are passed to each child of a Hand modifier tree from the root DataSource.
/// </summary>
public class HmdDataSourceConfig
{
public ITrackingToWorldTransformer TrackingToWorldTransformer { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5e6945eb8bd2e9941a48a55b14cda4d5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,62 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using UnityEngine;
using UnityEngine.Assertions;
namespace Oculus.Interaction.Input
{
/// <summary>
/// A set of constants that are passed to each child of a Hand modifier tree from the root DataSource.
/// </summary>
public class HmdRef : MonoBehaviour, IHmd
{
[SerializeField, Interface(typeof(Hmd))]
private MonoBehaviour _hmd;
private IHmd Hmd;
public event Action HmdUpdated
{
add => Hmd.HmdUpdated += value;
remove => Hmd.HmdUpdated -= value;
}
protected virtual void Awake()
{
Hmd = _hmd as IHmd;
}
protected virtual void Start()
{
Assert.IsNotNull(Hmd);
}
public bool GetRootPose(out Pose pose)
{
return Hmd.GetRootPose(out pose);
}
#region Inject
public void InjectAllHmdRef(IHmd hmd)
{
InjectHmd(hmd);
}
public void InjectHmd(IHmd hmd)
{
_hmd = hmd as MonoBehaviour;
Hmd = hmd;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 484167e684014224c9a8bff92b293c6a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using UnityEngine;
namespace Oculus.Interaction.Input
{
public interface IHmd
{
bool GetRootPose(out Pose pose);
event Action HmdUpdated;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d92925b93eb01cf4ba528518efe2705a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c02ebbf428f995b45a218658ebd541d6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4b1422466b455b248ad5e0e27e1e043e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,39 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using UnityEngine;
namespace Oculus.Interaction.Input
{
public class DummyDataModifier : Hand
{
public Vector3 offset;
public float animationTime;
#region IHandInputDataModifier Implementation
protected override void Apply(HandDataAsset handDataAsset)
{
if (!handDataAsset.IsTracked)
{
return;
}
var interpolant = Mathf.Sin(Mathf.PI * 2.0f * (Time.time % animationTime) / animationTime) * 0.5f + 0.5f;
handDataAsset.Root.position = handDataAsset.Root.position + interpolant * offset + offset * -0.5f;
ref var joint = ref handDataAsset.Joints[(int)HandJointId.HandIndex1];
var rot = Quaternion.AngleAxis(interpolant * 90 - 45, Vector3.forward);
joint = joint * rot;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2d9aa5fe07a77244d89c6c80b08b33ab
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,48 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using UnityEngine;
namespace Oculus.Interaction.Input
{
public class FixedScaleDataModifier : Hand
{
[SerializeField]
private float _scale = 1f;
#region DataModifier Implementation
protected override void Apply(HandDataAsset data)
{
Pose rootToPointer = PoseUtils.RelativeOffset(data.PointerPose, data.Root);
rootToPointer.position = (rootToPointer.position / data.HandScale) * _scale;
PoseUtils.Multiply(data.Root, rootToPointer, ref data.PointerPose);
data.HandScale = _scale;
}
#endregion
#region Inject
public void InjectAllFixedScaleDataModifier(UpdateModeFlags updateMode, IDataSource updateAfter,
DataModifier<HandDataAsset, HandDataSourceConfig> modifyDataFromSource, bool applyModifier,
Component[] aspects, float scale)
{
base.InjectAllHand(updateMode, updateAfter, modifyDataFromSource, applyModifier, aspects);
InjectScale(scale);
}
public void InjectScale(float scale)
{
_scale = scale;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b927808915b4eba41b76168390b99c24
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,101 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using Oculus.Interaction.Throw;
using UnityEngine;
using UnityEngine.Serialization;
namespace Oculus.Interaction.Input
{
/// <summary>
/// Tracks the history of finger rotations and can be set to use the joint
/// rotations from some number of frames ago.
/// </summary>
public class JointRotationHistoryModifier : Hand
{
[SerializeField]
private int _historyLength = 60;
[SerializeField]
private int _historyOffset = 5;
private Quaternion[][] _jointHistory = new Quaternion[(int)HandJointId.HandMaxSkinnable][];
private int _historyIndex = 0;
private int _capturedDataVersion;
protected override void Start()
{
base.Start();
for (int i = 0; i < _jointHistory.Length; i++)
{
_jointHistory[i] = new Quaternion[_historyLength];
for (int j = 0; j < _historyLength; j++)
{
_jointHistory[i][j] = Quaternion.identity;
}
}
}
#region DataModifier Implementation
protected override void Apply(HandDataAsset data)
{
if (!data.IsDataValid)
{
return;
}
if (_capturedDataVersion != ModifyDataFromSource.CurrentDataVersion)
{
_capturedDataVersion = ModifyDataFromSource.CurrentDataVersion;
_historyIndex = (_historyIndex + 1) % _historyLength;
for (int i = 0; i < _jointHistory.Length; i++)
{
_jointHistory[i][_historyIndex] = data.Joints[i];
}
}
_historyOffset = Mathf.Clamp(_historyOffset, 0, _historyLength);
int index = (_historyIndex + _historyLength - _historyOffset) % _historyLength;
for (int i = 0; i < _jointHistory.Length; i++)
{
data.Joints[i] = _jointHistory[i][index];
}
}
#endregion
public void SetHistoryOffset(int offset)
{
_historyOffset = offset;
MarkInputDataRequiresUpdate();
}
#region Inject
public void InjectAllJointRotationHistoryModifier(UpdateModeFlags updateMode, IDataSource updateAfter,
DataModifier<HandDataAsset, HandDataSourceConfig> modifyDataFromSource, bool applyModifier,
Component[] aspects, int historyLength, int historyOffset)
{
base.InjectAllHand(updateMode, updateAfter, modifyDataFromSource, applyModifier, aspects);
InjectHistoryLength(historyLength);
SetHistoryOffset(historyOffset);
}
public void InjectHistoryLength(int historyLength)
{
_historyLength = historyLength;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4b5d61cebc8bc2644b45d6034694ea8f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,49 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
namespace Oculus.Interaction.Input
{
public class LastKnownGoodDataModifier : Hand
{
private readonly HandDataAsset _lastState = new HandDataAsset();
#region DataModifier Implementation
protected override void Apply(HandDataAsset data)
{
bool shouldUseData = data.IsHighConfidence ||
data.RootPoseOrigin == PoseOrigin.FilteredTrackedPose ||
data.RootPoseOrigin == PoseOrigin.SyntheticPose;
if (data.IsDataValid && data.IsTracked && shouldUseData)
{
_lastState.CopyFrom(data);
}
else if (_lastState.IsDataValid && data.IsConnected)
{
// No high confidence data, use last known good.
// Only copy pose data, not confidence/tracked flags.
data.CopyPosesFrom(_lastState);
data.RootPoseOrigin = PoseOrigin.SyntheticPose;
data.IsDataValid = true;
data.IsTracked = true;
data.IsHighConfidence = true;
}
else
{
// This hand is not connected, or has never seen valid data.
data.IsTracked = false;
data.IsHighConfidence = false;
data.RootPoseOrigin = PoseOrigin.None;
}
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7daff26e66096cd49a253ca3ab592c03
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,83 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using UnityEngine;
using UnityEngine.Profiling;
namespace Oculus.Interaction.Input
{
public class OneEuroFilterPositionDataModifier : Hand
{
[Header("Wrist")]
[SerializeField]
private OneEuroFilterPropertyBlock _wristFilterProperties =
new OneEuroFilterPropertyBlock(2f, 10f);
private IOneEuroFilter<Vector3> _wristFilter;
private int _lastFrameUpdated;
private Pose _lastSmoothedPose;
protected override void Start()
{
base.Start();
_lastFrameUpdated = 0;
_wristFilter = OneEuroFilter.CreateVector3();
}
#region IHandInputDataModifier Implementation
protected override void Apply(HandDataAsset handDataAsset)
{
if (!handDataAsset.IsTracked)
{
return;
}
Profiler.BeginSample($"{nameof(OneEuroFilterPositionDataModifier)}." +
$"{nameof(OneEuroFilterPositionDataModifier.Apply)}");
if (Time.frameCount > _lastFrameUpdated)
{
_lastFrameUpdated = Time.frameCount;
_lastSmoothedPose = ApplyFilter(handDataAsset.Root);
}
handDataAsset.Root = _lastSmoothedPose;
handDataAsset.RootPoseOrigin = PoseOrigin.FilteredTrackedPose;
Profiler.EndSample();
}
#endregion
private Pose ApplyFilter(Pose pose)
{
_wristFilter.SetProperties(_wristFilterProperties);
pose.position = _wristFilter.Step(pose.position, Time.fixedDeltaTime);
return pose;
}
#region Inject
public void InjectAllOneEuroFilterPositionDataModifier(UpdateModeFlags updateMode, IDataSource updateAfter,
DataModifier<HandDataAsset, HandDataSourceConfig> modifyDataFromSource, bool applyModifier,
Component[] aspects, OneEuroFilterPropertyBlock wristFilterProperties)
{
base.InjectAllHand(updateMode, updateAfter, modifyDataFromSource, applyModifier, aspects);
InjectWristFilterProperties(wristFilterProperties);
}
public void InjectWristFilterProperties(OneEuroFilterPropertyBlock wristFilterProperties)
{
_wristFilterProperties = wristFilterProperties;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 77f93b4928ccdb2448c377308b7f4731
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,162 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.Profiling;
namespace Oculus.Interaction.Input
{
/// <summary>
/// Data Modifier use to apply the One Euro Filter to a hand pose.
/// Filtering can be applied to the wrist and any number of finger joints.
/// </summary>
public class OneEuroFilterRotationDataModifier : Hand
{
[Header("Wrist")]
[SerializeField]
private bool _wristFilterEnabled = true;
[SerializeField]
private OneEuroFilterPropertyBlock _wristFilterProperties =
new OneEuroFilterPropertyBlock(2f, 3f);
[Header("Fingers")]
[SerializeField]
private bool _fingerFiltersEnabled = true;
[SerializeField]
private HandFingerJointFlags _fingerJoints = HandFingerJointFlags.None;
[SerializeField]
private OneEuroFilterPropertyBlock _fingerFilterProperties =
new OneEuroFilterPropertyBlock(1f, 2f);
private IOneEuroFilter<Quaternion> _wristFilter;
private List<JointFilter> _fingerJointFilters;
private HandDataAsset _lastFiltered;
private int _lastFrameUpdated;
protected override void Start()
{
base.Start();
InitFingerJointFilters();
_lastFrameUpdated = 0;
_lastFiltered = new HandDataAsset();
_wristFilter = OneEuroFilter.CreateQuaternion();
}
private void InitFingerJointFilters()
{
_fingerJointFilters = new List<JointFilter>();
if (_fingerJoints == HandFingerJointFlags.None)
{
return;
}
foreach (var jointId in HandJointUtils.JointIds)
{
HandFingerJointFlags jointFlag = (HandFingerJointFlags)(1 << (int)jointId);
if (!Enum.IsDefined(typeof(HandFingerJointFlags), jointFlag))
{
continue;
}
if (_fingerJoints.HasFlag(jointFlag))
{
_fingerJointFilters.Add(new JointFilter(jointId));
}
}
}
#region IHandInputDataModifier Implementation
protected override void Apply(HandDataAsset handDataAsset)
{
if (!handDataAsset.IsTracked)
{
return;
}
Profiler.BeginSample($"{nameof(OneEuroFilterRotationDataModifier)}." +
$"{nameof(OneEuroFilterRotationDataModifier.Apply)}");
if (Time.frameCount > _lastFrameUpdated)
{
_lastFrameUpdated = Time.frameCount;
ApplyFilters(handDataAsset);
_lastFiltered.CopyFrom(handDataAsset);
}
else
{
handDataAsset.CopyFrom(_lastFiltered);
}
handDataAsset.RootPoseOrigin = PoseOrigin.FilteredTrackedPose;
Profiler.EndSample();
}
#endregion
private void ApplyFilters(HandDataAsset handDataAsset)
{
if (_wristFilterEnabled)
{
Pose rootPose = handDataAsset.Root;
_wristFilter.SetProperties(_wristFilterProperties);
rootPose.rotation = _wristFilter.Step(rootPose.rotation, Time.fixedDeltaTime);
handDataAsset.Root = rootPose;
}
if (_fingerFiltersEnabled)
{
foreach (var joint in _fingerJointFilters)
{
joint.Filter.SetProperties(_fingerFilterProperties);
handDataAsset.Joints[(int)joint.JointId] =
joint.Filter.Step(handDataAsset.Joints[(int)joint.JointId], Time.fixedDeltaTime);
}
}
}
private class JointFilter
{
public HandJointId JointId => _jointId;
public IOneEuroFilter<Quaternion> Filter => _filter;
private readonly HandJointId _jointId;
private readonly IOneEuroFilter<Quaternion> _filter;
public JointFilter(HandJointId jointId)
{
_jointId = jointId;
_filter = OneEuroFilter.CreateQuaternion();
}
}
#region Inject
public void InjectAllOneEuroFilterRotationDataModifier(UpdateModeFlags updateMode, IDataSource updateAfter,
DataModifier<HandDataAsset, HandDataSourceConfig> modifyDataFromSource, bool applyModifier,
Component[] aspects, OneEuroFilterPropertyBlock wristFilterProperties)
{
base.InjectAllHand(updateMode, updateAfter, modifyDataFromSource, applyModifier, aspects);
InjectWristFilterProperties(wristFilterProperties);
}
public void InjectWristFilterProperties(OneEuroFilterPropertyBlock wristFilterProperties)
{
_wristFilterProperties = wristFilterProperties;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e410712d2f3ef084daeb2eac77899ce2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,508 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using UnityEngine;
namespace Oculus.Interaction.Input
{
/// <summary>
/// Alters hand data piped into this modifier to lock and unlock joints (wrist position and rotation,
/// finger joint rotations) When switching between locked and unlocked states, additionally smooths
/// out transitions by easing between source hand data and target hand data.
/// </summary>
public class SyntheticHandModifier : Hand
{
[System.Flags]
public enum WristLockMode
{
Position = 1 << 0,
Rotation = 1 << 1,
Full = (1 << 2) - 1
}
[SerializeField]
private ProgressCurve _wristPositionLockCurve = new ProgressCurve();
[SerializeField]
private ProgressCurve _wristPositionUnlockCurve;
[SerializeField]
private ProgressCurve _wristRotationLockCurve;
[SerializeField]
private ProgressCurve _wristRotationUnlockCurve;
[SerializeField]
private ProgressCurve _jointLockCurve;
[SerializeField]
private ProgressCurve _jointUnlockCurve;
/// <summary>
/// Use this factor to control how much the fingers can spread when nearby a constrained pose.
/// </summary>
[SerializeField]
[Tooltip("Use this factor to control how much the fingers can spread when nearby a constrained pose.")]
private float _spreadAllowance = 5f;
public System.Action UpdateRequired = delegate { };
private readonly HandDataAsset _lastStates = new HandDataAsset();
private float _wristPositionOverrideFactor;
private float _wristRotationOverrideFactor;
private float[] _jointsOverrideFactor = new float[FingersMetadata.HAND_JOINT_IDS.Length];
private ProgressCurve[] _jointLockProgressCurves = new ProgressCurve[FingersMetadata.HAND_JOINT_IDS.Length];
private ProgressCurve[] _jointUnlockProgressCurves = new ProgressCurve[FingersMetadata.HAND_JOINT_IDS.Length];
private Pose _desiredWristPose;
private bool _wristPositionLocked;
private bool _wristRotationLocked;
private Pose _constrainedWristPose;
private Pose _lastWristPose;
private Quaternion[] _desiredJointsRotation = new Quaternion[FingersMetadata.HAND_JOINT_IDS.Length];
private Quaternion[] _constrainedJointRotations = new Quaternion[FingersMetadata.HAND_JOINT_IDS.Length];
private Quaternion[] _lastSyntheticRotation = new Quaternion[FingersMetadata.HAND_JOINT_IDS.Length];
private JointFreedom[] _jointsFreedomLevels = new JointFreedom[FingersMetadata.HAND_JOINT_IDS.Length];
private bool _hasConnectedData;
protected override void Start()
{
base.Start();
for (int i = 0; i < FingersMetadata.HAND_JOINT_IDS.Length; i++)
{
_jointLockProgressCurves[i] = new ProgressCurve(_jointLockCurve);
_jointUnlockProgressCurves[i] = new ProgressCurve(_jointUnlockCurve);
}
}
protected override void Apply(HandDataAsset data)
{
if (!data.IsDataValid || !data.IsTracked || !data.IsHighConfidence)
{
data.IsConnected = false;
data.RootPoseOrigin = PoseOrigin.None;
_hasConnectedData = false;
return;
}
UpdateRequired.Invoke();
_lastStates.CopyFrom(data);
if (!_hasConnectedData)
{
_constrainedWristPose = data.Root;
_hasConnectedData = true;
}
UpdateJointsRotation(data);
UpdateRootPose(ref data.Root);
data.RootPoseOrigin = PoseOrigin.SyntheticPose;
}
/// <summary>
/// Updates the pose of the root of the hand
/// using the visual provided values. Sometimes this
/// might require lerping between the tracked pose
/// and the provided one to improve the movement of the hand
/// without worrying about when the overwrite value was written.
///
/// During this update, the modifier also ensures the unlocking
/// animations are executed.
/// </summary>
/// <param name="root">The tracked root value to modify</param>
private void UpdateRootPose(ref Pose root)
{
float smoothPositionFactor = _wristPositionLocked ? _wristPositionLockCurve.Progress() : _wristPositionUnlockCurve.Progress();
Vector3 position = Vector3.Lerp(root.position, _desiredWristPose.position, _wristPositionOverrideFactor);
root.position = Vector3.Lerp(_constrainedWristPose.position, position, smoothPositionFactor);
float smoothRotationFactor = _wristRotationLocked ? _wristRotationLockCurve.Progress() : _wristRotationUnlockCurve.Progress();
Quaternion rotation = Quaternion.Lerp(root.rotation, _desiredWristPose.rotation, _wristRotationOverrideFactor);
root.rotation = Quaternion.Lerp(_constrainedWristPose.rotation, rotation, smoothRotationFactor);
_lastWristPose.CopyFrom(root);
}
/// <summary>
/// Updates the rotation of the joints in the hand
/// using the visual provided values. Sometimes this
/// might require lerping between the tracked pose
/// and the provided ones to improve the movement of the fingers
/// without worrying about when the overwrite values were written.
///
/// During this update the modifier also ensures that fingers that disallow
/// some movement (locked or constrained) have their values properly set, and
/// when there is an unlock event the finger values are smoothly animated back to
/// their tracked rotations.
/// </summary>
/// <param name="data">The entire hand data structure to read and write the joints rotations from</param>
private void UpdateJointsRotation(HandDataAsset data)
{
float extraRotationAllowance = 0f;
Quaternion[] jointRotations = data.Joints;
for (int i = 0; i < FingersMetadata.HAND_JOINT_IDS.Length; ++i)
{
JointFreedom freedomLevel = _jointsFreedomLevels[i];
Quaternion desiredRotation = _desiredJointsRotation[i];
float overrideFactor = _jointsOverrideFactor[i];
int rawJointIndex = (int)FingersMetadata.HAND_JOINT_IDS[i];
if (freedomLevel == JointFreedom.Free)
{
//nothing to do, we move the finger freely
}
else if (freedomLevel == JointFreedom.Locked)
{
jointRotations[rawJointIndex] = Quaternion.Slerp(
jointRotations[rawJointIndex],
desiredRotation,
overrideFactor);
}
else if (freedomLevel == JointFreedom.Constrained)
{
bool jointCanSpread = false;
if (FingersMetadata.HAND_JOINT_CAN_SPREAD[i])
{
jointCanSpread = true;
extraRotationAllowance = 0f;
}
Quaternion maxRotation = desiredRotation * Quaternion.Euler(0f, 0f, -90f * extraRotationAllowance);
float overRotation = OverFlex(jointRotations[rawJointIndex], maxRotation);
extraRotationAllowance = Mathf.Max(extraRotationAllowance, overRotation);
if (overRotation < 0f)
{
jointRotations[rawJointIndex] = Quaternion.Slerp(
jointRotations[rawJointIndex],
maxRotation,
overrideFactor);
}
else if (jointCanSpread)
{
Quaternion trackedRotation = jointRotations[rawJointIndex];
float spreadAngle = Vector3.SignedAngle(
trackedRotation * Vector3.forward,
maxRotation * Vector3.forward,
trackedRotation * Vector3.up);
float spreadFactor = 1f - Mathf.Clamp01(overRotation * _spreadAllowance);
trackedRotation = trackedRotation * Quaternion.Euler(0f, spreadAngle * spreadFactor, 0f);
jointRotations[rawJointIndex] = trackedRotation;
}
}
float smoothFactor = _jointsFreedomLevels[i] == JointFreedom.Free ?
_jointUnlockProgressCurves[i].Progress()
: _jointLockProgressCurves[i].Progress();
jointRotations[rawJointIndex] = Quaternion.Slerp(
_constrainedJointRotations[i],
jointRotations[rawJointIndex],
smoothFactor);
_lastSyntheticRotation[i] = jointRotations[rawJointIndex];
}
}
/// <summary>
/// Stores the rotation data for all joints in the hand, to be applied during the ApplyHand event.
/// </summary>
/// <param name="jointRotations">The joint rotations following the FingersMetadata.HAND_JOINT_IDS format.</param>
/// <param name="overrideFactor">How much to lerp the fingers from the tracked (raw) state to the provided one.</param>
public void OverrideAllJoints(in Quaternion[] jointRotations, float overrideFactor)
{
for (int i = 0; i < FingersMetadata.HAND_JOINT_IDS.Length; ++i)
{
_desiredJointsRotation[i] = jointRotations[i];
_jointsOverrideFactor[i] = overrideFactor;
}
}
/// <summary>
/// Stores the rotation data for all joints for the given finger, to be applied during the ApplyHand event.
/// </summary>
/// <param name="finger">The finger for which to lock joints.</param>
/// <param name="rotations">The joint rotations for each joint on the finger</param>
/// <param name="overrideFactor">How much to lerp the fingers from the tracked (raw) state to the provided one.</param>
public void OverrideFingerRotations(HandFinger finger, Quaternion[] rotations, float overrideFactor)
{
int[] jointIndices = FingersMetadata.FINGER_TO_JOINT_INDEX[(int)finger];
for (int i = 0; i < jointIndices.Length; i++)
{
OverrideJointRotationAtIndex(jointIndices[i], rotations[i], overrideFactor);
}
}
public void OverrideJointRotation(HandJointId jointId, Quaternion rotation, float overrideFactor)
{
int jointIndex = FingersMetadata.HandJointIdToIndex(jointId);
OverrideJointRotationAtIndex(jointIndex, rotation, overrideFactor);
}
private void OverrideJointRotationAtIndex(int jointIndex, Quaternion rotation, float overrideFactor)
{
_desiredJointsRotation[jointIndex] = rotation;
_jointsOverrideFactor[jointIndex] = overrideFactor;
}
/// <summary>
/// Immediately locks an individual finger (all its internal joints) at the last known value.
/// </summary>
/// <param name="finger">The finger for which to lock joints.</param>
public void LockFingerAtCurrent(in HandFinger finger)
{
SetFingerFreedom(finger, JointFreedom.Locked);
int fingerIndex = (int)finger;
int[] jointIndexes = FingersMetadata.FINGER_TO_JOINT_INDEX[fingerIndex];
for (int i = 0; i < jointIndexes.Length; ++i)
{
int jointIndex = jointIndexes[i];
int rawJointIndex = (int)FingersMetadata.HAND_JOINT_IDS[jointIndex];
_desiredJointsRotation[jointIndex] = _lastStates.Joints[rawJointIndex];
_jointsOverrideFactor[jointIndex] = 1f;
}
}
public void LockJoint(in HandJointId jointId, Quaternion rotation, float overrideFactor = 1f)
{
int jointIndex = FingersMetadata.HandJointIdToIndex(jointId);
_desiredJointsRotation[jointIndex] = rotation;
_jointsOverrideFactor[jointIndex] = 1f;
SetJointFreedomAtIndex(jointIndex, JointFreedom.Locked);
}
/// <summary>
/// To use in conjunction with OverrideAllJoints, it sets the freedom state for a provided finger.
/// Opposite to LockFingerAtCurrent, this method uses the data provided in OverrideAllJoints instead
/// of the last known state.
/// </summary>
/// <param name="freedomLevel">The freedom level for the finger</param>
public void SetFingerFreedom(in HandFinger finger, in JointFreedom freedomLevel, bool skipAnimation = false)
{
int[] jointIndexes = FingersMetadata.FINGER_TO_JOINT_INDEX[(int)finger];
for (int i = 0; i < jointIndexes.Length; ++i)
{
SetJointFreedomAtIndex(jointIndexes[i], freedomLevel, skipAnimation);
}
}
public void SetJointFreedom(in HandJointId jointId, in JointFreedom freedomLevel, bool skipAnimation = false)
{
int jointIndex = FingersMetadata.HandJointIdToIndex(jointId);
SetJointFreedomAtIndex(jointIndex, freedomLevel, skipAnimation);
}
/// <summary>
/// Short-hand method for setting the freedom level of all fingers in a hand to Free.
/// Similar to calling SetFingerFreedom for each single finger in the hand
/// with a value of FingerFreedom.Free for the freedomLevel
/// </summary>
public void FreeAllJoints()
{
for (int i = 0; i < FingersMetadata.HAND_JOINT_IDS.Length; ++i)
{
SetJointFreedomAtIndex(i, JointFreedom.Free);
}
}
private void SetJointFreedomAtIndex(int jointId, in JointFreedom freedomLevel, bool skipAnimation = false)
{
JointFreedom currentFreedom = _jointsFreedomLevels[jointId];
if (currentFreedom != freedomLevel)
{
bool locked = freedomLevel == JointFreedom.Locked
|| freedomLevel == JointFreedom.Constrained;
UpdateProgressCurve(ref _jointLockProgressCurves[jointId],
ref _jointUnlockProgressCurves[jointId],
locked, skipAnimation);
_constrainedJointRotations[jointId] = _lastSyntheticRotation[jointId];
}
_jointsFreedomLevels[jointId] = freedomLevel;
}
/// <summary>
/// Stores the desired pose to set the wrist of the hand to.
/// This is not necessarily the final pose of the hand, as it allows
/// lerping between the tracked and provided one during the ApplyHand phase.
///
/// To ensure the hand is locked at the desired pose, pass a value of 1 in the overrideFactor
/// </summary>
/// <param name="wristPose">The final pose desired for the wrist</param>
/// <param name="lockMode">Either lock the position, rotation or both (default)</param>
/// <param name="overrideFactor">How much to lerp between the tracked and the provided pose</param>
/// <param name="skipAnimation">Whether to skip the animation curve for this override.</param>
public void LockWristPose(Pose wristPose, float overrideFactor = 1f, WristLockMode lockMode = WristLockMode.Full, bool worldPose = false, bool skipAnimation = false)
{
Pose desiredWristPose = worldPose ? TrackingToWorldTransformer.ToTrackingPose(wristPose) : wristPose;
if ((lockMode & WristLockMode.Position) != 0)
{
LockWristPosition(desiredWristPose.position, overrideFactor, skipAnimation);
}
if ((lockMode & WristLockMode.Rotation) != 0)
{
LockWristRotation(desiredWristPose.rotation, overrideFactor, skipAnimation);
}
}
public void LockWristPosition(Vector3 position, float overrideFactor = 1f, bool skipAnimation = false)
{
_wristPositionOverrideFactor = overrideFactor;
_desiredWristPose.position = position;
if (!_wristPositionLocked)
{
SyntheticWristLockChangedState(WristLockMode.Position, skipAnimation);
_wristPositionLocked = true;
}
}
public void LockWristRotation(Quaternion rotation, float overrideFactor = 1f, bool skipAnimation = false)
{
_wristRotationOverrideFactor = overrideFactor;
_desiredWristPose.rotation = rotation;
if (!_wristRotationLocked)
{
SyntheticWristLockChangedState(WristLockMode.Rotation, skipAnimation);
_wristRotationLocked = true;
}
}
/// <summary>
/// Unlocks the hand (locked at the OverrideWristPose method) starting
/// a timer for the smooth release animation.
/// </summary>
public void FreeWrist(WristLockMode lockMode = WristLockMode.Full)
{
if ((lockMode & WristLockMode.Position) != 0
&& _wristPositionLocked)
{
_wristPositionOverrideFactor = 0f;
_wristPositionLocked = false;
SyntheticWristLockChangedState(WristLockMode.Position);
}
if ((lockMode & WristLockMode.Rotation) != 0
&& _wristRotationLocked)
{
_wristRotationOverrideFactor = 0f;
_wristRotationLocked = false;
SyntheticWristLockChangedState(WristLockMode.Rotation);
}
}
private void SyntheticWristLockChangedState(WristLockMode lockMode, bool skipAnimation = false)
{
if ((lockMode & WristLockMode.Position) != 0)
{
UpdateProgressCurve(ref _wristPositionLockCurve, ref _wristPositionUnlockCurve,
_wristPositionLocked, skipAnimation);
_constrainedWristPose.position = _lastWristPose.position;
}
if ((lockMode & WristLockMode.Rotation) != 0)
{
UpdateProgressCurve(ref _wristRotationLockCurve, ref _wristRotationUnlockCurve,
_wristRotationLocked, skipAnimation);
_constrainedWristPose.rotation = _lastWristPose.rotation;
}
}
/// <summary>
/// Indicates whether a joint's tracked rotation is past a given rotation.
/// Works in local Unity Joint coordinates.
/// This is useful for blocking fingers past the snapping point.
/// </summary>
/// <param name="desiredLocalRot">The known local rotation of the joint. </param>
/// <param name="maxLocalRot">The desired max local rotation of the joint.</param>
/// <returns>A negative scalar proportional to how much the rotation is over the max one, a proportional positive scalar if under.</returns>
private static float OverFlex(in Quaternion desiredLocalRot, in Quaternion maxLocalRot)
{
Vector3 jointDir = desiredLocalRot * Vector3.right;
Vector3 jointTan = desiredLocalRot * Vector3.back;
Vector3 maxDir = maxLocalRot * Vector3.right;
Vector3 difference = Vector3.Cross(jointDir, maxDir);
return Vector3.Dot(jointTan, difference);
}
private static void UpdateProgressCurve(ref ProgressCurve lockProgress, ref ProgressCurve unlockProgress, bool locked, bool skipAnimation)
{
ProgressCurve progress = locked ? lockProgress : unlockProgress;
if (skipAnimation)
{
progress.End();
}
else
{
progress.Start();
}
}
#region Inject
public void InjectAllSyntheticHandModifier(UpdateModeFlags updateMode, IDataSource updateAfter,
DataModifier<HandDataAsset, HandDataSourceConfig> modifyDataFromSource, bool applyModifier,
Component[] aspects,
ProgressCurve wristPositionLockCurve, ProgressCurve wristPositionUnlockCurve,
ProgressCurve wristRotationLockCurve, ProgressCurve wristRotationUnlockCurve,
ProgressCurve jointLockCurve, ProgressCurve jointUnlockCurve,
float spreadAllowance)
{
base.InjectAllHand(updateMode, updateAfter, modifyDataFromSource, applyModifier, aspects);
InjectWristPositionLockCurve(wristPositionLockCurve);
InjectWristPositionUnlockCurve(wristPositionUnlockCurve);
InjectWristRotationLockCurve(wristRotationLockCurve);
InjectWristRotationUnlockCurve(wristRotationUnlockCurve);
InjectJointLockCurve(jointLockCurve);
InjectJointUnlockCurve(jointUnlockCurve);
InjectSpreadAllowance(spreadAllowance);
}
public void InjectWristPositionLockCurve(ProgressCurve wristPositionLockCurve) {
_wristPositionLockCurve = wristPositionLockCurve;
}
public void InjectWristPositionUnlockCurve(ProgressCurve wristPositionUnlockCurve) {
_wristPositionUnlockCurve = wristPositionUnlockCurve;
}
public void InjectWristRotationLockCurve(ProgressCurve wristRotationLockCurve) {
_wristRotationLockCurve = wristRotationLockCurve;
}
public void InjectWristRotationUnlockCurve(ProgressCurve wristRotationUnlockCurve) {
_wristRotationUnlockCurve = wristRotationUnlockCurve;
}
public void InjectJointLockCurve(ProgressCurve jointLockCurve) {
_jointLockCurve = jointLockCurve;
}
public void InjectJointUnlockCurve(ProgressCurve jointUnlockCurve) {
_jointUnlockCurve = jointUnlockCurve;
}
public void InjectSpreadAllowance(float spreadAllowance) {
_spreadAllowance = spreadAllowance;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5c67033f580359c4581dff1ccffcca91
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,137 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
namespace Oculus.Interaction.Input
{
public enum JointFreedom
{
Free,
Constrained,
Locked
}
/// <summary>
/// This class contains a series of useful fingers-related data structures
/// to be used for optimal calculations without relying in dictionaries.
///
/// Since we always assume the hand pose information to be sorted in
/// the HAND_JOINT_IDS order, we can align multiple data structures
/// that follow that convention.
/// </summary>
public class FingersMetadata
{
public static JointFreedom[] DefaultFingersFreedom()
{
return new JointFreedom[Constants.NUM_FINGERS]
{
JointFreedom.Locked,
JointFreedom.Locked,
JointFreedom.Constrained,
JointFreedom.Constrained,
JointFreedom.Free
};
}
public static int HandJointIdToIndex(HandJointId id)
{
return (int)id - (int)HandJointId.HandThumb0;
}
/// <summary>
/// Valid identifiers for the i-bone of a hand.
/// </summary>
public static readonly HandJointId[] HAND_JOINT_IDS = new HandJointId[]
{
HandJointId.HandThumb0,
HandJointId.HandThumb1,
HandJointId.HandThumb2,
HandJointId.HandThumb3,
HandJointId.HandIndex1,
HandJointId.HandIndex2,
HandJointId.HandIndex3,
HandJointId.HandMiddle1,
HandJointId.HandMiddle2,
HandJointId.HandMiddle3,
HandJointId.HandRing1,
HandJointId.HandRing2,
HandJointId.HandRing3,
HandJointId.HandPinky0,
HandJointId.HandPinky1,
HandJointId.HandPinky2,
HandJointId.HandPinky3
};
/// <summary>
/// This array is used to convert from Finger id to the list indices
/// of its joint in the HAND_JOINT_IDS list.
/// </summary>
public static readonly int[][] FINGER_TO_JOINT_INDEX = new int[][]
{
new[] {0,1,2,3},
new[] {4,5,6},
new[] {7,8,9},
new[] {10,11,12},
new[] {13,14,15,16}
};
/// <summary>
/// Array order following HAND_JOINT_IDS that indicates if the i joint
/// can spread (rotate around Y). Should be true for the root of the fingers
/// but Pink and Thumb are special cases
/// </summary>
public static readonly bool[] HAND_JOINT_CAN_SPREAD = new bool[]
{
true, //HandJointId.HandThumb0
true, //HandJointId.HandThumb1
false,//HandJointId.HandThumb2
false,//HandJointId.HandThumb3
true, //HandJointId.HandIndex1
false,//HandJointId.HandIndex2
false,//HandJointId.HandIndex3
true, //HandJointId.HandMiddle1
false,//HandJointId.HandMiddle2
false,//HandJointId.HandMiddle3
true, //HandJointId.HandRing1
false,//HandJointId.HandRing2
false,//HandJointId.HandRing3
true, //HandJointId.HandPinky0
true, //HandJointId.HandPinky1
false,//HandJointId.HandPinky2
false //HandJointId.HandPinky3
};
/// <summary>
/// Sorted like HAND_JOINT_IDS, this array is used to retrieve the finger
/// each joint belongs to.
/// </summary>
public static readonly HandFinger[] HAND_FINGER_ID = new HandFinger[]
{
HandFinger.Thumb,
HandFinger.Thumb,
HandFinger.Thumb,
HandFinger.Thumb,
HandFinger.Index,
HandFinger.Index,
HandFinger.Index,
HandFinger.Middle,
HandFinger.Middle,
HandFinger.Middle,
HandFinger.Ring,
HandFinger.Ring,
HandFinger.Ring,
HandFinger.Pinky,
HandFinger.Pinky,
HandFinger.Pinky,
HandFinger.Pinky
};
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9c86919be0f18a54b8706542dc38dede
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,274 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;
namespace Oculus.Interaction.Input
{
// A top level component that provides hand pose data, pinch states, and more.
// Rather than sourcing data directly from the runtime layer, provides one
// level of abstraction so that the aforementioned data can be injected
// from other sources.
public class Hand : DataModifier<HandDataAsset, HandDataSourceConfig>, IHand
{
[SerializeField]
[Tooltip("Provides access to additional functionality on top of what the IHand interface provides." +
"For example, this list can be used to provide access to the SkinnedMeshRenderer through " +
"the IHand.GetHandAspect method.")]
private Component[] _aspects;
public IReadOnlyList<Component> Aspects => _aspects;
public ITrackingToWorldTransformer TrackingToWorldTransformer =>
Config.TrackingToWorldTransformer;
private HandJointCache _jointPosesCache;
public event Action HandUpdated = delegate { };
public bool IsConnected => GetData().IsDataValidAndConnected;
public bool IsHighConfidence => GetData().IsHighConfidence;
public bool IsDominantHand => GetData().IsDominantHand;
public Handedness Handedness => Config.Handedness;
public float Scale => GetData().HandScale * TrackingToWorldTransformer.Transform.localScale.x;
private static readonly Vector3 PALM_LOCAL_OFFSET = new Vector3(0.08f, -0.01f, 0.0f);
protected override void Apply(HandDataAsset data)
{
// Default implementation does nothing, to allow instantiation of this modifier directly
}
public override void MarkInputDataRequiresUpdate()
{
base.MarkInputDataRequiresUpdate();
if (Started)
{
InitializeJointPosesCache();
HandUpdated.Invoke();
}
}
private void InitializeJointPosesCache()
{
if (_jointPosesCache == null && GetData().IsDataValidAndConnected)
{
_jointPosesCache = new HandJointCache(Config.HandSkeleton);
}
}
private void CheckJointPosesCacheUpdate()
{
if (_jointPosesCache != null
&& CurrentDataVersion != _jointPosesCache.LocalDataVersion)
{
_jointPosesCache.Update(GetData(), CurrentDataVersion);
}
}
#region IHandState implementation
public bool GetFingerIsPinching(HandFinger finger)
{
HandDataAsset currentData = GetData();
return currentData.IsConnected && currentData.IsFingerPinching[(int)finger];
}
public bool GetIndexFingerIsPinching()
{
return GetFingerIsPinching(HandFinger.Index);
}
public bool IsPointerPoseValid => IsPoseOriginAllowed(GetData().PointerPoseOrigin);
public bool GetPointerPose(out Pose pose)
{
HandDataAsset currentData = GetData();
return ValidatePose(currentData.PointerPose, currentData.PointerPoseOrigin,
out pose);
}
public bool GetJointPose(HandJointId handJointId, out Pose pose)
{
pose = Pose.identity;
if (!IsTrackedDataValid
|| _jointPosesCache == null
|| !GetRootPose(out Pose rootPose))
{
return false;
}
CheckJointPosesCacheUpdate();
pose = _jointPosesCache.WorldJointPose(handJointId, rootPose, Scale);
return true;
}
public bool GetJointPoseLocal(HandJointId handJointId, out Pose pose)
{
pose = Pose.identity;
if (!GetJointPosesLocal(out ReadOnlyHandJointPoses localJointPoses))
{
return false;
}
pose = localJointPoses[(int)handJointId];
return true;
}
public bool GetJointPosesLocal(out ReadOnlyHandJointPoses localJointPoses)
{
if (!IsTrackedDataValid || _jointPosesCache == null)
{
localJointPoses = ReadOnlyHandJointPoses.Empty;
return false;
}
CheckJointPosesCacheUpdate();
return _jointPosesCache.GetAllLocalPoses(out localJointPoses);
}
public bool GetJointPoseFromWrist(HandJointId handJointId, out Pose pose)
{
pose = Pose.identity;
if (!GetJointPosesFromWrist(out ReadOnlyHandJointPoses jointPosesFromWrist))
{
return false;
}
pose = jointPosesFromWrist[(int)handJointId];
return true;
}
public bool GetJointPosesFromWrist(out ReadOnlyHandJointPoses jointPosesFromWrist)
{
if (!IsTrackedDataValid || _jointPosesCache == null)
{
jointPosesFromWrist = ReadOnlyHandJointPoses.Empty;
return false;
}
CheckJointPosesCacheUpdate();
return _jointPosesCache.GetAllPosesFromWrist(out jointPosesFromWrist);
}
public bool GetPalmPoseLocal(out Pose pose)
{
Quaternion rotationQuat = Quaternion.identity;
Vector3 offset = PALM_LOCAL_OFFSET;
if (Handedness == Handedness.Left)
{
offset = -offset;
}
pose = new Pose(offset * Scale, rotationQuat);
return true;
}
public bool GetFingerIsHighConfidence(HandFinger finger)
{
return GetData().IsFingerHighConfidence[(int)finger];
}
public float GetFingerPinchStrength(HandFinger finger)
{
return GetData().FingerPinchStrength[(int)finger];
}
public bool IsTrackedDataValid => IsPoseOriginAllowed(GetData().RootPoseOrigin);
public bool GetRootPose(out Pose pose)
{
HandDataAsset currentData = GetData();
return ValidatePose(currentData.Root, currentData.RootPoseOrigin, out pose);
}
public bool IsCenterEyePoseValid => Config.HmdData.GetData().IsTracked;
public bool GetCenterEyePose(out Pose pose)
{
HmdDataAsset hmd = Config.HmdData.GetData();
if (!hmd.IsTracked)
{
pose = new Pose();
return false;
}
pose = TrackingToWorldTransformer.ToWorldPose(hmd.Root);
return true;
}
#endregion
public Transform TrackingToWorldSpace
{
get
{
return TrackingToWorldTransformer.Transform;
}
}
private bool ValidatePose(in Pose sourcePose, PoseOrigin sourcePoseOrigin, out Pose pose)
{
if (IsPoseOriginDisallowed(sourcePoseOrigin))
{
pose = Pose.identity;
return false;
}
pose = TrackingToWorldTransformer.ToWorldPose(sourcePose);
return true;
}
private bool IsPoseOriginAllowed(PoseOrigin poseOrigin)
{
return poseOrigin != PoseOrigin.None;
}
private bool IsPoseOriginDisallowed(PoseOrigin poseOrigin)
{
return poseOrigin == PoseOrigin.None;
}
public bool GetHandAspect<TComponent>(out TComponent foundComponent) where TComponent : class
{
foreach (Component aspect in _aspects)
{
foundComponent = aspect as TComponent;
if (foundComponent != null)
{
return true;
}
}
foundComponent = null;
return false;
}
#region Inject
public void InjectAllHand(UpdateModeFlags updateMode, IDataSource updateAfter,
DataModifier<HandDataAsset, HandDataSourceConfig> modifyDataFromSource, bool applyModifier,
Component[] aspects)
{
base.InjectAllDataModifier(updateMode, updateAfter, modifyDataFromSource, applyModifier);
InjectAspects(aspects);
}
public void InjectAspects(Component[] aspects)
{
_aspects = aspects;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1a379f34d4f4f2e408d34f14bfb753ce
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,62 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using UnityEngine;
namespace Oculus.Interaction.Input
{
[Serializable]
public class HandDataAsset : ICopyFrom<HandDataAsset>
{
public bool IsDataValid;
public bool IsConnected;
public bool IsTracked;
public Pose Root;
public PoseOrigin RootPoseOrigin;
public Quaternion[] Joints = new Quaternion[Constants.NUM_HAND_JOINTS];
public bool IsHighConfidence;
public bool[] IsFingerPinching = new bool[Constants.NUM_FINGERS];
public bool[] IsFingerHighConfidence = new bool[Constants.NUM_FINGERS];
public float[] FingerPinchStrength = new float[Constants.NUM_FINGERS];
public float HandScale;
public Pose PointerPose;
public PoseOrigin PointerPoseOrigin;
public bool IsDominantHand;
public bool IsDataValidAndConnected => IsDataValid && IsConnected;
public void CopyFrom(HandDataAsset source)
{
IsDataValid = source.IsDataValid;
IsConnected = source.IsConnected;
IsTracked = source.IsTracked;
IsHighConfidence = source.IsHighConfidence;
IsDominantHand = source.IsDominantHand;
CopyPosesFrom(source);
}
public void CopyPosesFrom(HandDataAsset source)
{
Root = source.Root;
RootPoseOrigin = source.RootPoseOrigin;
Array.Copy(source.Joints, Joints, Constants.NUM_HAND_JOINTS);
Array.Copy(source.IsFingerPinching, IsFingerPinching, IsFingerPinching.Length);
Array.Copy(source.IsFingerHighConfidence, IsFingerHighConfidence,
IsFingerHighConfidence.Length);
Array.Copy(source.FingerPinchStrength, FingerPinchStrength, FingerPinchStrength.Length);
HandScale = source.HandScale;
PointerPose = source.PointerPose;
PointerPoseOrigin = source.PointerPoseOrigin;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 24ccc8fce03318d4fb4fbd8bb782ded2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,25 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
namespace Oculus.Interaction.Input
{
/// <summary>
/// A set of constants that are passed to each child of a Hand modifier tree from the root DataSource.
/// </summary>
public class HandDataSourceConfig
{
public Handedness Handedness { get; set; }
public ITrackingToWorldTransformer TrackingToWorldTransformer { get; set; }
public HandSkeleton HandSkeleton { get; set; }
public IDataSource<HmdDataAsset, HmdDataSourceConfig> HmdData { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cf1f3c380e869844ba59339cad4a325c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,145 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using UnityEngine;
namespace Oculus.Interaction.Input
{
public class HandJointCache
{
private Pose[] _localPoses = new Pose[Constants.NUM_HAND_JOINTS];
private Pose[] _posesFromWrist = new Pose[Constants.NUM_HAND_JOINTS];
private Pose[] _worldPoses = new Pose[Constants.NUM_HAND_JOINTS];
private ReadOnlyHandJointPoses _posesFromWristCollection;
private ReadOnlyHandJointPoses _localPosesCollection;
private IReadOnlyHandSkeletonJointList _originalJoints;
private int _dirtyWorldJoints = 0;
private int _dirtyWristJoints = 0;
public int LocalDataVersion { get; private set; } = -1;
public HandJointCache(IReadOnlyHandSkeleton handSkeleton)
{
LocalDataVersion = -1;
_posesFromWrist[0] = Pose.identity;
_posesFromWristCollection = new ReadOnlyHandJointPoses(_posesFromWrist);
_localPosesCollection = new ReadOnlyHandJointPoses(_localPoses);
_originalJoints = handSkeleton.Joints;
}
public void Update(HandDataAsset data, int dataVersion)
{
_dirtyWorldJoints = _dirtyWristJoints = (1 << (int)HandJointId.HandEnd) - 1; //set all dirty
if (!data.IsDataValidAndConnected)
{
return;
}
LocalDataVersion = dataVersion;
UpdateAllLocalPoses(data);
}
public bool GetAllLocalPoses(out ReadOnlyHandJointPoses localJointPoses)
{
localJointPoses = _localPosesCollection;
return _posesFromWristCollection.Count > 0;
}
public bool GetAllPosesFromWrist(out ReadOnlyHandJointPoses jointPosesFromWrist)
{
UpdateAllPosesFromWrist();
jointPosesFromWrist = _posesFromWristCollection;
return _posesFromWristCollection.Count > 0;
}
public Pose LocalJointPose(HandJointId jointid)
{
return _localPoses[(int)jointid];
}
public Pose PoseFromWrist(HandJointId jointid)
{
Pose pose = _posesFromWrist[(int)jointid];
UpdateWristJoint(jointid, ref pose);
return pose;
}
public Pose WorldJointPose(HandJointId jointid, Pose rootPose, float handScale)
{
int jointIndex = (int)jointid;
if ((_dirtyWorldJoints & (1 << jointIndex)) != 0) //its dirty
{
Pose wristPose = Pose.identity;
UpdateWristJoint(jointid, ref wristPose);
PoseUtils.Multiply(_localPoses[0], wristPose, ref _worldPoses[jointIndex]);
_worldPoses[jointIndex].position *= handScale;
_worldPoses[jointIndex].Postmultiply(rootPose);
_dirtyWorldJoints = _dirtyWorldJoints & ~(1 << jointIndex); //set clean
}
return _worldPoses[jointIndex];
}
private void UpdateAllLocalPoses(HandDataAsset data)
{
for (int i = 0; i < Constants.NUM_HAND_JOINTS; ++i)
{
HandSkeletonJoint originalJoint = _originalJoints[i];
_localPoses[i].position = originalJoint.pose.position;
_localPoses[i].rotation = data.Joints[i];
}
}
private void UpdateAllPosesFromWrist()
{
if (_dirtyWristJoints == 0) //its completely clean
{
return;
}
for (int jointIndex = 0; jointIndex < Constants.NUM_HAND_JOINTS; ++jointIndex)
{
if ((_dirtyWristJoints & (1 << jointIndex)) == 0) //its clean
{
continue;
}
HandSkeletonJoint originalJoint = _originalJoints[jointIndex];
if (originalJoint.parent >= 0)
{
PoseUtils.Multiply(_posesFromWrist[originalJoint.parent],
_localPoses[jointIndex], ref _posesFromWrist[jointIndex]);
}
}
_dirtyWristJoints = 0; //set all clean
}
private void UpdateWristJoint(HandJointId jointid, ref Pose pose)
{
int jointIndex = (int)jointid;
if ((_dirtyWristJoints & (1 << jointIndex)) != 0)// its dirty
{
if (jointid > HandJointId.HandWristRoot)
{
UpdateWristJoint((HandJointId)_originalJoints[jointIndex].parent, ref pose);
PoseUtils.Multiply(pose, _localPoses[jointIndex], ref _posesFromWrist[jointIndex]);
}
_dirtyWristJoints = _dirtyWristJoints & ~(1 << jointIndex); //set clean
}
pose.CopyFrom(_posesFromWrist[jointIndex]);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f06ae507a1989e04daeeedc9859327ff
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,245 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Primitive type serialization
/// </summary>
namespace Oculus.Interaction.Input
{
public static class Constants
{
public const int NUM_HAND_JOINTS = (int)HandJointId.HandEnd;
public const int NUM_FINGERS = 5;
}
public enum Handedness
{
Left = 0,
Right = 1,
}
public enum HandFinger
{
Thumb = 0,
Index = 1,
Middle = 2,
Ring = 3,
Pinky = 4,
}
[Flags]
public enum HandFingerFlags
{
None = 0,
Thumb = 1 << 0,
Index = 1 << 1,
Middle = 1 << 2,
Ring = 1 << 3,
Pinky = 1 << 4,
All = (1 << 5) - 1
}
[Flags]
public enum HandFingerJointFlags
{
None = 0,
Thumb0 = 1 << HandJointId.HandThumb0,
Thumb1 = 1 << HandJointId.HandThumb1,
Thumb2 = 1 << HandJointId.HandThumb2,
Thumb3 = 1 << HandJointId.HandThumb3,
Index1 = 1 << HandJointId.HandIndex1,
Index2 = 1 << HandJointId.HandIndex2,
Index3 = 1 << HandJointId.HandIndex3,
Middle1 = 1 << HandJointId.HandMiddle1,
Middle2 = 1 << HandJointId.HandMiddle2,
Middle3 = 1 << HandJointId.HandMiddle3,
Ring1 = 1 << HandJointId.HandRing1,
Ring2 = 1 << HandJointId.HandRing2,
Ring3 = 1 << HandJointId.HandRing3,
Pinky0 = 1 << HandJointId.HandPinky0,
Pinky1 = 1 << HandJointId.HandPinky1,
Pinky2 = 1 << HandJointId.HandPinky2,
Pinky3 = 1 << HandJointId.HandPinky3,
}
public static class HandFingerUtils
{
public static HandFingerFlags ToFlags(HandFinger handFinger)
{
return (HandFingerFlags)(1 << (int)handFinger);
}
}
public enum HandJointId
{
Invalid = -1,
// hand bones
HandStart = 0,
HandWristRoot = HandStart + 0, // root frame of the hand, where the wrist is located
HandForearmStub = HandStart + 1, // frame for user's forearm
HandThumb0 = HandStart + 2, // thumb trapezium bone
HandThumb1 = HandStart + 3, // thumb metacarpal bone
HandThumb2 = HandStart + 4, // thumb proximal phalange bone
HandThumb3 = HandStart + 5, // thumb distal phalange bone
HandIndex1 = HandStart + 6, // index proximal phalange bone
HandIndex2 = HandStart + 7, // index intermediate phalange bone
HandIndex3 = HandStart + 8, // index distal phalange bone
HandMiddle1 = HandStart + 9, // middle proximal phalange bone
HandMiddle2 = HandStart + 10, // middle intermediate phalange bone
HandMiddle3 = HandStart + 11, // middle distal phalange bone
HandRing1 = HandStart + 12, // ring proximal phalange bone
HandRing2 = HandStart + 13, // ring intermediate phalange bone
HandRing3 = HandStart + 14, // ring distal phalange bone
HandPinky0 = HandStart + 15, // pinky metacarpal bone
HandPinky1 = HandStart + 16, // pinky proximal phalange bone
HandPinky2 = HandStart + 17, // pinky intermediate phalange bone
HandPinky3 = HandStart + 18, // pinky distal phalange bone
HandMaxSkinnable = HandStart + 19,
// Bone tips are position only.
// They are not used for skinning but are useful for hit-testing.
// NOTE: HandThumbTip == HandMaxSkinnable since the extended tips need to be contiguous
HandThumbTip = HandMaxSkinnable + 0, // tip of the thumb
HandIndexTip = HandMaxSkinnable + 1, // tip of the index finger
HandMiddleTip = HandMaxSkinnable + 2, // tip of the middle finger
HandRingTip = HandMaxSkinnable + 3, // tip of the ring finger
HandPinkyTip = HandMaxSkinnable + 4, // tip of the pinky
HandEnd = HandMaxSkinnable + 5,
}
public class HandJointUtils
{
public static List<HandJointId[]> FingerToJointList = new List<HandJointId[]>()
{
new[] {HandJointId.HandThumb0,HandJointId.HandThumb1,HandJointId.HandThumb2,HandJointId.HandThumb3},
new[] {HandJointId.HandIndex1, HandJointId.HandIndex2, HandJointId.HandIndex3},
new[] {HandJointId.HandMiddle1, HandJointId.HandMiddle2, HandJointId.HandMiddle3},
new[] {HandJointId.HandRing1,HandJointId.HandRing2,HandJointId.HandRing3},
new[] {HandJointId.HandPinky0, HandJointId.HandPinky1, HandJointId.HandPinky2, HandJointId.HandPinky3}
};
public static List<HandJointId> JointIds = new List<HandJointId>()
{
HandJointId.HandIndex1,
HandJointId.HandIndex2,
HandJointId.HandIndex3,
HandJointId.HandMiddle1,
HandJointId.HandMiddle2,
HandJointId.HandMiddle3,
HandJointId.HandRing1,
HandJointId.HandRing2,
HandJointId.HandRing3,
HandJointId.HandPinky0,
HandJointId.HandPinky1,
HandJointId.HandPinky2,
HandJointId.HandPinky3,
HandJointId.HandThumb0,
HandJointId.HandThumb1,
HandJointId.HandThumb2,
HandJointId.HandThumb3
};
private static readonly HandJointId[] _handFingerProximals =
{
HandJointId.HandThumb2, HandJointId.HandIndex1, HandJointId.HandMiddle1,
HandJointId.HandRing1, HandJointId.HandPinky1
};
public static HandJointId GetHandFingerTip(HandFinger finger)
{
return HandJointId.HandMaxSkinnable + (int)finger;
}
/// <summary>
/// Returns the "proximal" JointId for the given finger.
/// This is commonly known as the Knuckle.
/// For fingers, proximal is the join with index 1; eg HandIndex1.
/// For thumb, proximal is the joint with index 2; eg HandThumb2.
/// </summary>
public static HandJointId GetHandFingerProximal(HandFinger finger)
{
return _handFingerProximals[(int)finger];
}
}
public struct HandSkeletonJoint
{
/// <summary>
/// Id of the parent joint in the skeleton hierarchy. Must always have a lower index than
/// this joint.
/// </summary>
public int parent;
/// <summary>
/// Stores the pose of the joint, in local space.
/// </summary>
public Pose pose;
}
public interface IReadOnlyHandSkeletonJointList
{
ref readonly HandSkeletonJoint this[int jointId] { get; }
}
public interface IReadOnlyHandSkeleton
{
IReadOnlyHandSkeletonJointList Joints { get; }
}
public interface ICopyFrom<in TSelfType>
{
void CopyFrom(TSelfType source);
}
public class ReadOnlyHandJointPoses : IReadOnlyList<Pose>
{
private Pose[] _poses;
public ReadOnlyHandJointPoses(Pose[] poses)
{
_poses = poses;
}
public IEnumerator<Pose> GetEnumerator()
{
foreach (var pose in _poses)
{
yield return pose;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public static ReadOnlyHandJointPoses Empty { get; } = new ReadOnlyHandJointPoses(Array.Empty<Pose>());
public int Count => _poses.Length;
public Pose this[int index] => _poses[index];
public ref readonly Pose this[HandJointId index] => ref _poses[(int)index];
}
public class HandSkeleton : IReadOnlyHandSkeleton, IReadOnlyHandSkeletonJointList
{
public HandSkeletonJoint[] joints = new HandSkeletonJoint[Constants.NUM_HAND_JOINTS];
public IReadOnlyHandSkeletonJointList Joints => this;
public ref readonly HandSkeletonJoint this[int jointId] => ref joints[jointId];
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3140fee102ed8c2489e5442c16b1b36f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,150 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using UnityEngine;
using UnityEngine.Assertions;
namespace Oculus.Interaction.Input
{
/// <summary>
/// HandRef is a utility component that delegates all of its IHand implementation
/// to the provided Hand object.
/// </summary>
public class HandRef : MonoBehaviour, IHand, IActiveState
{
[SerializeField, Interface(typeof(IHand))]
private MonoBehaviour _hand;
public IHand Hand { get; private set; }
public Handedness Handedness => Hand.Handedness;
public bool IsConnected => Hand.IsConnected;
public bool IsHighConfidence => Hand.IsHighConfidence;
public bool IsDominantHand => Hand.IsDominantHand;
public float Scale => Hand.Scale;
public bool IsPointerPoseValid => Hand.IsPointerPoseValid;
public bool IsTrackedDataValid => Hand.IsTrackedDataValid;
public bool IsCenterEyePoseValid => Hand.IsCenterEyePoseValid;
public Transform TrackingToWorldSpace => Hand.TrackingToWorldSpace;
public int CurrentDataVersion => Hand.CurrentDataVersion;
public event Action HandUpdated
{
add => Hand.HandUpdated += value;
remove => Hand.HandUpdated -= value;
}
public bool Active => IsConnected;
protected virtual void Awake()
{
Hand = _hand as IHand;
}
protected virtual void Start()
{
Assert.IsNotNull(Hand);
}
public bool GetFingerIsPinching(HandFinger finger)
{
return Hand.GetFingerIsPinching(finger);
}
public bool GetIndexFingerIsPinching()
{
return Hand.GetIndexFingerIsPinching();
}
public bool GetPointerPose(out Pose pose)
{
return Hand.GetPointerPose(out pose);
}
public bool GetJointPose(HandJointId handJointId, out Pose pose)
{
return Hand.GetJointPose(handJointId, out pose);
}
public bool GetJointPoseLocal(HandJointId handJointId, out Pose pose)
{
return Hand.GetJointPoseLocal(handJointId, out pose);
}
public bool GetJointPosesLocal(out ReadOnlyHandJointPoses jointPosesLocal)
{
return Hand.GetJointPosesLocal(out jointPosesLocal);
}
public bool GetJointPoseFromWrist(HandJointId handJointId, out Pose pose)
{
return Hand.GetJointPoseFromWrist(handJointId, out pose);
}
public bool GetJointPosesFromWrist(out ReadOnlyHandJointPoses jointPosesFromWrist)
{
return Hand.GetJointPosesFromWrist(out jointPosesFromWrist);
}
public bool GetPalmPoseLocal(out Pose pose)
{
return Hand.GetPalmPoseLocal(out pose);
}
public bool GetFingerIsHighConfidence(HandFinger finger)
{
return Hand.GetFingerIsHighConfidence(finger);
}
public float GetFingerPinchStrength(HandFinger finger)
{
return Hand.GetFingerPinchStrength(finger);
}
public bool GetRootPose(out Pose pose)
{
return Hand.GetRootPose(out pose);
}
public bool GetCenterEyePose(out Pose pose)
{
return Hand.GetCenterEyePose(out pose);
}
public bool GetHandAspect<TComponent>(out TComponent foundComponent) where TComponent : class
{
return Hand.GetHandAspect(out foundComponent);
}
#region Inject
public void InjectAllHandRef(IHand hand)
{
InjectHand(hand);
}
public void InjectHand(IHand hand)
{
_hand = hand as MonoBehaviour;
Hand = hand;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b14164f8f23faae4293baeb84485b3d6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,157 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using UnityEngine;
using System;
namespace Oculus.Interaction.Input
{
public interface IHand
{
Handedness Handedness { get; }
bool IsConnected { get; }
/// <summary>
/// The hand is connected and tracked, and the root pose's tracking data is marked as
/// high confidence.
/// If this is true, then it implies that IsConnected and IsRootPoseValid are also true,
/// so they don't need to be checked in addition to this.
/// </summary>
bool IsHighConfidence { get; }
bool IsDominantHand { get; }
float Scale { get; }
bool GetFingerIsPinching(HandFinger finger);
bool GetIndexFingerIsPinching();
/// <summary>
/// Will return true if a pointer pose is available, that can be retrieved via
/// <see cref="GetPointerPose"/>
/// </summary>
bool IsPointerPoseValid { get; }
/// <summary>
/// Attempts to calculate the pose that can be used as a root for raycasting, in world space
/// Returns false if there is no valid tracking data.
/// </summary>
bool GetPointerPose(out Pose pose);
/// <summary>
/// Attempts to calculate the pose of the requested hand joint, in world space.
/// Returns false if the skeleton is not yet initialized, or there is no valid
/// tracking data.
/// </summary>
bool GetJointPose(HandJointId handJointId, out Pose pose);
/// <summary>
/// Attempts to calculate the pose of the requested hand joint, in local space.
/// Returns false if the skeleton is not yet initialized, or there is no valid
/// tracking data.
/// </summary>
bool GetJointPoseLocal(HandJointId handJointId, out Pose pose);
/// <summary>
/// Returns an array containing the local pose of each joint. The poses
/// do not have the root pose applied, nor the hand scale. It is in the same coordinate
/// system as the hand skeleton.
/// </summary>
/// <param name="localJointPoses">The array with the local joint poses.
/// It will be empty if no poses where found</param>
/// <returns>
/// True if the poses collection was correctly populated. False otherwise.
/// </returns>
bool GetJointPosesLocal(out ReadOnlyHandJointPoses localJointPoses);
/// <summary>
/// Attempts to calculate the pose of the requested hand joint relative to the wrist.
/// Returns false if the skeleton is not yet initialized, or there is no valid
/// tracking data.
/// </summary>
bool GetJointPoseFromWrist(HandJointId handJointId, out Pose pose);
/// <summary>
/// Returns an array containing the pose of each joint relative to the wrist. The poses
/// do not have the root pose applied, nor the hand scale. It is in the same coordinate
/// system as the hand skeleton.
/// </summary>
/// <param name="jointPosesFromWrist">The array with the joint poses from the wrist.
/// It will be empty if no poses where found</param>
/// <returns>
/// True if the poses collection was correctly populated. False otherwise.
/// </returns>
bool GetJointPosesFromWrist(out ReadOnlyHandJointPoses jointPosesFromWrist);
/// <summary>
/// Obtains palm pose in local space.
/// </summary>
/// <param name="pose">The pose to populate</param>
/// <returns>
/// True if pose was obtained.
/// </returns>
bool GetPalmPoseLocal(out Pose pose);
bool GetFingerIsHighConfidence(HandFinger finger);
float GetFingerPinchStrength(HandFinger finger);
/// <summary>
/// True if the hand is currently tracked, thus tracking poses are available for the hand
/// root and finger joints.
/// This property does not indicate pointing pose validity, which has its own property:
/// <see cref="IsPointerPoseValid"/>.
/// </summary>
bool IsTrackedDataValid { get; }
/// <summary>
/// Gets the root pose of the wrist, in world space.
/// Will return true if a pose was available; false otherwise.
/// Confidence level of the pose is exposed via <see cref="IsHighConfidence"/>.
/// </summary>
bool GetRootPose(out Pose pose);
/// <summary>
/// Will return true if an HMD Center Eye pose available, that can be retrieved via
/// <see cref="GetCenterEyePose"/>
/// </summary>
bool IsCenterEyePoseValid { get; }
/// <summary>
/// Gets the pose of the center eye (HMD), in world space.
/// Will return true if a pose was available; false otherwise.
/// </summary>
bool GetCenterEyePose(out Pose pose);
/// <summary>
/// The transform that was applied to all tracking space poses to convert them to world
/// space.
/// </summary>
Transform TrackingToWorldSpace { get; }
/// <summary>
/// Incremented every time the source tracking or state data changes.
/// </summary>
int CurrentDataVersion { get; }
/// <summary>
/// An Aspect provides additional functionality on top of what the HandState provides.
/// The underlying hand is responsible for finding the most appropriate component.
/// It is usually, but not necessarily, located within the same GameObject as the
/// underlying hand.
/// For example, this method can be used to source the SkinnedMeshRenderer representing the
/// hand, if one exists.
/// <returns>true if an aspect of the requested type was found, false otherwise</returns>
/// </summary>
bool GetHandAspect<TComponent>(out TComponent foundComponent) where TComponent : class;
event Action HandUpdated;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e500f060fe544c21b9b8892fb57511e1
timeCreated: 1630518667

View File

@@ -0,0 +1,19 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
namespace Oculus.Interaction.Input
{
public interface IHandSkeletonProvider
{
HandSkeleton this[Handedness handedness] { get; }
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: be3974c2b13042ecb43558bf99c1603b
timeCreated: 1629410878

View File

@@ -0,0 +1,131 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Oculus.Interaction.Input
{
public class JointLock
{
public HandJointId JointId;
public bool Locked;
public Quaternion SourceRotation;
public Quaternion AnimationStartRotation;
public Quaternion AnimationTargetRotation;
public float AnimationTime = 0f;
public Quaternion OutputRotation;
}
public class JointLocking
{
public static void Initialize(HandDataAsset data,
out Dictionary<HandJointId, JointLock> jointMap)
{
jointMap = new Dictionary<HandJointId, JointLock>();
foreach (HandJointId jointId in HandJointUtils.JointIds)
{
JointLock jointLock = new JointLock()
{
JointId = jointId,
SourceRotation = data.Joints[(int)jointId],
AnimationTargetRotation = data.Joints[(int)jointId],
OutputRotation = data.Joints[(int)jointId],
AnimationTime = 0f,
Locked = false
};
jointMap.Add(jointId, jointLock);
}
}
public static void UpdateLockedJoints(
HandDataAsset data,
Dictionary<HandJointId, JointLock> jointMap,
float totalEaseTime,
AnimationCurve animationCurve)
{
foreach (JointLock angleLock in jointMap.Values)
{
angleLock.SourceRotation = data.Joints[(int)angleLock.JointId];
if (!angleLock.Locked)
{
angleLock.AnimationTargetRotation = data.Joints[(int)angleLock.JointId];
}
angleLock.AnimationTime = Math.Min(angleLock.AnimationTime + Time.deltaTime /
totalEaseTime, 1.0f);
float easeTime = animationCurve.Evaluate(angleLock.AnimationTime);
angleLock.OutputRotation = Quaternion.Slerp(angleLock.AnimationStartRotation,
angleLock.AnimationTargetRotation, easeTime);
data.Joints[(int)angleLock.JointId] = angleLock.OutputRotation;
}
}
public static void LockJoint(
HandJointId jointId,
Quaternion targetRotation,
Dictionary<HandJointId, JointLock> jointMap)
{
if (jointMap[jointId].Locked)
{
return;
}
jointMap[jointId].Locked = true;
jointMap[jointId].AnimationTargetRotation = targetRotation;
jointMap[jointId].AnimationStartRotation = jointMap[jointId].OutputRotation;
jointMap[jointId].AnimationTime = 0f;
}
public static void UnlockJoint(HandJointId jointId,
Dictionary<HandJointId, JointLock> jointMap)
{
if (!jointMap[jointId].Locked) return;
jointMap[jointId].Locked = false;
jointMap[jointId].AnimationStartRotation = jointMap[jointId].OutputRotation;
jointMap[jointId].AnimationTime = 0f;
}
public static void UnlockAllJoints(Dictionary<HandJointId, JointLock> jointMap)
{
foreach (var jointId in jointMap.Keys)
{
UnlockJoint(jointId, jointMap);
}
}
public static void LockByFingerId(HandFinger finger,
Dictionary<HandJointId, JointLock> jointMap)
{
HandJointId[] joints = HandJointUtils.FingerToJointList[(int)finger];
foreach (var jointId in joints)
{
LockJoint(jointId, jointMap[jointId].SourceRotation, jointMap);
}
}
public static void UnlockByFingerId(HandFinger finger,
Dictionary<HandJointId, JointLock> jointMap)
{
HandJointId[] joints = HandJointUtils.FingerToJointList[(int)finger];
foreach (var jointId in joints)
{
UnlockJoint(jointId, jointMap);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d043893ca7b199f42a4d1c3785a23d02
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,35 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using UnityEngine;
namespace Oculus.Interaction.Input
{
public interface ITrackingToWorldTransformer
{
Transform Transform { get; }
/// <summary>
/// Converts a tracking space pose to a pose in in Unity's world coordinate space
/// (i.e. teleportation applied)
/// </summary>
Pose ToWorldPose(Pose poseRh);
/// <summary>
/// Converts a world space pose in Unity's coordinate space
/// to a pose in tracking space (i.e. no teleportation applied)
/// </summary>
Pose ToTrackingPose(in Pose worldPose);
Quaternion WorldToTrackingWristJointFixup { get; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cf17380a7dbcc344dbdbdbc163933e4a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 96e4e4f16838b9548b5c62249aa3b023
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,114 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using UnityEngine;
namespace Oculus.Interaction.Input
{
public class AnimatedHandOVR : MonoBehaviour
{
public const string ANIM_LAYER_NAME_POINT = "Point Layer";
public const string ANIM_LAYER_NAME_THUMB = "Thumb Layer";
public const string ANIM_PARAM_NAME_FLEX = "Flex";
public const float INPUT_RATE_CHANGE = 20.0f;
[SerializeField]
private OVRInput.Controller _controller = OVRInput.Controller.None;
[SerializeField]
private Animator _animator = null;
private int _animLayerIndexThumb = -1;
private int _animLayerIndexPoint = -1;
private int _animParamIndexFlex = -1;
private bool _isPointing = false;
private bool _isGivingThumbsUp = false;
private float _pointBlend = 0.0f;
private float _thumbsUpBlend = 0.0f;
protected virtual void Start()
{
_animLayerIndexPoint = _animator.GetLayerIndex(ANIM_LAYER_NAME_POINT);
_animLayerIndexThumb = _animator.GetLayerIndex(ANIM_LAYER_NAME_THUMB);
_animParamIndexFlex = Animator.StringToHash(ANIM_PARAM_NAME_FLEX);
}
protected virtual void Update()
{
UpdateCapTouchStates();
_pointBlend = InputValueRateChange(_isPointing, _pointBlend);
_thumbsUpBlend = InputValueRateChange(_isGivingThumbsUp, _thumbsUpBlend);
UpdateAnimStates();
}
private void UpdateCapTouchStates()
{
_isPointing = !OVRInput.Get(OVRInput.NearTouch.PrimaryIndexTrigger, _controller);
_isGivingThumbsUp = !OVRInput.Get(OVRInput.NearTouch.PrimaryThumbButtons, _controller);
}
/// <summary>
/// Based on InputValueRateChange from OVR Samples it ensures
/// the animation blending happens with controlled timing instead of instantly
/// </summary>
/// <param name="isDown">Direction of the animation</param>
/// <param name="value">Value to change</param>
/// <returns>The input value increased or decreased at a fixed rate</returns>
private float InputValueRateChange(bool isDown, float value)
{
float rateDelta = Time.deltaTime * INPUT_RATE_CHANGE;
float sign = isDown ? 1.0f : -1.0f;
return Mathf.Clamp01(value + rateDelta * sign);
}
private void UpdateAnimStates()
{
// Flex
// blend between open hand and fully closed fist
float flex = OVRInput.Get(OVRInput.Axis1D.PrimaryHandTrigger, _controller);
_animator.SetFloat(_animParamIndexFlex, flex);
// Point
_animator.SetLayerWeight(_animLayerIndexPoint, _pointBlend);
// Thumbs up
_animator.SetLayerWeight(_animLayerIndexThumb, _thumbsUpBlend);
float pinch = OVRInput.Get(OVRInput.Axis1D.PrimaryIndexTrigger, _controller);
_animator.SetFloat("Pinch", pinch);
}
#region Inject
public void InjectAllAnimatedHandOVR(OVRInput.Controller controller, Animator animator)
{
InjectController(controller);
InjectAnimator(animator);
}
public void InjectController(OVRInput.Controller controller)
{
_controller = controller;
}
public void InjectAnimator(Animator animator)
{
_animator = animator;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2864da2f393a3e948bb12ec4ac9b1782
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,283 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Serialization;
namespace Oculus.Interaction.Input
{
struct UsageMapping
{
public UsageMapping(ControllerButtonUsage usage, OVRInput.Touch touch)
{
Usage = usage;
Touch = touch;
Button = OVRInput.Button.None;
}
public UsageMapping(ControllerButtonUsage usage, OVRInput.Button button)
{
Usage = usage;
Touch = OVRInput.Touch.None;
Button = button;
}
public bool IsTouch => Touch != OVRInput.Touch.None;
public bool IsButton => Button != OVRInput.Button.None;
public ControllerButtonUsage Usage { get; }
public OVRInput.Touch Touch { get; }
public OVRInput.Button Button { get; }
}
/// <summary>
/// Returns the Pointer Pose for the active controller model
/// as found in the official prefabs.
/// This point is usually located at the front tip of the controller.
/// </summary>
struct OVRPointerPoseSelector
{
private static readonly Pose[] QUEST1_POINTERS = new Pose[2]
{
new Pose(new Vector3(-0.00779999979f,-0.00410000002f,0.0375000015f),
Quaternion.Euler(359.209534f, 6.45196056f, 6.95544577f)),
new Pose(new Vector3(0.00779999979f,-0.00410000002f,0.0375000015f),
Quaternion.Euler(359.209534f, 353.548035f, 353.044556f))
};
private static readonly Pose[] QUEST2_POINTERS = new Pose[2]
{
new Pose(new Vector3(0.00899999961f, -0.00321028521f, 0.030869998f),
Quaternion.Euler(359.209534f, 6.45196056f, 6.95544577f)),
new Pose(new Vector3(-0.00899999961f, -0.00321028521f, 0.030869998f),
Quaternion.Euler(359.209534f, 353.548035f, 353.044556f))
};
public Pose LocalPointerPose { get; private set; }
public OVRPointerPoseSelector(Handedness handedness)
{
OVRPlugin.SystemHeadset headset = OVRPlugin.GetSystemHeadsetType();
switch (headset)
{
case OVRPlugin.SystemHeadset.Oculus_Quest_2:
case OVRPlugin.SystemHeadset.Oculus_Link_Quest_2:
LocalPointerPose = QUEST2_POINTERS[(int)handedness];
break;
default:
LocalPointerPose = QUEST1_POINTERS[(int)handedness];
break;
}
}
}
public class FromOVRControllerDataSource : DataSource<ControllerDataAsset, ControllerDataSourceConfig>
{
[Header("OVR Data Source")]
[SerializeField, Interface(typeof(IOVRCameraRigRef))]
private MonoBehaviour _cameraRigRef;
[Header("Shared Configuration")]
[SerializeField]
private Handedness _handedness;
[SerializeField, Interface(typeof(ITrackingToWorldTransformer))]
private MonoBehaviour _trackingToWorldTransformer;
private ITrackingToWorldTransformer TrackingToWorldTransformer;
[SerializeField, Interface(typeof(IDataSource<HmdDataAsset, HmdDataSourceConfig>))]
private MonoBehaviour _hmdData;
private IDataSource<HmdDataAsset, HmdDataSourceConfig> HmdData;
private readonly ControllerDataAsset _controllerDataAsset = new ControllerDataAsset();
private OVRInput.Controller _ovrController;
private Transform _ovrControllerAnchor;
private ControllerDataSourceConfig _config;
private OVRPointerPoseSelector _pointerPoseSelector;
public IOVRCameraRigRef CameraRigRef { get; private set; }
#region OVR Controller Mappings
// Mappings from Unity XR CommonUsage to Oculus Button/Touch.
private static readonly UsageMapping[] ControllerUsageMappings =
{
new UsageMapping(ControllerButtonUsage.PrimaryButton, OVRInput.Button.One),
new UsageMapping(ControllerButtonUsage.PrimaryTouch, OVRInput.Touch.One),
new UsageMapping(ControllerButtonUsage.SecondaryButton, OVRInput.Button.Two),
new UsageMapping(ControllerButtonUsage.SecondaryTouch, OVRInput.Touch.Two),
new UsageMapping(ControllerButtonUsage.GripButton,
OVRInput.Button.PrimaryHandTrigger),
new UsageMapping(ControllerButtonUsage.TriggerButton,
OVRInput.Button.PrimaryIndexTrigger),
new UsageMapping(ControllerButtonUsage.MenuButton, OVRInput.Button.Start),
new UsageMapping(ControllerButtonUsage.Primary2DAxisClick,
OVRInput.Button.PrimaryThumbstick),
new UsageMapping(ControllerButtonUsage.Primary2DAxisTouch,
OVRInput.Touch.PrimaryThumbstick),
new UsageMapping(ControllerButtonUsage.Thumbrest, OVRInput.Touch.PrimaryThumbRest)
};
#endregion
protected void Awake()
{
TrackingToWorldTransformer = _trackingToWorldTransformer as ITrackingToWorldTransformer;
HmdData = _hmdData as IDataSource<HmdDataAsset, HmdDataSourceConfig>;
CameraRigRef = _cameraRigRef as IOVRCameraRigRef;
}
protected override void Start()
{
base.Start();
Assert.IsNotNull(CameraRigRef);
Assert.IsNotNull(TrackingToWorldTransformer);
Assert.IsNotNull(HmdData);
if (_handedness == Handedness.Left)
{
Assert.IsNotNull(CameraRigRef.LeftController);
_ovrControllerAnchor = CameraRigRef.LeftController;
_ovrController = OVRInput.Controller.LTouch;
}
else
{
Assert.IsNotNull(CameraRigRef.RightController);
_ovrControllerAnchor = CameraRigRef.RightController;
_ovrController = OVRInput.Controller.RTouch;
}
_pointerPoseSelector = new OVRPointerPoseSelector(_handedness);
}
private void InitConfig()
{
if (_config != null)
{
return;
}
_config = new ControllerDataSourceConfig()
{
Handedness = _handedness,
TrackingToWorldTransformer = TrackingToWorldTransformer,
HmdData = HmdData
};
}
protected override void UpdateData()
{
var worldToTrackingSpace = CameraRigRef.CameraRig.transform.worldToLocalMatrix;
Transform ovrController = _ovrControllerAnchor;
_controllerDataAsset.IsDataValid = true;
_controllerDataAsset.IsConnected =
(OVRInput.GetConnectedControllers() & _ovrController) > 0;
if (!_controllerDataAsset.IsConnected)
{
// revert state fields to their defaults
_controllerDataAsset.IsTracked = default;
_controllerDataAsset.ButtonUsageMask = default;
_controllerDataAsset.RootPoseOrigin = default;
return;
}
_controllerDataAsset.IsTracked = true;
// Update button usages
_controllerDataAsset.ButtonUsageMask = ControllerButtonUsage.None;
OVRInput.Controller controllerMask = _ovrController;
foreach (UsageMapping mapping in ControllerUsageMappings)
{
bool usageActive;
if (mapping.IsTouch)
{
usageActive = OVRInput.Get(mapping.Touch, controllerMask);
}
else
{
Assert.IsTrue(mapping.IsButton);
usageActive = OVRInput.Get(mapping.Button, controllerMask);
}
if (usageActive)
{
_controllerDataAsset.ButtonUsageMask |= mapping.Usage;
}
}
// Update poses
// Convert controller pose from world to tracking space.
Pose worldRoot = new Pose(ovrController.position, ovrController.rotation);
_controllerDataAsset.RootPose.position = worldToTrackingSpace.MultiplyPoint3x4(worldRoot.position);
_controllerDataAsset.RootPose.rotation = worldToTrackingSpace.rotation * worldRoot.rotation;
_controllerDataAsset.RootPoseOrigin = PoseOrigin.RawTrackedPose;
// Convert controller pointer pose from local to tracking space.
Pose pointerPose = PoseUtils.Multiply(worldRoot, _pointerPoseSelector.LocalPointerPose);
_controllerDataAsset.PointerPose.position = worldToTrackingSpace.MultiplyPoint3x4(pointerPose.position);
_controllerDataAsset.PointerPose.rotation = worldToTrackingSpace.rotation * pointerPose.rotation;
_controllerDataAsset.PointerPoseOrigin = PoseOrigin.RawTrackedPose;
}
protected override ControllerDataAsset DataAsset => _controllerDataAsset;
// It is important that this creates an object on the fly, as it is possible it is called
// from other components Awake methods.
public override ControllerDataSourceConfig Config
{
get
{
if (_config == null)
{
InitConfig();
}
return _config;
}
}
#region Inject
public void InjectAllFromOVRControllerDataSource(UpdateModeFlags updateMode, IDataSource updateAfter,
Handedness handedness, ITrackingToWorldTransformer trackingToWorldTransformer,
IDataSource<HmdDataAsset, HmdDataSourceConfig> hmdData)
{
base.InjectAllDataSource(updateMode, updateAfter);
InjectHandedness(handedness);
InjectTrackingToWorldTransformer(trackingToWorldTransformer);
InjectHmdData(hmdData);
}
public void InjectHandedness(Handedness handedness)
{
_handedness = handedness;
}
public void InjectTrackingToWorldTransformer(ITrackingToWorldTransformer trackingToWorldTransformer)
{
_trackingToWorldTransformer = trackingToWorldTransformer as MonoBehaviour;
TrackingToWorldTransformer = trackingToWorldTransformer;
}
public void InjectHmdData(IDataSource<HmdDataAsset,HmdDataSourceConfig> hmdData)
{
_hmdData = hmdData as MonoBehaviour;
HmdData = hmdData;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ee6b94f7bc105c24ea3746dc4141a7eb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,270 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Serialization;
namespace Oculus.Interaction.Input
{
public class FromOVRControllerHandDataSource : DataSource<HandDataAsset, HandDataSourceConfig>
{
[SerializeField]
private Transform[] _bones;
[SerializeField]
private AnimationCurve _pinchCurve = AnimationCurve.EaseInOut(0.1f, 0f, 0.9f, 1f);
[SerializeField]
private Vector3 _rootOffset;
[SerializeField]
private Vector3 _rootAngleOffset;
[Header("OVR Data Source")]
[SerializeField, Interface(typeof(IOVRCameraRigRef))]
private MonoBehaviour _cameraRigRef;
private IOVRCameraRigRef CameraRigRef;
[Header("Shared Configuration")]
[SerializeField]
private Handedness _handedness;
[SerializeField, Interface(typeof(ITrackingToWorldTransformer))]
private MonoBehaviour _trackingToWorldTransformer;
private ITrackingToWorldTransformer TrackingToWorldTransformer;
[SerializeField, Interface(typeof(IDataSource<HmdDataAsset, HmdDataSourceConfig>))]
private MonoBehaviour _hmdData;
private IDataSource<HmdDataAsset, HmdDataSourceConfig> HmdData;
private readonly HandDataAsset _handDataAsset = new HandDataAsset();
private OVRInput.Controller _ovrController;
private Transform _ovrControllerAnchor;
private HandDataSourceConfig _config;
private Pose _poseOffset;
public static Quaternion WristFixupRotation { get; } =
new Quaternion(0.0f, 1.0f, 0.0f, 0.0f);
protected override HandDataAsset DataAsset => _handDataAsset;
private HandSkeleton _skeleton;
public override HandDataSourceConfig Config
{
get
{
if (_config == null)
{
InitConfig();
}
return _config;
}
}
protected void Awake()
{
_skeleton = HandSkeletonOVR.CreateSkeletonData(_handedness);
TrackingToWorldTransformer = _trackingToWorldTransformer as ITrackingToWorldTransformer;
HmdData = _hmdData as IDataSource<HmdDataAsset, HmdDataSourceConfig>;
CameraRigRef = _cameraRigRef as IOVRCameraRigRef;
}
protected override void Start()
{
base.Start();
Assert.IsNotNull(CameraRigRef);
Assert.IsNotNull(TrackingToWorldTransformer);
Assert.IsNotNull(HmdData);
if (_handedness == Handedness.Left)
{
Assert.IsNotNull(CameraRigRef.LeftHand);
_ovrControllerAnchor = CameraRigRef.LeftController;
_ovrController = OVRInput.Controller.LTouch;
}
else
{
Assert.IsNotNull(CameraRigRef.RightHand);
_ovrControllerAnchor = CameraRigRef.RightController;
_ovrController = OVRInput.Controller.RTouch;
}
Pose offset = new Pose(_rootOffset, Quaternion.Euler(_rootAngleOffset));
if (_handedness == Handedness.Left)
{
offset.position.x = -offset.position.x;
offset.rotation = Quaternion.Euler(180f, 0f, 0f) * offset.rotation;
}
_poseOffset = offset;
InitConfig();
}
private void UpdateSkeleton()
{
for (int i = 0; i < _skeleton.joints.Length; i++)
{
_skeleton.joints[i].pose.position = _bones[i].localPosition;
_skeleton.joints[i].pose.rotation = _bones[i].localRotation;
}
}
private void InitConfig()
{
if (_config != null)
{
return;
}
UpdateSkeleton();
_config = new HandDataSourceConfig()
{
Handedness = _handedness,
TrackingToWorldTransformer = TrackingToWorldTransformer,
HandSkeleton = _skeleton,
HmdData = HmdData
};
}
protected override void UpdateData()
{
_handDataAsset.IsDataValid = true;
_handDataAsset.IsConnected = (OVRInput.GetConnectedControllers() & _ovrController) > 0;
if (!_handDataAsset.IsConnected)
{
// revert state fields to their defaults
_handDataAsset.IsTracked = default;
_handDataAsset.RootPoseOrigin = default;
_handDataAsset.PointerPoseOrigin = default;
_handDataAsset.IsHighConfidence = default;
for (var fingerIdx = 0; fingerIdx < Constants.NUM_FINGERS; fingerIdx++)
{
_handDataAsset.IsFingerPinching[fingerIdx] = default;
_handDataAsset.IsFingerHighConfidence[fingerIdx] = default;
}
return;
}
_handDataAsset.IsTracked = true;
_handDataAsset.IsHighConfidence = true;
_handDataAsset.HandScale = 1f;
_handDataAsset.IsDominantHand =
OVRInput.GetDominantHand() == OVRInput.Handedness.LeftHanded
&& _handedness == Handedness.Left
|| (OVRInput.GetDominantHand() == OVRInput.Handedness.RightHanded
&& _handedness == Handedness.Right);
float indexStrength = _pinchCurve.Evaluate(OVRInput.Get(OVRInput.Axis1D.PrimaryIndexTrigger, _ovrController));
float gripStrength = _pinchCurve.Evaluate(OVRInput.Get(OVRInput.Axis1D.PrimaryHandTrigger, _ovrController));
_handDataAsset.IsFingerHighConfidence[(int)HandFinger.Thumb] = true;
_handDataAsset.IsFingerPinching[(int)HandFinger.Thumb] = indexStrength >= 1f || gripStrength >= 1f;
_handDataAsset.FingerPinchStrength[(int)HandFinger.Thumb] = Mathf.Max(indexStrength, gripStrength);
_handDataAsset.IsFingerHighConfidence[(int)HandFinger.Index] = true;
_handDataAsset.IsFingerPinching[(int)HandFinger.Index] = indexStrength >= 1f;
_handDataAsset.FingerPinchStrength[(int)HandFinger.Index] = indexStrength;
_handDataAsset.IsFingerHighConfidence[(int)HandFinger.Middle] = true;
_handDataAsset.IsFingerPinching[(int)HandFinger.Middle] = gripStrength >= 1f;
_handDataAsset.FingerPinchStrength[(int)HandFinger.Middle] = gripStrength;
_handDataAsset.IsFingerHighConfidence[(int)HandFinger.Ring] = true;
_handDataAsset.IsFingerPinching[(int)HandFinger.Ring] = gripStrength >= 1f;
_handDataAsset.FingerPinchStrength[(int)HandFinger.Ring] = gripStrength;
_handDataAsset.IsFingerHighConfidence[(int)HandFinger.Pinky] = true;
_handDataAsset.IsFingerPinching[(int)HandFinger.Pinky] = gripStrength >= 1f;
_handDataAsset.FingerPinchStrength[(int)HandFinger.Pinky] = gripStrength;
_handDataAsset.PointerPoseOrigin = PoseOrigin.RawTrackedPose;
_handDataAsset.PointerPose = new Pose(
OVRInput.GetLocalControllerPosition(_ovrController),
OVRInput.GetLocalControllerRotation(_ovrController));
for (int i = 0; i < _bones.Length; i++)
{
_handDataAsset.Joints[i] = _bones[i].localRotation;
}
_handDataAsset.Joints[0] = WristFixupRotation;
// Convert controller pose from world to tracking space.
Pose pose = new Pose(_ovrControllerAnchor.position, _ovrControllerAnchor.rotation);
pose = Config.TrackingToWorldTransformer.ToTrackingPose(pose);
PoseUtils.Multiply(pose, _poseOffset, ref _handDataAsset.Root);
_handDataAsset.RootPoseOrigin = PoseOrigin.RawTrackedPose;
}
#region Inject
public void InjectAllFromOVRControllerHandDataSource(UpdateModeFlags updateMode, IDataSource updateAfter,
Handedness handedness, ITrackingToWorldTransformer trackingToWorldTransformer,
IDataSource<HmdDataAsset, HmdDataSourceConfig> hmdData, Transform[] bones, AnimationCurve pinchCurve,
Vector3 rootOffset, Vector3 rootAngleOffset)
{
base.InjectAllDataSource(updateMode, updateAfter);
InjectHandedness(handedness);
InjectTrackingToWorldTransformer(trackingToWorldTransformer);
InjectHmdData(hmdData);
InjectBones(bones);
InjectPinchCurve(pinchCurve);
InjectRootOffset(rootOffset);
InjectRootAngleOffset(rootAngleOffset);
}
public void InjectHandedness(Handedness handedness)
{
_handedness = handedness;
}
public void InjectTrackingToWorldTransformer(ITrackingToWorldTransformer trackingToWorldTransformer)
{
_trackingToWorldTransformer = trackingToWorldTransformer as MonoBehaviour;
TrackingToWorldTransformer = trackingToWorldTransformer;
}
public void InjectHmdData(IDataSource<HmdDataAsset, HmdDataSourceConfig> hmdData)
{
_hmdData = hmdData as MonoBehaviour;
HmdData = hmdData;
}
public void InjectBones(Transform[] bones)
{
_bones = bones;
}
public void InjectPinchCurve(AnimationCurve pinchCurve)
{
_pinchCurve = pinchCurve;
}
public void InjectRootOffset(Vector3 rootOffset)
{
_rootOffset = rootOffset;
}
public void InjectRootAngleOffset(Vector3 rootAngleOffset)
{
_rootAngleOffset = rootAngleOffset;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: eb7d6cff5f17513488d465cdc4efd298
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,247 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Serialization;
using static OVRSkeleton;
namespace Oculus.Interaction.Input
{
public class FromOVRHandDataSource : DataSource<HandDataAsset, HandDataSourceConfig>
{
[Header("OVR Data Source")]
[SerializeField, Interface(typeof(IOVRCameraRigRef))]
private MonoBehaviour _cameraRigRef;
[Header("Shared Configuration")]
[SerializeField]
private Handedness _handedness;
[SerializeField, Interface(typeof(ITrackingToWorldTransformer))]
private MonoBehaviour _trackingToWorldTransformer;
private ITrackingToWorldTransformer TrackingToWorldTransformer;
[SerializeField, Interface(typeof(IHandSkeletonProvider))]
private MonoBehaviour _handSkeletonProvider;
private IHandSkeletonProvider HandSkeletonProvider;
[SerializeField, Interface(typeof(IDataSource<HmdDataAsset, HmdDataSourceConfig>))]
private MonoBehaviour _hmdData;
private IDataSource<HmdDataAsset, HmdDataSourceConfig> HmdData;
private readonly HandDataAsset _handDataAsset = new HandDataAsset();
private OVRHand _ovrHand;
private OVRInput.Controller _ovrController;
private float _lastHandScale;
private HandDataSourceConfig _config;
private IOVRCameraRigRef CameraRigRef;
protected override HandDataAsset DataAsset => _handDataAsset;
// Wrist rotations that come from OVR need correcting.
public static Quaternion WristFixupRotation { get; } =
new Quaternion(0.0f, 1.0f, 0.0f, 0.0f);
// It is important that this creates an object on the fly, as it is possible it is called
// from other components Start methods.
public override HandDataSourceConfig Config => _config ?? InitConfig();
protected virtual void Awake()
{
TrackingToWorldTransformer = _trackingToWorldTransformer as ITrackingToWorldTransformer;
HmdData = _hmdData as IDataSource<HmdDataAsset, HmdDataSourceConfig>;
CameraRigRef = _cameraRigRef as IOVRCameraRigRef;
HandSkeletonProvider = _handSkeletonProvider as IHandSkeletonProvider;
}
protected override void Start()
{
base.Start();
Assert.IsNotNull(CameraRigRef);
Assert.IsNotNull(TrackingToWorldTransformer);
Assert.IsNotNull(HandSkeletonProvider);
Assert.IsNotNull(HmdData);
if (_handedness == Handedness.Left)
{
_ovrHand = CameraRigRef.LeftHand;
_ovrController = OVRInput.Controller.LHand;
}
else
{
_ovrHand = CameraRigRef.RightHand;
_ovrController = OVRInput.Controller.RHand;
}
}
private HandDataSourceConfig InitConfig()
{
if (_config != null)
{
return _config;
}
_config = new HandDataSourceConfig()
{
Handedness = _handedness,
TrackingToWorldTransformer = TrackingToWorldTransformer,
HandSkeleton = HandSkeletonProvider[_handedness],
HmdData = HmdData
};
return _config;
}
protected override void UpdateData()
{
_handDataAsset.IsDataValid = true;
_handDataAsset.IsConnected =
(OVRInput.GetConnectedControllers() & _ovrController) > 0;
if (_ovrHand != null)
{
var skeletonProvider = (IOVRSkeletonDataProvider)_ovrHand;
var poseData = skeletonProvider.GetSkeletonPoseData();
if (poseData.IsDataValid && poseData.RootScale <= 0.0f)
{
if (_lastHandScale <= 0.0f)
{
poseData.IsDataValid = false;
}
else
{
poseData.RootScale = _lastHandScale;
}
}
else
{
_lastHandScale = poseData.RootScale;
}
if (poseData.IsDataValid && _handDataAsset.IsConnected)
{
UpdateDataPoses(poseData);
return;
}
}
// revert state fields to their defaults
_handDataAsset.IsConnected = default;
_handDataAsset.IsTracked = default;
_handDataAsset.RootPoseOrigin = default;
_handDataAsset.PointerPoseOrigin = default;
_handDataAsset.IsHighConfidence = default;
for (var fingerIdx = 0; fingerIdx < Constants.NUM_FINGERS; fingerIdx++)
{
_handDataAsset.IsFingerPinching[fingerIdx] = default;
_handDataAsset.IsFingerHighConfidence[fingerIdx] = default;
}
}
private void UpdateDataPoses(SkeletonPoseData poseData)
{
_handDataAsset.HandScale = poseData.RootScale;
_handDataAsset.IsTracked = _ovrHand.IsTracked;
_handDataAsset.IsHighConfidence = poseData.IsDataHighConfidence;
_handDataAsset.IsDominantHand = _ovrHand.IsDominantHand;
_handDataAsset.RootPoseOrigin = _handDataAsset.IsTracked
? PoseOrigin.RawTrackedPose
: PoseOrigin.None;
for (var fingerIdx = 0; fingerIdx < Constants.NUM_FINGERS; fingerIdx++)
{
var ovrFingerIdx = (OVRHand.HandFinger)fingerIdx;
bool isPinching = _ovrHand.GetFingerIsPinching(ovrFingerIdx);
_handDataAsset.IsFingerPinching[fingerIdx] = isPinching;
bool isHighConfidence =
_ovrHand.GetFingerConfidence(ovrFingerIdx) == OVRHand.TrackingConfidence.High;
_handDataAsset.IsFingerHighConfidence[fingerIdx] = isHighConfidence;
float fingerPinchStrength = _ovrHand.GetFingerPinchStrength(ovrFingerIdx);
_handDataAsset.FingerPinchStrength[fingerIdx] = fingerPinchStrength;
}
// Read the poses directly from the poseData, so it isn't in conflict with
// any modifications that the application makes to OVRSkeleton
_handDataAsset.Root = new Pose()
{
position = poseData.RootPose.Position.FromFlippedZVector3f(),
rotation = poseData.RootPose.Orientation.FromFlippedZQuatf()
};
if (_ovrHand.IsPointerPoseValid)
{
_handDataAsset.PointerPoseOrigin = PoseOrigin.RawTrackedPose;
_handDataAsset.PointerPose = new Pose(_ovrHand.PointerPose.localPosition,
_ovrHand.PointerPose.localRotation);
}
else
{
_handDataAsset.PointerPoseOrigin = PoseOrigin.None;
}
// Hand joint rotations X axis needs flipping to get to Unity's coordinate system.
var bones = poseData.BoneRotations;
for (int i = 0; i < bones.Length; i++)
{
// When using Link in the Unity Editor, the first frame of hand data
// sometimes contains bad joint data.
_handDataAsset.Joints[i] = float.IsNaN(bones[i].w)
? Config.HandSkeleton.joints[i].pose.rotation
: bones[i].FromFlippedXQuatf();
}
_handDataAsset.Joints[0] = WristFixupRotation;
}
#region Inject
public void InjectAllFromOVRHandDataSource(UpdateModeFlags updateMode, IDataSource updateAfter,
Handedness handedness, ITrackingToWorldTransformer trackingToWorldTransformer,
IHandSkeletonProvider handSkeletonProvider, IDataSource<HmdDataAsset, HmdDataSourceConfig> hmdData)
{
base.InjectAllDataSource(updateMode, updateAfter);
InjectHandedness(handedness);
InjectTrackingToWorldTransformer(trackingToWorldTransformer);
InjectHandSkeletonProvider(handSkeletonProvider);
InjectHmdData(hmdData);
}
public void InjectHandedness(Handedness handedness)
{
_handedness = handedness;
}
public void InjectTrackingToWorldTransformer(ITrackingToWorldTransformer trackingToWorldTransformer)
{
_trackingToWorldTransformer = trackingToWorldTransformer as MonoBehaviour;
TrackingToWorldTransformer = trackingToWorldTransformer;
}
public void InjectHandSkeletonProvider(IHandSkeletonProvider handSkeletonProvider)
{
_handSkeletonProvider = handSkeletonProvider as MonoBehaviour;
HandSkeletonProvider = handSkeletonProvider;
}
public void InjectHmdData(IDataSource<HmdDataAsset,HmdDataSourceConfig> hmdData)
{
_hmdData = hmdData as MonoBehaviour;
HmdData = hmdData;
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4855895ba1c44959a306beb7ae318fc2
timeCreated: 1630528577

View File

@@ -0,0 +1,157 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Serialization;
using UnityEngine.XR;
namespace Oculus.Interaction.Input
{
public class FromOVRHmdDataSource : DataSource<HmdDataAsset, HmdDataSourceConfig>
{
[Header("OVR Data Source")]
[SerializeField, Interface(typeof(IOVRCameraRigRef))]
private MonoBehaviour _cameraRigRef;
public IOVRCameraRigRef CameraRigRef { get; private set; }
[SerializeField]
[Tooltip("If true, uses OVRManager.headPoseRelativeOffset rather than sensor data for " +
"HMD pose.")]
private bool _useOvrManagerEmulatedPose = false;
[Header("Shared Configuration")]
[SerializeField, Interface(typeof(ITrackingToWorldTransformer))]
private MonoBehaviour _trackingToWorldTransformer;
private ITrackingToWorldTransformer TrackingToWorldTransformer;
private HmdDataAsset _hmdDataAsset = new HmdDataAsset();
private HmdDataSourceConfig _config;
protected void Awake()
{
CameraRigRef = _cameraRigRef as IOVRCameraRigRef;
TrackingToWorldTransformer = _trackingToWorldTransformer as ITrackingToWorldTransformer;
}
protected override void Start()
{
base.Start();
Assert.IsNotNull(CameraRigRef);
Assert.IsNotNull(TrackingToWorldTransformer);
InitConfig();
}
private void InitConfig()
{
if (_config != null)
{
return;
}
_config = new HmdDataSourceConfig()
{
TrackingToWorldTransformer = TrackingToWorldTransformer
};
}
protected override void UpdateData()
{
bool hmdPresent = OVRNodeStateProperties.IsHmdPresent();
ref var centerEyePose = ref _hmdDataAsset.Root;
if (_useOvrManagerEmulatedPose)
{
Quaternion emulatedRotation = Quaternion.Euler(
-OVRManager.instance.headPoseRelativeOffsetRotation.x,
-OVRManager.instance.headPoseRelativeOffsetRotation.y,
OVRManager.instance.headPoseRelativeOffsetRotation.z);
centerEyePose.rotation = emulatedRotation;
centerEyePose.position = OVRManager.instance.headPoseRelativeOffsetTranslation;
hmdPresent = true;
}
else
{
var previousEyePose = new Pose();
if (_hmdDataAsset.IsTracked)
{
previousEyePose = _hmdDataAsset.Root;
}
if (hmdPresent)
{
// These are already in Unity's coordinate system (LHS)
if (!OVRNodeStateProperties.GetNodeStatePropertyVector3(XRNode.CenterEye,
NodeStatePropertyType.Position, OVRPlugin.Node.EyeCenter,
OVRPlugin.Step.Render, out centerEyePose.position))
{
centerEyePose.position = previousEyePose.position;
}
if (!OVRNodeStateProperties.GetNodeStatePropertyQuaternion(XRNode.CenterEye,
NodeStatePropertyType.Orientation, OVRPlugin.Node.EyeCenter,
OVRPlugin.Step.Render, out centerEyePose.rotation))
{
centerEyePose.rotation = previousEyePose.rotation;
}
}
else
{
centerEyePose = previousEyePose;
}
}
_hmdDataAsset.IsTracked = hmdPresent;
_hmdDataAsset.FrameId = Time.frameCount;
}
protected override HmdDataAsset DataAsset => _hmdDataAsset;
// It is important that this creates an object on the fly, as it is possible it is called
// from other components Awake methods.
public override HmdDataSourceConfig Config
{
get
{
if (_config == null)
{
InitConfig();
}
return _config;
}
}
#region Inject
public void InjectAllFromOVRHmdDataSource(UpdateModeFlags updateMode, IDataSource updateAfter,
bool useOvrManagerEmulatedPose, ITrackingToWorldTransformer trackingToWorldTransformer)
{
base.InjectAllDataSource(updateMode, updateAfter);
InjectUseOvrManagerEmulatedPose(useOvrManagerEmulatedPose);
InjectTrackingToWorldTransformer(trackingToWorldTransformer);
}
public void InjectUseOvrManagerEmulatedPose(bool useOvrManagerEmulatedPose)
{
_useOvrManagerEmulatedPose = useOvrManagerEmulatedPose;
}
public void InjectTrackingToWorldTransformer(ITrackingToWorldTransformer trackingToWorldTransformer)
{
_trackingToWorldTransformer = trackingToWorldTransformer as MonoBehaviour;
TrackingToWorldTransformer = trackingToWorldTransformer;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f273abee0604ad2409c9bbc9a60e461e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,188 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Serialization;
namespace Oculus.Interaction.Input
{
public class HandPhysicsCapsules : MonoBehaviour
{
[SerializeField] private HandVisual _handVisual;
private GameObject _capsulesGO;
private List<BoneCapsule> _capsules;
public IList<BoneCapsule> Capsules { get; private set; }
private OVRPlugin.Skeleton2 _skeleton;
private bool _capsulesAreActive;
protected bool _started;
protected virtual void Awake()
{
Assert.IsNotNull(_handVisual);
}
protected virtual void Start()
{
this.BeginStart(ref _started);
_skeleton = _handVisual.Hand.Handedness == Handedness.Left
? OVRSkeletonData.LeftSkeleton
: OVRSkeletonData.RightSkeleton;
_capsulesGO = new GameObject("Capsules");
_capsulesGO.transform.SetParent(transform, false);
_capsulesGO.transform.localPosition = Vector3.zero;
_capsulesGO.transform.localRotation = Quaternion.identity;
_capsules = new List<BoneCapsule>(new BoneCapsule[_skeleton.NumBoneCapsules]);
Capsules = _capsules.AsReadOnly();
for (int i = 0; i < _capsules.Count; ++i)
{
Transform boneTransform = _handVisual.Joints[_skeleton.BoneCapsules[i].BoneIndex];
BoneCapsule capsule = new BoneCapsule();
_capsules[i] = capsule;
capsule.BoneIndex = _skeleton.BoneCapsules[i].BoneIndex;
capsule.CapsuleRigidbody = new GameObject((boneTransform.name).ToString() + "_CapsuleRigidbody")
.AddComponent<Rigidbody>();
capsule.CapsuleRigidbody.mass = 1.0f;
capsule.CapsuleRigidbody.isKinematic = true;
capsule.CapsuleRigidbody.useGravity = false;
capsule.CapsuleRigidbody.collisionDetectionMode = CollisionDetectionMode.ContinuousSpeculative;
GameObject rbGO = capsule.CapsuleRigidbody.gameObject;
rbGO.transform.SetParent(_capsulesGO.transform, false);
rbGO.transform.position = boneTransform.position;
rbGO.transform.rotation = boneTransform.rotation;
rbGO.SetActive(false);
capsule.CapsuleCollider = new GameObject((boneTransform.name).ToString() + "_CapsuleCollider")
.AddComponent<CapsuleCollider>();
capsule.CapsuleCollider.isTrigger = false;
var p0 = _skeleton.BoneCapsules[i].StartPoint.FromFlippedXVector3f();
var p1 = _skeleton.BoneCapsules[i].EndPoint.FromFlippedXVector3f();
var delta = p1 - p0;
var mag = delta.magnitude;
var rot = Quaternion.FromToRotation(Vector3.right, delta);
capsule.CapsuleCollider.radius = _skeleton.BoneCapsules[i].Radius;
capsule.CapsuleCollider.height = mag + _skeleton.BoneCapsules[i].Radius * 2.0f;
capsule.CapsuleCollider.direction = 0;
capsule.CapsuleCollider.center = Vector3.right * mag * 0.5f;
GameObject ccGO = capsule.CapsuleCollider.gameObject;
ccGO.transform.SetParent(rbGO.transform, false);
ccGO.transform.localPosition = p0;
ccGO.transform.localRotation = rot;
}
this.EndStart(ref _started);
}
protected virtual void OnEnable()
{
if (_started)
{
_handVisual.WhenHandVisualUpdated += HandleHandVisualUpdated;
}
}
protected virtual void OnDisable()
{
if (_started)
{
_handVisual.WhenHandVisualUpdated -= HandleHandVisualUpdated;
if (_capsules != null)
{
for (int i = 0; i < _capsules.Count; ++i)
{
var capsuleGO = _capsules[i].CapsuleRigidbody.gameObject;
capsuleGO.SetActive(false);
}
_capsulesAreActive = false;
}
}
}
protected virtual void FixedUpdate()
{
if (_capsulesAreActive && !_handVisual.IsVisible)
{
for (int i = 0; i < _capsules.Count; ++i)
{
var capsuleGO = _capsules[i].CapsuleRigidbody.gameObject;
capsuleGO.SetActive(false);
}
_capsulesAreActive = false;
}
}
private void HandleHandVisualUpdated()
{
_capsulesAreActive = _handVisual.IsVisible;
for (int i = 0; i < _capsules.Count; ++i)
{
BoneCapsule capsule = _capsules[i];
var capsuleGO = capsule.CapsuleRigidbody.gameObject;
if (_capsulesAreActive)
{
Transform boneTransform = _handVisual.Joints[(int)capsule.BoneIndex];
if (capsuleGO.activeSelf)
{
capsule.CapsuleRigidbody.MovePosition(boneTransform.position);
capsule.CapsuleRigidbody.MoveRotation(boneTransform.rotation);
}
else
{
capsuleGO.SetActive(true);
capsule.CapsuleRigidbody.position = boneTransform.position;
capsule.CapsuleRigidbody.rotation = boneTransform.rotation;
}
}
else
{
if (capsuleGO.activeSelf)
{
capsuleGO.SetActive(false);
}
}
}
}
#region Inject
public void InjectAllOVRHandPhysicsCapsules(HandVisual hand)
{
InjectHandSkeleton(hand);
}
public void InjectHandSkeleton(HandVisual hand)
{
_handVisual = hand;
}
#endregion
}
public class BoneCapsule
{
public short BoneIndex { get; set; }
public Rigidbody CapsuleRigidbody { get; set; }
public CapsuleCollider CapsuleCollider { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a1e477b940c8a084ab4f2dda703b49ef
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,69 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using UnityEngine;
using UnityEngine.Assertions;
namespace Oculus.Interaction.Input
{
public class HandSkeletonOVR : MonoBehaviour, IHandSkeletonProvider
{
private readonly HandSkeleton[] _skeletons = { null, null };
public HandSkeleton this[Handedness handedness] => _skeletons[(int)handedness];
protected void Awake()
{
_skeletons[0] = CreateSkeletonData(Handedness.Left);
_skeletons[1] = CreateSkeletonData(Handedness.Right);
}
public static HandSkeleton CreateSkeletonData(Handedness handedness)
{
HandSkeleton handSkeleton = new HandSkeleton();
// When running in the editor, the call to load the skeleton from OVRPlugin may fail. Use baked skeleton
// data.
if (handedness == Handedness.Left)
{
ApplyToSkeleton(OVRSkeletonData.LeftSkeleton, handSkeleton);
}
else
{
ApplyToSkeleton(OVRSkeletonData.RightSkeleton, handSkeleton);
}
return handSkeleton;
}
private static void ApplyToSkeleton(in OVRPlugin.Skeleton2 ovrSkeleton, HandSkeleton handSkeleton)
{
int numJoints = handSkeleton.joints.Length;
Assert.AreEqual(ovrSkeleton.NumBones, numJoints);
for (int i = 0; i < numJoints; ++i)
{
ref var srcPose = ref ovrSkeleton.Bones[i].Pose;
handSkeleton.joints[i] = new HandSkeletonJoint()
{
pose = new Pose()
{
position = srcPose.Position.FromFlippedXVector3f(),
rotation = srcPose.Orientation.FromFlippedXQuatf()
},
parent = ovrSkeleton.Bones[i].ParentBoneIndex
};
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 86bd0d3098d25db4c9c839739557480b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,138 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Serialization;
namespace Oculus.Interaction.Input
{
// When it is desired for HandDataAsset to drive OVRSkeleton, the DataSources:
// Must execute after OVRHands (so that the modifier stack can read the latest IsTracked value)
// Must execute before OVRSkeleton (so that the created IOVRSkeletonDataProvider injected into
// OVRSkeleton can read from the updated HandDataAsset)
// By deriving from InputDataProviderUpdateTrigger, we ensure that the InputData will be
// invalidated at the right time (at priority -85), so that it is recalculated just-in-time
// in the skeleton data callbacks (at priority -80)
[DefaultExecutionOrder(-85)]
public class InputDataProviderUpdateTriggerOVR : MonoBehaviour
{
[SerializeField, Interface(typeof(IDataSource))]
private MonoBehaviour _dataSource;
private IDataSource DataSource;
[SerializeField]
private bool _enableUpdate = true;
[SerializeField]
private bool _enableFixedUpdate = true;
[SerializeField, Interface(typeof(IOVRCameraRigRef)), Optional]
private MonoBehaviour _cameraRigRef;
protected bool _started = false;
public IOVRCameraRigRef CameraRigRef { get; private set; } = null;
protected virtual void Awake()
{
DataSource = _dataSource as IDataSource;
CameraRigRef = _cameraRigRef as IOVRCameraRigRef;
}
protected virtual void Start()
{
this.BeginStart(ref _started);
Assert.IsNotNull(DataSource);
if (_cameraRigRef != null)
{
Assert.IsNotNull(CameraRigRef);
}
this.EndStart(ref _started);
}
protected virtual void OnEnable()
{
if (_started)
{
if (CameraRigRef != null)
{
CameraRigRef.OnAnchorsUpdated += MarkRequiresUpdate;
}
}
}
private void MarkRequiresUpdate()
{
DataSource.MarkInputDataRequiresUpdate();
}
protected virtual void Update()
{
if (_enableUpdate)
{
MarkRequiresUpdate();
}
}
protected virtual void FixedUpdate()
{
if (_enableFixedUpdate)
{
MarkRequiresUpdate();
}
}
protected virtual void OnDisable()
{
if (_started)
{
if (CameraRigRef != null)
{
CameraRigRef.OnAnchorsUpdated -= MarkRequiresUpdate;
}
}
}
#region Inject
public void InjectAllInputDataProviderUpdateTriggerOVR(IDataSource dataSource, bool enableUpdate, bool enableFixedUpdate)
{
InjectDataSource(dataSource);
InjectEnableUpdate(enableUpdate);
InjectEnableFixedUpdate(enableFixedUpdate);
}
public void InjectDataSource(IDataSource dataSource)
{
_dataSource = dataSource as MonoBehaviour;
DataSource = dataSource;
}
public void InjectEnableUpdate(bool enableUpdate)
{
_enableUpdate = enableUpdate;
}
public void InjectEnableFixedUpdate(bool enableFixedUpdate)
{
_enableFixedUpdate = enableFixedUpdate;
}
public void InjectOptionalCameraRigRef(IOVRCameraRigRef cameraRigRef)
{
_cameraRigRef = cameraRigRef as MonoBehaviour;
CameraRigRef = cameraRigRef;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7198950508e319a40b9b3ca5c3960e58
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,133 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using UnityEngine;
using UnityEngine.Assertions;
namespace Oculus.Interaction.Input
{
public interface IOVRCameraRigRef
{
OVRCameraRig CameraRig { get; }
/// <summary>
/// Returns a valid OVRHand object representing the left hand, if one exists on the
/// OVRCameraRig. If none is available, returns null.
/// </summary>
OVRHand LeftHand { get; }
/// <summary>
/// Returns a valid OVRHand object representing the right hand, if one exists on the
/// OVRCameraRig. If none is available, returns null.
/// </summary>
OVRHand RightHand { get; }
Transform LeftController { get; }
Transform RightController { get; }
event Action OnAnchorsUpdated;
}
/// <summary>
/// Points to an OVRCameraRig instance. This level of indirection provides a single
/// configuration point on the root of a prefab.
/// Must execute before all other OVR related classes so that the fields are
/// initialized correctly and ready to use.
/// </summary>
[DefaultExecutionOrder(-90)]
public class OVRCameraRigRef : MonoBehaviour, IOVRCameraRigRef
{
[Header("Configuration")]
[SerializeField]
private OVRCameraRig _ovrCameraRig;
[SerializeField]
private bool _requireOvrHands = true;
public OVRCameraRig CameraRig => _ovrCameraRig;
private OVRHand _leftHand;
private OVRHand _rightHand;
public OVRHand LeftHand => GetHandCached(ref _leftHand, _ovrCameraRig.leftHandAnchor);
public OVRHand RightHand => GetHandCached(ref _rightHand, _ovrCameraRig.rightHandAnchor);
public Transform LeftController => _ovrCameraRig.leftControllerAnchor;
public Transform RightController => _ovrCameraRig.rightControllerAnchor;
public event Action OnAnchorsUpdated = delegate { };
protected bool _started = false;
protected virtual void Start()
{
this.BeginStart(ref _started);
Assert.IsNotNull(_ovrCameraRig);
this.EndStart(ref _started);
}
protected virtual void OnEnable()
{
if (_started)
{
_ovrCameraRig.UpdatedAnchors += OnUpdateAnchors;
}
}
protected virtual void OnDisable()
{
if (_started)
{
_ovrCameraRig.UpdatedAnchors -= OnUpdateAnchors;
}
}
private OVRHand GetHandCached(ref OVRHand cachedValue, Transform handAnchor)
{
if (cachedValue != null)
{
return cachedValue;
}
cachedValue = handAnchor.GetComponentInChildren<OVRHand>(true);
if (_requireOvrHands)
{
Assert.IsNotNull(cachedValue);
}
return cachedValue;
}
private void OnUpdateAnchors(OVRCameraRig ovrCameraRig)
{
OnAnchorsUpdated();
}
#region Inject
public void InjectAllOVRCameraRigRef(OVRCameraRig ovrCameraRig, bool requireHands)
{
InjectOVRCameraRig(ovrCameraRig);
InjectRequireHands(requireHands);
}
public void InjectOVRCameraRig(OVRCameraRig ovrCameraRig)
{
_ovrCameraRig = ovrCameraRig;
// Clear the cached values to force new values to be read on next access
_leftHand = null;
_rightHand = null;
}
public void InjectRequireHands(bool requireHands)
{
_requireOvrHands = requireHands;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a7b47e36715521d4e8a30d2c5b6e83e2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,55 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System.Collections.Generic;
using UnityEngine;
namespace Oculus.Interaction.Input
{
/// <summary>
/// Returns the active status of an OVRInput device based on whether
/// OVRInput's current active controller matches any of the controller
/// types set up in the inspector. OVRInput `Controllers` include
/// types like Touch, L Touch, R TouchR, Hands, L Hand, R Hand
/// </summary>
public class OVRInputDeviceActiveState : MonoBehaviour, IActiveState
{
[SerializeField]
private List<OVRInput.Controller> _controllerTypes;
public bool Active
{
get
{
foreach (OVRInput.Controller controllerType in _controllerTypes)
{
if (OVRInput.GetConnectedControllers() == controllerType) return true;
}
return false;
}
}
#region Inject
public void InjectAllOVRInputDeviceActiveState(List<OVRInput.Controller> controllerTypes)
{
InjectControllerTypes(controllerTypes);
}
public void InjectControllerTypes(List<OVRInput.Controller> controllerTypes)
{
_controllerTypes = controllerTypes;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ce6a3535bf452cd42a0b2fb1c571b76e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,171 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using UnityEngine;
namespace Oculus.Interaction.Input
{
public class OVRSkeletonData
{
#if UNITY_EDITOR
// This method can be used to generate a serialized skeleton in C# format.
public static string CreateString(OVRPlugin.Skeleton2 skeleton)
{
string bonesJson = "";
for (int i = 0; i < skeleton.NumBones; i++)
{
var bone = skeleton.Bones[i];
bonesJson +=
"new OVRPlugin.Bone() { " +
"Id=OVRPlugin.BoneId." + bone.Id.ToString() + ", " +
"ParentBoneIndex=" + bone.ParentBoneIndex + ", " +
"Pose=new OVRPlugin.Posef() { " +
"Position=new OVRPlugin.Vector3f() {x=" + bone.Pose.Position.x + "f,y=" + bone.Pose.Position.y + "f,z=" + bone.Pose.Position.z + "f}, " +
"Orientation=new OVRPlugin.Quatf(){x=" + bone.Pose.Orientation.x + "f,y=" + bone.Pose.Orientation.y + "f,z=" + bone.Pose.Orientation.z + "f,w=" + bone.Pose.Orientation.w + "f}}}";
if (i != skeleton.Bones.Length - 1)
{
bonesJson += ",";
}
bonesJson += "\n";
}
string boneCapsulesJson = "";
for (int i = 0; i < skeleton.NumBoneCapsules; i++)
{
var cap = skeleton.BoneCapsules[i];
boneCapsulesJson += "new OVRPlugin.BoneCapsule() { BoneIndex=" + cap.BoneIndex + ", Radius=" + cap.Radius + "f, " +
"StartPoint=new OVRPlugin.Vector3f() {x=" + cap.StartPoint.x + "f,y=" + cap.StartPoint.y + "f,z=" + cap.StartPoint.z + "f}, " +
"EndPoint=new OVRPlugin.Vector3f() {x=" + cap.EndPoint.x + "f,y=" + cap.EndPoint.y + "f,z=" + cap.EndPoint.z + "f}}";
if (i != skeleton.Bones.Length - 1)
{
boneCapsulesJson += ",";
}
boneCapsulesJson += "\n";
}
return "new OVRPlugin.Skeleton2() { " +
"Type=OVRPlugin.SkeletonType." + skeleton.Type.ToString() + ", " +
"NumBones=" + skeleton.NumBones + ", " +
"NumBoneCapsules=" + skeleton.NumBoneCapsules + ", " +
"Bones=new OVRPlugin.Bone[] {" + bonesJson + "}, " +
"BoneCapsules=new OVRPlugin.BoneCapsule[] {" + boneCapsulesJson + "}" +
"};";
}
#endif
public static readonly OVRPlugin.Skeleton2 LeftSkeleton = new OVRPlugin.Skeleton2()
{
Type = OVRPlugin.SkeletonType.HandLeft,
NumBones = 24,
NumBoneCapsules = 19,
Bones = new OVRPlugin.Bone[] {
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Start, ParentBoneIndex=-1, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0f,y=0f,z=0f}, Orientation=new OVRPlugin.Quatf(){x=0f,y=0f,z=0f,w=1f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_ForearmStub, ParentBoneIndex=0, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0f,y=0f,z=0f}, Orientation=new OVRPlugin.Quatf(){x=0f,y=0f,z=0f,w=1f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Thumb0, ParentBoneIndex=0, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.0200693f,y=0.0115541f,z=-0.01049652f}, Orientation=new OVRPlugin.Quatf(){x=0.3753869f,y=0.4245841f,z=-0.007778856f,w=0.8238644f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Thumb1, ParentBoneIndex=2, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.02485256f,y=-9.31E-10f,z=-1.863E-09f}, Orientation=new OVRPlugin.Quatf(){x=0.2602303f,y=0.02433088f,z=0.125678f,w=0.9570231f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Thumb2, ParentBoneIndex=3, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.03251291f,y=5.82E-10f,z=1.863E-09f}, Orientation=new OVRPlugin.Quatf(){x=-0.08270377f,y=-0.0769617f,z=-0.08406223f,w=0.9900357f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Thumb3, ParentBoneIndex=4, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.0337931f,y=3.26E-09f,z=1.863E-09f}, Orientation=new OVRPlugin.Quatf(){x=0.08350593f,y=0.06501573f,z=-0.05827406f,w=0.9926752f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Index1, ParentBoneIndex=0, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.09599624f,y=0.007316455f,z=-0.02355068f}, Orientation=new OVRPlugin.Quatf(){x=0.03068309f,y=-0.01885559f,z=0.04328144f,w=0.9984136f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Index2, ParentBoneIndex=6, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.0379273f,y=-5.82E-10f,z=-5.97E-10f}, Orientation=new OVRPlugin.Quatf(){x=-0.02585241f,y=-0.007116061f,z=0.003292944f,w=0.999635f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Index3, ParentBoneIndex=7, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.02430365f,y=-6.73E-10f,z=-6.75E-10f}, Orientation=new OVRPlugin.Quatf(){x=-0.016056f,y=-0.02714872f,z=-0.072034f,w=0.9969034f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Middle1, ParentBoneIndex=0, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.09564661f,y=0.002543155f,z=-0.001725906f}, Orientation=new OVRPlugin.Quatf(){x=-0.009066326f,y=-0.05146559f,z=0.05183575f,w=0.9972874f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Middle2, ParentBoneIndex=9, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.042927f,y=-8.51E-10f,z=-1.193E-09f}, Orientation=new OVRPlugin.Quatf(){x=-0.01122823f,y=-0.004378874f,z=-0.001978267f,w=0.9999254f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Middle3, ParentBoneIndex=10, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.02754958f,y=3.09E-10f,z=1.128E-09f}, Orientation=new OVRPlugin.Quatf(){x=-0.03431955f,y=-0.004611839f,z=-0.09300701f,w=0.9950631f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Ring1, ParentBoneIndex=0, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.0886938f,y=0.006529308f,z=0.01746524f}, Orientation=new OVRPlugin.Quatf(){x=-0.05315936f,y=-0.1231034f,z=0.04981349f,w=0.9897162f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Ring2, ParentBoneIndex=12, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.0389961f,y=0f,z=5.24E-10f}, Orientation=new OVRPlugin.Quatf(){x=-0.03363252f,y=-0.00278984f,z=0.00567602f,w=0.9994143f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Ring3, ParentBoneIndex=13, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.02657339f,y=1.281E-09f,z=1.63E-09f}, Orientation=new OVRPlugin.Quatf(){x=-0.003477462f,y=0.02917945f,z=-0.02502854f,w=0.9992548f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Pinky0, ParentBoneIndex=0, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.03407356f,y=0.009419836f,z=0.02299858f}, Orientation=new OVRPlugin.Quatf(){x=-0.207036f,y=-0.1403428f,z=0.0183118f,w=0.9680417f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Pinky1, ParentBoneIndex=15, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.04565055f,y=9.97679E-07f,z=-2.193963E-06f}, Orientation=new OVRPlugin.Quatf(){x=0.09111304f,y=0.00407137f,z=0.02812923f,w=0.9954349f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Pinky2, ParentBoneIndex=16, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.03072042f,y=1.048E-09f,z=-1.75E-10f}, Orientation=new OVRPlugin.Quatf(){x=-0.03761665f,y=-0.04293772f,z=-0.01328605f,w=0.9982809f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Pinky3, ParentBoneIndex=17, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.02031138f,y=-2.91E-10f,z=9.31E-10f}, Orientation=new OVRPlugin.Quatf(){x=0.0006447434f,y=0.04917067f,z=-0.02401883f,w=0.9985014f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_ThumbTip, ParentBoneIndex=5, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.02459077f,y=-0.001026974f,z=0.0006703701f}, Orientation=new OVRPlugin.Quatf(){x=0f,y=0f,z=0f,w=1f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_IndexTip, ParentBoneIndex=8, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.02236338f,y=-0.00102507f,z=0.0002956076f}, Orientation=new OVRPlugin.Quatf(){x=0f,y=0f,z=0f,w=1f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_MiddleTip, ParentBoneIndex=11, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.02496492f,y=-0.001137299f,z=0.0003086528f}, Orientation=new OVRPlugin.Quatf(){x=0f,y=0f,z=0f,w=1f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_RingTip, ParentBoneIndex=14, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.02432613f,y=-0.001608172f,z=0.000257905f}, Orientation=new OVRPlugin.Quatf(){x=0f,y=0f,z=0f,w=1f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_PinkyTip, ParentBoneIndex=18, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0.02192238f,y=-0.001216086f,z=-0.0002464796f}, Orientation=new OVRPlugin.Quatf(){x=0f,y=0f,z=0f,w=1f}}},
},
BoneCapsules = new OVRPlugin.BoneCapsule[] {
new OVRPlugin.BoneCapsule() { BoneIndex=0, Radius=0.01822828f, StartPoint=new OVRPlugin.Vector3f() {x=0.02755879f,y=0.01404149f,z=-0.01685145f}, EndPoint=new OVRPlugin.Vector3f() {x=0.07794081f,y=0.009090679f,z=-0.02178327f}},
new OVRPlugin.BoneCapsule() { BoneIndex=0, Radius=0.02323196f, StartPoint=new OVRPlugin.Vector3f() {x=0.02632602f,y=0.008661013f,z=-0.006531342f}, EndPoint=new OVRPlugin.Vector3f() {x=0.07255958f,y=0.004580691f,z=-0.003326343f}},
new OVRPlugin.BoneCapsule() { BoneIndex=0, Radius=0.01608828f, StartPoint=new OVRPlugin.Vector3f() {x=0.0297035f,y=0.00920606f,z=0.01111641f}, EndPoint=new OVRPlugin.Vector3f() {x=0.07271415f,y=0.007254403f,z=0.01574543f}},
new OVRPlugin.BoneCapsule() { BoneIndex=0, Radius=0.02346085f, StartPoint=new OVRPlugin.Vector3f() {x=0.02844799f,y=0.008827154f,z=0.01446979f}, EndPoint=new OVRPlugin.Vector3f() {x=0.06036391f,y=0.009573798f,z=0.02133043f}},
new OVRPlugin.BoneCapsule() { BoneIndex=3, Radius=0.01838252f, StartPoint=new OVRPlugin.Vector3f() {x=0f,y=2.561E-09f,z=1.863E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=0.03251291f,y=6.98E-10f,z=-3.492E-09f}},
new OVRPlugin.BoneCapsule() { BoneIndex=4, Radius=0.01028295f, StartPoint=new OVRPlugin.Vector3f() {x=7.451E-09f,y=2.794E-09f,z=-3.725E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=0.03379309f,y=6.519E-09f,z=-8.382E-09f}},
new OVRPlugin.BoneCapsule() { BoneIndex=5, Radius=0.009768805f, StartPoint=new OVRPlugin.Vector3f() {x=7.451E-09f,y=5.588E-09f,z=-4.657E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=0.01500075f,y=-0.0006525163f,z=0.0005929575f}},
new OVRPlugin.BoneCapsule() { BoneIndex=6, Radius=0.01029526f, StartPoint=new OVRPlugin.Vector3f() {x=0f,y=0f,z=-1.863E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=0.03792731f,y=4.66E-10f,z=-3.725E-09f}},
new OVRPlugin.BoneCapsule() { BoneIndex=7, Radius=0.008038102f, StartPoint=new OVRPlugin.Vector3f() {x=0f,y=-9.31E-10f,z=-1.863E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=0.02430364f,y=-1.863E-09f,z=-3.725E-09f}},
new OVRPlugin.BoneCapsule() { BoneIndex=8, Radius=0.007636196f, StartPoint=new OVRPlugin.Vector3f() {x=-1.4901E-08f,y=-1.863E-09f,z=0f}, EndPoint=new OVRPlugin.Vector3f() {x=0.01507758f,y=-0.0005028695f,z=6.049499E-05f}},
new OVRPlugin.BoneCapsule() { BoneIndex=9, Radius=0.01117394f, StartPoint=new OVRPlugin.Vector3f() {x=0f,y=-4.66E-10f,z=9.31E-10f}, EndPoint=new OVRPlugin.Vector3f() {x=0.042927f,y=-2.328E-09f,z=-9.31E-10f}},
new OVRPlugin.BoneCapsule() { BoneIndex=10, Radius=0.008030958f, StartPoint=new OVRPlugin.Vector3f() {x=1.4901E-08f,y=-4.66E-10f,z=0f}, EndPoint=new OVRPlugin.Vector3f() {x=0.02754962f,y=-4.66E-10f,z=-1.863E-09f}},
new OVRPlugin.BoneCapsule() { BoneIndex=11, Radius=0.007629411f, StartPoint=new OVRPlugin.Vector3f() {x=1.4901E-08f,y=-3.725E-09f,z=0f}, EndPoint=new OVRPlugin.Vector3f() {x=0.01719159f,y=-0.0007450115f,z=0.0004036371f}},
new OVRPlugin.BoneCapsule() { BoneIndex=12, Radius=0.009922137f, StartPoint=new OVRPlugin.Vector3f() {x=0f,y=2.33E-10f,z=2.328E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=0.03899612f,y=0f,z=4.66E-10f}},
new OVRPlugin.BoneCapsule() { BoneIndex=13, Radius=0.007611672f, StartPoint=new OVRPlugin.Vector3f() {x=1.4901E-08f,y=-4.66E-10f,z=1.863E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=0.02657339f,y=1.397E-09f,z=0f}},
new OVRPlugin.BoneCapsule() { BoneIndex=14, Radius=0.007231089f, StartPoint=new OVRPlugin.Vector3f() {x=0f,y=9.31E-10f,z=2.328E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=0.01632451f,y=-0.001288094f,z=0.0001235888f}},
new OVRPlugin.BoneCapsule() { BoneIndex=16, Radius=0.008483353f, StartPoint=new OVRPlugin.Vector3f() {x=0f,y=-2.33E-10f,z=1.863E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=0.03072041f,y=-1.164E-09f,z=0f}},
new OVRPlugin.BoneCapsule() { BoneIndex=17, Radius=0.006764194f, StartPoint=new OVRPlugin.Vector3f() {x=-7.451E-09f,y=-1.717E-09f,z=1.863E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=0.02031137f,y=1.46E-10f,z=1.863E-09f}},
new OVRPlugin.BoneCapsule() { BoneIndex=18, Radius=0.006425985f, StartPoint=new OVRPlugin.Vector3f() {x=0f,y=0f,z=-1.863E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=0.01507002f,y=-0.0006056242f,z=-2.491474E-05f}},
}
};
public static readonly OVRPlugin.Skeleton2 RightSkeleton = new OVRPlugin.Skeleton2()
{
Type = OVRPlugin.SkeletonType.HandRight,
NumBones = 24,
NumBoneCapsules = 19,
Bones = new OVRPlugin.Bone[] {new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Start, ParentBoneIndex=-1, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0f,y=0f,z=0f}, Orientation=new OVRPlugin.Quatf(){x=0f,y=0f,z=0f,w=1f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_ForearmStub, ParentBoneIndex=0, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=0f,y=0f,z=0f}, Orientation=new OVRPlugin.Quatf(){x=0f,y=0f,z=0f,w=1f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Thumb0, ParentBoneIndex=0, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.0200693f,y=-0.0115541f,z=0.01049652f}, Orientation=new OVRPlugin.Quatf(){x=0.3753869f,y=0.4245841f,z=-0.007778856f,w=0.8238644f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Thumb1, ParentBoneIndex=2, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.02485256f,y=2.328E-09f,z=0f}, Orientation=new OVRPlugin.Quatf(){x=0.2602303f,y=0.02433088f,z=0.125678f,w=0.9570231f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Thumb2, ParentBoneIndex=3, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.03251291f,y=-1.16E-10f,z=0f}, Orientation=new OVRPlugin.Quatf(){x=-0.08270377f,y=-0.0769617f,z=-0.08406223f,w=0.9900357f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Thumb3, ParentBoneIndex=4, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.0337931f,y=-3.26E-09f,z=-1.863E-09f}, Orientation=new OVRPlugin.Quatf(){x=0.08350593f,y=0.06501573f,z=-0.05827406f,w=0.9926752f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Index1, ParentBoneIndex=0, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.09599624f,y=-0.007316455f,z=0.02355068f}, Orientation=new OVRPlugin.Quatf(){x=0.03068309f,y=-0.01885559f,z=0.04328144f,w=0.9984136f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Index2, ParentBoneIndex=6, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.0379273f,y=1.16E-10f,z=5.97E-10f}, Orientation=new OVRPlugin.Quatf(){x=-0.02585241f,y=-0.007116061f,z=0.003292944f,w=0.999635f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Index3, ParentBoneIndex=7, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.02430365f,y=6.73E-10f,z=6.75E-10f}, Orientation=new OVRPlugin.Quatf(){x=-0.016056f,y=-0.02714872f,z=-0.072034f,w=0.9969034f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Middle1, ParentBoneIndex=0, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.09564661f,y=-0.002543155f,z=0.001725906f}, Orientation=new OVRPlugin.Quatf(){x=-0.009066326f,y=-0.05146559f,z=0.05183575f,w=0.9972874f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Middle2, ParentBoneIndex=9, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.042927f,y=1.317E-09f,z=1.193E-09f}, Orientation=new OVRPlugin.Quatf(){x=-0.01122823f,y=-0.004378874f,z=-0.001978267f,w=0.9999254f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Middle3, ParentBoneIndex=10, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.02754958f,y=-7.71E-10f,z=-1.12E-09f}, Orientation=new OVRPlugin.Quatf(){x=-0.03431955f,y=-0.004611839f,z=-0.09300701f,w=0.9950631f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Ring1, ParentBoneIndex=0, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.0886938f,y=-0.006529307f,z=-0.01746524f}, Orientation=new OVRPlugin.Quatf(){x=-0.05315936f,y=-0.1231034f,z=0.04981349f,w=0.9897162f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Ring2, ParentBoneIndex=12, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.0389961f,y=-4.66E-10f,z=-5.24E-10f}, Orientation=new OVRPlugin.Quatf(){x=-0.03363252f,y=-0.00278984f,z=0.00567602f,w=0.9994143f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Ring3, ParentBoneIndex=13, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.02657339f,y=-1.281E-09f,z=-1.63E-09f}, Orientation=new OVRPlugin.Quatf(){x=-0.003477462f,y=0.02917945f,z=-0.02502854f,w=0.9992548f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Pinky0, ParentBoneIndex=0, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.03407356f,y=-0.009419835f,z=-0.02299858f}, Orientation=new OVRPlugin.Quatf(){x=-0.207036f,y=-0.1403428f,z=0.0183118f,w=0.9680417f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Pinky1, ParentBoneIndex=15, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.04565055f,y=-9.98611E-07f,z=2.193963E-06f}, Orientation=new OVRPlugin.Quatf(){x=0.09111304f,y=0.00407137f,z=0.02812923f,w=0.9954349f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Pinky2, ParentBoneIndex=16, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.03072042f,y=6.98E-10f,z=1.106E-09f}, Orientation=new OVRPlugin.Quatf(){x=-0.03761665f,y=-0.04293772f,z=-0.01328605f,w=0.9982809f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_Pinky3, ParentBoneIndex=17, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.02031138f,y=-1.455E-09f,z=-1.397E-09f}, Orientation=new OVRPlugin.Quatf(){x=0.0006447434f,y=0.04917067f,z=-0.02401883f,w=0.9985014f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_ThumbTip, ParentBoneIndex=5, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.02459077f,y=0.001026974f,z=-0.0006703701f}, Orientation=new OVRPlugin.Quatf(){x=0f,y=0f,z=0f,w=1f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_IndexTip, ParentBoneIndex=8, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.02236338f,y=0.00102507f,z=-0.0002956076f}, Orientation=new OVRPlugin.Quatf(){x=0f,y=0f,z=0f,w=1f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_MiddleTip, ParentBoneIndex=11, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.02496492f,y=0.001137299f,z=-0.0003086528f}, Orientation=new OVRPlugin.Quatf(){x=0f,y=0f,z=0f,w=1f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_RingTip, ParentBoneIndex=14, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.02432613f,y=0.001608172f,z=-0.000257905f}, Orientation=new OVRPlugin.Quatf(){x=0f,y=0f,z=0f,w=1f}}},
new OVRPlugin.Bone() { Id=OVRPlugin.BoneId.Hand_PinkyTip, ParentBoneIndex=18, Pose=new OVRPlugin.Posef() { Position=new OVRPlugin.Vector3f() {x=-0.02192238f,y=0.001216086f,z=0.0002464796f}, Orientation=new OVRPlugin.Quatf(){x=0f,y=0f,z=0f,w=1f}}},
},
BoneCapsules = new OVRPlugin.BoneCapsule[] {new OVRPlugin.BoneCapsule() { BoneIndex=0, Radius=0.01822828f, StartPoint=new OVRPlugin.Vector3f() {x=-0.02755879f,y=-0.01404148f,z=0.01685145f}, EndPoint=new OVRPlugin.Vector3f() {x=-0.07794081f,y=-0.009090678f,z=0.02178326f}},
new OVRPlugin.BoneCapsule() { BoneIndex=0, Radius=0.02323196f, StartPoint=new OVRPlugin.Vector3f() {x=-0.02632602f,y=-0.008661013f,z=0.006531343f}, EndPoint=new OVRPlugin.Vector3f() {x=-0.07255958f,y=-0.004580691f,z=0.003326343f}},
new OVRPlugin.BoneCapsule() { BoneIndex=0, Radius=0.01608828f, StartPoint=new OVRPlugin.Vector3f() {x=-0.0297035f,y=-0.00920606f,z=-0.01111641f}, EndPoint=new OVRPlugin.Vector3f() {x=-0.07271415f,y=-0.007254403f,z=-0.01574543f}},
new OVRPlugin.BoneCapsule() { BoneIndex=0, Radius=0.02346085f, StartPoint=new OVRPlugin.Vector3f() {x=-0.02844799f,y=-0.008827153f,z=-0.01446979f}, EndPoint=new OVRPlugin.Vector3f() {x=-0.06036392f,y=-0.009573797f,z=-0.02133043f}},
new OVRPlugin.BoneCapsule() { BoneIndex=3, Radius=0.01838251f, StartPoint=new OVRPlugin.Vector3f() {x=3.725E-09f,y=-6.98E-10f,z=-2.794E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=-0.03251291f,y=-6.98E-10f,z=2.561E-09f}},
new OVRPlugin.BoneCapsule() { BoneIndex=4, Radius=0.01028296f, StartPoint=new OVRPlugin.Vector3f() {x=0f,y=-9.31E-10f,z=5.588E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=-0.03379308f,y=-4.657E-09f,z=1.0245E-08f}},
new OVRPlugin.BoneCapsule() { BoneIndex=5, Radius=0.009768807f, StartPoint=new OVRPlugin.Vector3f() {x=-7.451E-09f,y=1.863E-09f,z=8.382E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=-0.0150008f,y=0.0006525647f,z=-0.000592957f}},
new OVRPlugin.BoneCapsule() { BoneIndex=6, Radius=0.01029526f, StartPoint=new OVRPlugin.Vector3f() {x=0f,y=4.66E-10f,z=1.863E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=-0.03792731f,y=-4.66E-10f,z=3.725E-09f}},
new OVRPlugin.BoneCapsule() { BoneIndex=7, Radius=0.008038101f, StartPoint=new OVRPlugin.Vector3f() {x=0f,y=9.31E-10f,z=1.863E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=-0.02430364f,y=1.863E-09f,z=3.725E-09f}},
new OVRPlugin.BoneCapsule() { BoneIndex=8, Radius=0.007636196f, StartPoint=new OVRPlugin.Vector3f() {x=1.4901E-08f,y=1.863E-09f,z=0f}, EndPoint=new OVRPlugin.Vector3f() {x=-0.01507759f,y=0.0005028695f,z=-6.052852E-05f}},
new OVRPlugin.BoneCapsule() { BoneIndex=9, Radius=0.01117394f, StartPoint=new OVRPlugin.Vector3f() {x=0f,y=0f,z=-9.31E-10f}, EndPoint=new OVRPlugin.Vector3f() {x=-0.042927f,y=1.863E-09f,z=9.31E-10f}},
new OVRPlugin.BoneCapsule() { BoneIndex=10, Radius=0.008030958f, StartPoint=new OVRPlugin.Vector3f() {x=-1.4901E-08f,y=0f,z=0f}, EndPoint=new OVRPlugin.Vector3f() {x=-0.02754962f,y=4.66E-10f,z=1.863E-09f}},
new OVRPlugin.BoneCapsule() { BoneIndex=11, Radius=0.00762941f, StartPoint=new OVRPlugin.Vector3f() {x=-1.4901E-08f,y=1.863E-09f,z=0f}, EndPoint=new OVRPlugin.Vector3f() {x=-0.01719156f,y=0.0007450022f,z=-0.0004036473f}},
new OVRPlugin.BoneCapsule() { BoneIndex=12, Radius=0.009922139f, StartPoint=new OVRPlugin.Vector3f() {x=0f,y=-2.33E-10f,z=-2.328E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=-0.03899612f,y=4.66E-10f,z=-4.66E-10f}},
new OVRPlugin.BoneCapsule() { BoneIndex=13, Radius=0.007611674f, StartPoint=new OVRPlugin.Vector3f() {x=-1.4901E-08f,y=1.863E-09f,z=-1.863E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=-0.02657339f,y=0f,z=0f}},
new OVRPlugin.BoneCapsule() { BoneIndex=14, Radius=0.00723109f, StartPoint=new OVRPlugin.Vector3f() {x=0f,y=9.31E-10f,z=-2.328E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=-0.01632455f,y=0.001288087f,z=-0.0001235851f}},
new OVRPlugin.BoneCapsule() { BoneIndex=16, Radius=0.008483353f, StartPoint=new OVRPlugin.Vector3f() {x=0f,y=2.33E-10f,z=-1.863E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=-0.03072041f,y=1.164E-09f,z=0f}},
new OVRPlugin.BoneCapsule() { BoneIndex=17, Radius=0.006764191f, StartPoint=new OVRPlugin.Vector3f() {x=7.451E-09f,y=1.717E-09f,z=1.863E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=-0.02031137f,y=-1.46E-10f,z=-1.863E-09f}},
new OVRPlugin.BoneCapsule() { BoneIndex=18, Radius=0.006425982f, StartPoint=new OVRPlugin.Vector3f() {x=0f,y=0f,z=1.863E-09f}, EndPoint=new OVRPlugin.Vector3f() {x=-0.01507004f,y=0.0006056186f,z=2.490915E-05f}},
}
};
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dfb63309ade4ca04dbff7beff6784781
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,690 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Serialization;
using static OVRMesh;
using static OVRMeshRenderer;
using static OVRSkeleton;
using static OVRSkeletonRenderer;
namespace Oculus.Interaction.Input
{
public delegate HandDataAsset HandInputDataReadFunction();
internal class OVRInputHandComponents
{
public OVRInputHandComponents(Transform handAnchor)
{
Anchor = handAnchor;
OvrHand = handAnchor.GetComponentInChildren<OVRHand>(true);
if (OvrHand != null)
{
OvrMesh = OvrHand.GetComponent<OVRMesh>();
OvrMeshRenderer = OvrHand.GetComponent<OVRMeshRenderer>();
OvrSkeleton = OvrHand.GetComponent<OVRSkeleton>();
OvrSkeletonRenderer = OvrHand.GetComponent<OVRSkeletonRenderer>();
}
}
public Transform Anchor { get; }
public OVRMesh OvrMesh { get; }
public OVRMeshRenderer OvrMeshRenderer { get; }
public OVRSkeleton OvrSkeleton { get; }
public OVRSkeletonRenderer OvrSkeletonRenderer { get; }
public OVRHand OvrHand { get; }
}
public enum HandRenderPoseOriginBehavior
{
/// <summary>
/// Show hand if it's PoseOrigin is RawTrackedPose or FilteredTrackedPose, regardless of the
/// tracking confidence
/// </summary>
ShowTrackedOnly,
/// <summary>
/// Show hand if it's PoseOrigin is RawTrackedPose or FilteredTrackedPose, and also has high
/// tracking confidence
/// </summary>
ShowHighConfidenceTrackedOnly,
/// <summary>
/// Show hand if it's PoseOrigin is any value other than None, and it is connected.
/// </summary>
ShowConnectedOnly,
}
public class BaseOVRDataProvider
{
private readonly HandRenderPoseOriginBehavior _poseOriginBehavior;
protected BaseOVRDataProvider(HandRenderPoseOriginBehavior poseOriginBehavior)
{
this._poseOriginBehavior = poseOriginBehavior;
}
public bool ToOvrConfidence(HandDataAsset handDataAsset)
{
bool isRootPoseTracked =
handDataAsset.RootPoseOrigin == PoseOrigin.RawTrackedPose ||
handDataAsset.RootPoseOrigin == PoseOrigin.FilteredTrackedPose;
switch (_poseOriginBehavior)
{
case HandRenderPoseOriginBehavior.ShowConnectedOnly:
{
bool isSyntheticPose =
handDataAsset.RootPoseOrigin == PoseOrigin.SyntheticPose;
return isRootPoseTracked || isSyntheticPose;
}
case HandRenderPoseOriginBehavior.ShowTrackedOnly:
return isRootPoseTracked;
case HandRenderPoseOriginBehavior.ShowHighConfidenceTrackedOnly:
return isRootPoseTracked && handDataAsset.IsHighConfidence;
default:
// Should not reach this.
return false;
}
}
}
public class FromDataAssetOVRMeshRendererDataProvider : BaseOVRDataProvider, IOVRMeshRendererDataProvider
{
public IOVRMeshRendererDataProvider originalProvider;
public HandInputDataReadFunction handInputDataProvider;
public FromDataAssetOVRMeshRendererDataProvider(
HandRenderPoseOriginBehavior poseOriginBehavior) : base(poseOriginBehavior)
{
}
public MeshRendererData GetMeshRendererData()
{
var data = originalProvider.GetMeshRendererData();
var handInputData = handInputDataProvider.Invoke();
if (handInputData == null)
{
return data;
}
if (!data.IsDataValid)
{
data.ShouldUseSystemGestureMaterial = false;
}
data.IsDataValid = handInputData.IsDataValid && handInputData.IsConnected;
if (!data.IsDataValid)
{
return data;
}
data.IsDataHighConfidence = ToOvrConfidence(handInputData);
return data;
}
}
public class FromDataAssetOVRSkeletonDataProvider : BaseOVRDataProvider, IOVRSkeletonDataProvider
{
public IOVRSkeletonDataProvider originalProvider;
public HandInputDataReadFunction handInputDataProvider;
public SkeletonType skeletonType;
private readonly OVRPlugin.Quatf[] _boneRotations =
new OVRPlugin.Quatf[OVRSkeletonData.LeftSkeleton.NumBones];
private SkeletonPoseData _poseData;
public FromDataAssetOVRSkeletonDataProvider(
HandRenderPoseOriginBehavior poseOriginBehavior) : base(poseOriginBehavior)
{
}
public static int InitialSkeletonChangeCount => 1;
public SkeletonPoseData GetSkeletonPoseData()
{
return _poseData;
}
public void UpdateSkeletonPoseData()
{
_poseData = originalProvider.GetSkeletonPoseData();
// If the hand is not connected, treat it as if there is no valid data.
var handInputData = handInputDataProvider.Invoke();
bool isValid = handInputData.IsDataValid && handInputData.IsConnected;
_poseData.IsDataValid = isValid;
if (!isValid)
{
return;
}
for (int i = 0; i < _boneRotations.Length; i++)
{
_boneRotations[i] = handInputData.Joints[i].ToFlippedXQuatf();
}
if (handInputData.HandScale <= 0.0f)
{
// If handScale is zero it will cause rendering artifacts on the hand meshes.
handInputData.HandScale = 1.0f;
}
_poseData.IsDataHighConfidence = ToOvrConfidence(handInputData);
_poseData.BoneRotations = _boneRotations;
_poseData.RootPose = new OVRPlugin.Posef()
{
Orientation = handInputData.Root.rotation.ToFlippedZQuatf(),
Position = handInputData.Root.position.ToFlippedZVector3f()
};
_poseData.RootScale = handInputData.HandScale;
}
public SkeletonType GetSkeletonType()
{
return skeletonType;
}
}
public class FromDataAssetOVRSkeletonRendererDataProvider : BaseOVRDataProvider, IOVRSkeletonRendererDataProvider
{
public HandInputDataReadFunction handInputDataProvider;
public IOVRSkeletonRendererDataProvider originalProvider;
public FromDataAssetOVRSkeletonRendererDataProvider(
HandRenderPoseOriginBehavior poseOriginBehavior) : base(poseOriginBehavior)
{
}
public SkeletonRendererData GetSkeletonRendererData()
{
var data = new SkeletonRendererData();
var handInputData = handInputDataProvider.Invoke();
if (handInputData == null)
{
return originalProvider.GetSkeletonRendererData();
}
data.IsDataValid = handInputData.RootPoseOrigin != PoseOrigin.None;
data.IsDataHighConfidence = ToOvrConfidence(handInputData);
data.RootScale = handInputData.HandScale;
data.ShouldUseSystemGestureMaterial = false;
return data;
}
}
/// <summary>
/// Reads hand & HMD pose data from the DataSources, and copies them onto the
/// given OVRSkeleton. Can also provide more sophisticated control of the mesh rendering,
/// to keep hand meshes visible when tracking is lost.
///
/// This class is not required if you are using the HandSkeletonVisual to render the hand.
/// </summary>
public class OVRSkeletonDataProviders : MonoBehaviour
{
[SerializeField, Interface(typeof(IOVRCameraRigRef))]
private MonoBehaviour _cameraRigRef;
public IOVRCameraRigRef CameraRigRef { get; private set; }
[Header("Update CameraRig Transforms")]
[SerializeField, Interface(typeof(IDataSource<HmdDataAsset, HmdDataSourceConfig>))]
private MonoBehaviour _hmdData;
private IDataSource<HmdDataAsset, HmdDataSourceConfig> _hmdDataSource;
[SerializeField]
private Hand _leftHand;
[SerializeField]
private Hand _rightHand;
[SerializeField]
private bool _modifyCameraRigAnchorTransforms = true;
[SerializeField]
private bool _modifyHandTransformsLeft = true;
[SerializeField]
private bool _modifyHandTransformsRight = true;
[Header("Hand Meshes")]
[Tooltip("If true, use the following hand meshes in place of those provided by OVRPlugin")]
[SerializeField]
private bool _replaceHandMeshRendererProviders = true;
[SerializeField, Optional]
private Mesh _leftHandMesh;
[SerializeField, Optional]
private Mesh _rightHandMesh;
[SerializeField]
private HandRenderPoseOriginBehavior _handRenderBehavior =
HandRenderPoseOriginBehavior.ShowConnectedOnly;
OVRInputHandComponents _leftHandComponents;
OVRInputHandComponents _rightHandComponents;
private FromDataAssetOVRSkeletonDataProvider _leftHandOvrSkeletonDataProvider;
private FromDataAssetOVRSkeletonDataProvider _rightHandOvrSkeletonDataProvider;
private const System.Reflection.BindingFlags PrivateInstanceFlags =
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance;
private const System.Reflection.BindingFlags InstanceFlags =
PrivateInstanceFlags | System.Reflection.BindingFlags.Public;
public void SetModifyCameraRigAndHandTransformState(bool modifyCameraRig,
bool modifyLeftHand, bool modifyRightHand)
{
_modifyCameraRigAnchorTransforms = modifyCameraRig;
_modifyHandTransformsLeft = modifyLeftHand;
_modifyHandTransformsRight = modifyRightHand;
}
protected bool _started = false;
protected virtual void Awake()
{
CameraRigRef = _cameraRigRef as IOVRCameraRigRef;
_hmdDataSource = _hmdData as IDataSource<HmdDataAsset, HmdDataSourceConfig>;
}
protected virtual void Start()
{
this.BeginStart(ref _started);
Assert.IsNotNull(CameraRigRef);
Assert.IsNotNull(_hmdDataSource);
Assert.IsNotNull(_leftHand);
Assert.IsNotNull(_rightHand);
OVRCameraRig cameraRig = CameraRigRef.CameraRig;
Assert.IsNotNull(cameraRig);
Assert.IsNotNull(cameraRig.leftHandAnchor);
Assert.IsNotNull(cameraRig.rightHandAnchor);
Assert.IsNotNull(cameraRig.centerEyeAnchor);
_leftHandComponents = new OVRInputHandComponents(cameraRig.leftHandAnchor);
_rightHandComponents = new OVRInputHandComponents(cameraRig.rightHandAnchor);
HandDataAsset LeftHandProvider() =>
_leftHand.isActiveAndEnabled
? _leftHand.GetData()
: null;
HandDataAsset RightHandProvider() =>
_rightHand.isActiveAndEnabled
? _rightHand.GetData()
: null;
if (_replaceHandMeshRendererProviders && _leftHandComponents.OvrHand != null &&
_rightHandComponents.OvrHand != null)
{
InitializeBakedMeshes();
}
// Inject a custom DataProvider to provide confidence levels to the
// OVRMeshRenderer
InitializeMeshRendererDataProvider(_leftHandComponents, LeftHandProvider);
InitializeMeshRendererDataProvider(_rightHandComponents, RightHandProvider);
// Inject a custom DataProvider to provide finger joints to the OVRSkeleton,
// which are surfaced though the `Bones` property.
// We update this providers state in this components Update method, so that we can
// catch skeleton changes and notify the DataSources.
_leftHandOvrSkeletonDataProvider = CreateHandSkeletonPoseDataProvider(
_leftHandComponents, LeftHandProvider);
_rightHandOvrSkeletonDataProvider = CreateHandSkeletonPoseDataProvider(
_rightHandComponents, RightHandProvider);
InitializeHandSkeletonPoseDataProvider(
_leftHandComponents, _leftHandOvrSkeletonDataProvider);
InitializeHandSkeletonPoseDataProvider(
_rightHandComponents, _rightHandOvrSkeletonDataProvider);
// Inject a custom DataProvider to provide poses to the OVRSkeletonRenderer
// (debug skeleton joint visualization)
InitializeHandSkeletonRendererPoseDataProvider(_leftHandComponents, LeftHandProvider);
InitializeHandSkeletonRendererPoseDataProvider(_rightHandComponents, RightHandProvider);
this.EndStart(ref _started);
}
private void InitializeBakedMeshes()
{
/*
Q: Why all the reflection to update OVRXYZ classes?
A: Since OVRMesh, OVRSkeleton etc directly call OVRPlugin.XYZ methods, without any hooks,
hooks, I can't easily get past the fact that on Oculus Link, when hand tracking is
not active, OVRHands/OVRSkeleton do not work. (OVRPlugin.GetMesh returns nothing)
The goal of this code below is to provide baked skeleton and mesh data to the OVR classes,
classes, rather than them retrieving it from OVRPlugin. This allows OVRHands to
render in the Editor using poses sourced from GRVF files, without needing to
call the OVRPlugin API's.
Q: Why are the hand fingers all messed up!
A: You might be using the mesh provided by the Oculus Integration (OculusHand_L or
OculusHand_R). These meshes are not compatible with OVRSkeleton by themselves; they
are intended for use with OVRCustomSkeleton. To fix this, use the provided meshes
(HandLeft, HandRight).
*/
ReplaceSkeletonData(_leftHandComponents.OvrSkeleton, OVRSkeletonData.LeftSkeleton);
ReplaceSkeletonData(_rightHandComponents.OvrSkeleton, OVRSkeletonData.RightSkeleton);
if (_leftHandMesh != null)
{
ReplaceHandMeshes(_leftHandComponents, _leftHandMesh);
}
if (_rightHandMesh != null)
{
ReplaceHandMeshes(_rightHandComponents, _rightHandMesh);
}
// Inject a custom DataProvider to provide finger joints to the OVRSkeleton,
// Inject a custom DataProvider to provide poses to the OVRSkeletonRenderer
}
protected virtual void OnEnable()
{
if (_started)
{
_leftHand.HandUpdated += OnLeftHandDataAvailable;
_rightHand.HandUpdated += OnRightHandDataAvailable;
// The root poses of the Hand and HMD must be updated just after OVRCameraRig, which is at
// priority 0. Otherwise the changes will be overwritten in that update. To solve this, root
// poses are updated in the OVRCameraRig.UpdatedAnchors callback.
CameraRigRef.CameraRig.UpdatedAnchors += OnCameraRigUpdatedAnchors;
}
}
protected virtual void OnDisable()
{
if (_started)
{
CameraRigRef.CameraRig.UpdatedAnchors -= OnCameraRigUpdatedAnchors;
_leftHand.HandUpdated -= OnLeftHandDataAvailable;
_rightHand.HandUpdated -= OnRightHandDataAvailable;
}
}
protected virtual void Update()
{
// Handle the case where OVRManager is not initialized (usually due to an HMD not being
// plugged in, when using LINK.
if (!OVRManager.OVRManagerinitialized && !CameraRigRef.CameraRig.useFixedUpdateForTracking)
{
CameraRigRef.CameraRig.EnsureGameObjectIntegrity();
OverwriteHandTransforms();
}
}
private void FixedUpdate()
{
// Handle the case where OVRManager is not initialized (usually due to an HMD not being
// plugged in, when using LINK.
if (!OVRManager.OVRManagerinitialized && CameraRigRef.CameraRig.useFixedUpdateForTracking)
{
CameraRigRef.CameraRig.EnsureGameObjectIntegrity();
OverwriteHandTransforms();
}
}
private void OnCameraRigUpdatedAnchors(OVRCameraRig obj)
{
OverwriteHandTransforms();
}
private void OnLeftHandDataAvailable()
{
_leftHandOvrSkeletonDataProvider.UpdateSkeletonPoseData();
}
private void OnRightHandDataAvailable()
{
_rightHandOvrSkeletonDataProvider.UpdateSkeletonPoseData();
}
private void OverwriteHandTransforms()
{
// Apply modified state back to the camera rig anchors
if (_modifyCameraRigAnchorTransforms && _hmdData.isActiveAndEnabled)
{
var hmdInputData = _hmdDataSource.GetData();
if (_modifyCameraRigAnchorTransforms && hmdInputData.IsTracked)
{
SetLocalTransform(CameraRigRef.CameraRig.centerEyeAnchor, hmdInputData.Root);
}
}
if (_modifyHandTransformsLeft && _leftHand.isActiveAndEnabled)
{
if (_modifyHandTransformsLeft && _leftHand.GetRootPose(out Pose rootPose))
{
SetTransform(_leftHandComponents.Anchor, rootPose);
}
}
if (_modifyHandTransformsRight && _rightHand.isActiveAndEnabled)
{
if (_modifyHandTransformsRight && _rightHand.GetRootPose(out Pose rootPose))
{
SetTransform(_rightHandComponents.Anchor, rootPose);
}
}
}
private static void SetLocalTransform(Transform transform, in Pose root)
{
transform.localPosition = root.position;
transform.localRotation = root.rotation;
}
private static void SetTransform(Transform transform, in Pose root)
{
transform.position = root.position;
transform.rotation = root.rotation;
}
private void ReplaceHandMeshes(OVRInputHandComponents handComponents, Mesh mesh)
{
if (handComponents.OvrMesh == null)
{
return;
}
// OVRSkeleton and OVRMesh will not initialize the skeleton in editor mode if the hand
// is not connected. This is a limitation with Link, the skeleton isn't available unless
// hands are tracked.
Assert.IsNotNull(mesh);
// Create a clone of the mesh, so that vertices in the asset file are not modified by
// changes to sharedMesh.
mesh = Instantiate(mesh);
InvokeSetField(handComponents.OvrMesh, "_mesh", mesh);
InvokeSetProp(handComponents.OvrMesh, "IsInitialized", true);
}
private void InitializeMeshRendererDataProvider(OVRInputHandComponents handComponents,
HandInputDataReadFunction inputDataProvider)
{
if (handComponents.OvrMeshRenderer == null)
{
return;
}
var dataProvider = new FromDataAssetOVRMeshRendererDataProvider(_handRenderBehavior)
{
handInputDataProvider = inputDataProvider,
originalProvider = handComponents.OvrHand
};
InvokeSetField(handComponents.OvrMeshRenderer, "_dataProvider", dataProvider);
}
private FromDataAssetOVRSkeletonDataProvider CreateHandSkeletonPoseDataProvider(
OVRInputHandComponents handComponents, HandInputDataReadFunction inputDataProvider)
{
var ovrMeshType = handComponents.OvrHand.GetComponent<IOVRMeshDataProvider>()
.GetMeshType();
SkeletonType skeletonType =
ovrMeshType == MeshType.HandLeft ? SkeletonType.HandLeft : SkeletonType.HandRight;
return new FromDataAssetOVRSkeletonDataProvider(_handRenderBehavior)
{
originalProvider = handComponents.OvrHand,
skeletonType = skeletonType,
handInputDataProvider = inputDataProvider
};
}
private void InitializeHandSkeletonPoseDataProvider(OVRInputHandComponents handComponents,
FromDataAssetOVRSkeletonDataProvider dataProvider)
{
InvokeSetField(handComponents.OvrSkeleton, "_dataProvider", dataProvider);
}
private void InitializeHandSkeletonRendererPoseDataProvider(
OVRInputHandComponents handComponents, HandInputDataReadFunction inputDataProvider)
{
if (handComponents.OvrSkeletonRenderer == null)
{
return;
}
var dataProvider = new FromDataAssetOVRSkeletonRendererDataProvider(_handRenderBehavior)
{
handInputDataProvider = inputDataProvider,
originalProvider = handComponents.OvrHand
};
InvokeSetField(handComponents.OvrSkeletonRenderer, "_dataProvider", dataProvider);
}
private void ReplaceSkeletonData(OVRSkeleton ovrLeftHandSkeleton,
OVRPlugin.Skeleton2 skeletonData)
{
var skeletonChangeCount = FromDataAssetOVRSkeletonDataProvider.InitialSkeletonChangeCount;
var nullParams = new object[] { };
InvokeSetField(ovrLeftHandSkeleton, "_skeleton", skeletonData);
InvokeMethod(ovrLeftHandSkeleton, "InitializeBones", nullParams);
InvokeMethod(ovrLeftHandSkeleton, "InitializeBindPose", nullParams);
InvokeMethod(ovrLeftHandSkeleton, "InitializeCapsules", nullParams);
InvokeSetProp(ovrLeftHandSkeleton, "IsInitialized", true);
InvokeSetProp(ovrLeftHandSkeleton, "SkeletonChangedCount", -1);
}
private static void InvokeMethod<T>(T instance, string methodName, object[] args)
{
var method = typeof(T).GetMethod(methodName, InstanceFlags);
Assert.IsNotNull(method, methodName + " method must exist on type: " + nameof(T));
method.Invoke(instance, args);
}
private static void InvokeSetField<T>(T instance, string fieldName, object val)
{
var prop = typeof(T).GetField(fieldName, InstanceFlags);
Assert.IsNotNull(prop, prop + " field must exist on type: " + nameof(T));
prop.SetValue(instance, val);
}
private static void InvokeSetProp<T>(T instance, string propName, object val)
{
var prop = typeof(T).GetProperty(propName, InstanceFlags);
Assert.IsNotNull(prop, prop + " property must exist on type: " + nameof(T));
prop.SetMethod.Invoke(instance, new[] { val });
}
#region Inject
public void InjectOVRSkeletonDataProviders(IOVRCameraRigRef cameraRigRef,
IDataSource<HmdDataAsset, HmdDataSourceConfig> hmdData,
Hand leftHand, Hand rightHand, bool modifyCameraRigAnchorTransforms, bool modifyHandTransformsLeft,
bool modifyHandTransformsRight, bool replaceHandMeshRendererProviders,
HandRenderPoseOriginBehavior handRenderBehavior)
{
InjectCameraRigRef(cameraRigRef);
InjectHmdData(hmdData);
InjectLeftHand(leftHand);
InjectRightHand(rightHand);
InjectModifyCameraRigAnchorTransforms(modifyCameraRigAnchorTransforms);
InjectModifyHandTransformsLeft(modifyHandTransformsLeft);
InjectModifyHandTransformsRight(modifyHandTransformsRight);
InjectReplaceHandMeshRendererProviders(replaceHandMeshRendererProviders);
InjectHandRenderBehavior(handRenderBehavior);
}
public void InjectCameraRigRef(IOVRCameraRigRef cameraRigRef)
{
_cameraRigRef = cameraRigRef as MonoBehaviour;
CameraRigRef = cameraRigRef;
}
public void InjectHmdData(IDataSource<HmdDataAsset,HmdDataSourceConfig> hmdData)
{
_hmdData = hmdData as MonoBehaviour;
_hmdDataSource = hmdData;
}
public void InjectLeftHand(Hand leftHand)
{
_leftHand = leftHand;
}
public void InjectRightHand(Hand rightHand)
{
_rightHand = rightHand;
}
public void InjectModifyCameraRigAnchorTransforms(bool modifyCameraRigAnchorTransforms)
{
_modifyCameraRigAnchorTransforms = modifyCameraRigAnchorTransforms;
}
public void InjectModifyHandTransformsLeft(bool modifyHandTransformsLeft)
{
_modifyHandTransformsLeft = modifyHandTransformsLeft;
}
public void InjectModifyHandTransformsRight(bool modifyHandTransformsRight)
{
_modifyHandTransformsRight = modifyHandTransformsRight;
}
public void InjectReplaceHandMeshRendererProviders(bool replaceHandMeshRendererProviders)
{
_replaceHandMeshRendererProviders = replaceHandMeshRendererProviders;
}
public void InjectHandRenderBehavior(HandRenderPoseOriginBehavior handRenderBehavior)
{
_handRenderBehavior = handRenderBehavior;
}
public void InjectOptionalLeftHandMesh(Mesh handMesh)
{
_leftHandMesh = handMesh;
}
public void InjectOptionalRightHandMesh(Mesh handMesh)
{
_rightHandMesh = handMesh;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ffac1ecd519bd1d409558219f47d07b0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,39 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System.Linq;
using UnityEngine;
namespace Oculus.Interaction.Input
{
public class SetDisplayRefresh : MonoBehaviour
{
[SerializeField]
private float _desiredDisplayFrequency = 90f;
public void SetDesiredDisplayFrequency(float desiredDisplayFrequency)
{
var validFrequencies = OVRPlugin.systemDisplayFrequenciesAvailable;
if (validFrequencies.Contains(_desiredDisplayFrequency))
{
Debug.Log("[Oculus.Interaction] Setting desired display frequency to " + _desiredDisplayFrequency);
OVRPlugin.systemDisplayFrequency = _desiredDisplayFrequency;
}
}
protected virtual void Awake()
{
SetDesiredDisplayFrequency(_desiredDisplayFrequency);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 215d90758f7ed4f42b7ad0a64d0dfec4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,79 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
using System;
using UnityEngine;
using UnityEngine.Assertions;
namespace Oculus.Interaction.Input
{
public class TrackingToWorldTransformerOVR : MonoBehaviour, ITrackingToWorldTransformer
{
[SerializeField, Interface(typeof(IOVRCameraRigRef))]
private MonoBehaviour _cameraRigRef;
public IOVRCameraRigRef CameraRigRef { get; private set; }
public Transform Transform => CameraRigRef.CameraRig.transform;
/// <summary>
/// Converts a tracking space pose to a world space pose (Applies any transform applied to the OVRCameraRig)
/// </summary>
public Pose ToWorldPose(Pose pose)
{
Transform trackingToWorldSpace = Transform;
pose.position = trackingToWorldSpace.TransformPoint(pose.position);
pose.rotation = trackingToWorldSpace.rotation * pose.rotation;
return pose;
}
/// <summary>
/// Converts a world space pose to a tracking space pose (Removes any transform applied to the OVRCameraRig)
/// </summary>
public Pose ToTrackingPose(in Pose worldPose)
{
Transform trackingToWorldSpace = Transform;
Vector3 position = trackingToWorldSpace.InverseTransformPoint(worldPose.position);
Quaternion rotation = Quaternion.Inverse(trackingToWorldSpace.rotation) * worldPose.rotation;
return new Pose(position, rotation);
}
public Quaternion WorldToTrackingWristJointFixup => FromOVRHandDataSource.WristFixupRotation;
protected virtual void Awake()
{
CameraRigRef = _cameraRigRef as IOVRCameraRigRef;
}
protected virtual void Start()
{
Assert.IsNotNull(CameraRigRef);
}
#region Inject
public void InjectAllTrackingToWorldTransformerOVR(IOVRCameraRigRef cameraRigRef)
{
InjectCameraRigRef(cameraRigRef);
}
public void InjectCameraRigRef(IOVRCameraRigRef cameraRigRef)
{
_cameraRigRef = cameraRigRef as MonoBehaviour;
CameraRigRef = cameraRigRef;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 998a5646185efb9488265f3a2f35a99a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 315b3e47cee7df349bc10128cf62dc2e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,39 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.
************************************************************************************/
namespace Oculus.Interaction.Input
{
public interface IOneEuroFilter<TData>
{
/// <summary>
/// The last value returned by <see cref="Step(TData, float)"/>
/// </summary>
TData Value { get; }
/// <summary>
/// Update the parameters of the filter
/// </summary>
/// <param name="propertyBlock">The property block containing the parameters to se</param>
void SetProperties(in OneEuroFilterPropertyBlock properties);
/// <summary>
/// Update the filter with a new noisy value to be smoothed.
/// This is a destructive operation that should be run once per frame, as
/// calling this updates the previous frame data.
/// </summary>
/// <param name="rawValue">The noisy value to be filtered</param>
/// <param name="deltaTime">The time between steps, use to derive filter frequency.
/// Omitting this value will fallback to <see cref="OneEuroFilter._DEFAULT_FREQUENCY_HZ"/></param>
/// <returns>The filtered value, equivalent to <see cref="Value"/></returns>
TData Step(TData rawValue, float deltaTime = 1f / OneEuroFilter._DEFAULT_FREQUENCY_HZ);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 00c937dac239f0644ae25e3b81b10753
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More