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,390 @@
/************************************************************************************
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 System;
namespace Oculus.Interaction.HandPosing.SnapSurfaces
{
[Serializable]
public class BoxSurfaceData : ICloneable
{
public object Clone()
{
BoxSurfaceData clone = new BoxSurfaceData();
clone.widthOffset = this.widthOffset;
clone.snapOffset = this.snapOffset;
clone.size = this.size;
clone.eulerAngles = this.eulerAngles;
return clone;
}
public BoxSurfaceData Mirror()
{
BoxSurfaceData mirror = Clone() as BoxSurfaceData;
mirror.snapOffset = new Vector4(
-mirror.snapOffset.y, -mirror.snapOffset.x,
-mirror.snapOffset.w, -mirror.snapOffset.z);
return mirror;
}
[Range(0f, 1f)]
public float widthOffset = 0.5f;
public Vector4 snapOffset;
public Vector3 size = new Vector3(0.1f, 0f, 0.1f);
public Vector3 eulerAngles;
}
/// <summary>
/// This SnapSurface defines a Rectangle around which the grip point is valid.
/// Since the grip point might be offset from the fingers, a valid range for each opposite
/// side of the rectangle can be set so the grabbing fingers are constrained to the object bounds.
/// </summary>
[Serializable]
public class BoxSurface : MonoBehaviour, ISnapSurface
{
[SerializeField]
protected BoxSurfaceData _data = new BoxSurfaceData();
/// <summary>
/// Getter for the data-only version of this surface. Used so it can be stored when created
/// at Play-Mode.
/// </summary>
public BoxSurfaceData Data
{
get
{
return _data;
}
set
{
_data = value;
}
}
[SerializeField]
private Transform _relativeTo;
[SerializeField]
private Transform _gripPoint;
/// <summary>
/// Transform to which the surface refers to.
/// </summary>
public Transform RelativeTo
{
get => _relativeTo;
set => _relativeTo = value;
}
/// <summary>
/// Valid point at which the hand can snap, typically the SnapPoint position itself.
/// </summary>
public Transform GripPoint
{
get => _gripPoint;
set => _gripPoint = value;
}
/// <summary>
/// The lateral displacement of the grip point in the main side.
/// </summary>
public float WidthOffset
{
get
{
return _data.widthOffset;
}
set
{
_data.widthOffset = value;
}
}
/// <summary>
/// The range at which the sides are constrained.
/// X,Y for the back and forward sides range.
/// Z,W for the left and right sides range.
/// </summary>
public Vector4 SnapOffset
{
get
{
return _data.snapOffset;
}
set
{
_data.snapOffset = value;
}
}
/// <summary>
/// The size of the rectangle. Y is ignored.
/// </summary>
public Vector3 Size
{
get
{
return _data.size;
}
set
{
_data.size = value;
}
}
/// <summary>
/// The rotation of the rectangle from the Grip point
/// </summary>
public Quaternion Rotation
{
get
{
return this.RelativeTo.rotation * Quaternion.Euler(_data.eulerAngles);
}
set
{
_data.eulerAngles = (Quaternion.Inverse(this.RelativeTo.rotation) * value).eulerAngles;
}
}
/// <summary>
/// The forward direction of the rectangle (based on its rotation)
/// </summary>
public Vector3 Direction
{
get
{
return Rotation * Vector3.forward;
}
}
#region editor events
private void Reset()
{
_gripPoint = this.transform;
if (this.TryGetComponent(out HandGrabPoint grabPoint))
{
_relativeTo = grabPoint.RelativeTo;
}
}
#endregion
protected virtual void Start()
{
Assert.IsNotNull(_relativeTo);
Assert.IsNotNull(_gripPoint);
Assert.IsNotNull(_data);
}
public Pose MirrorPose(in Pose pose)
{
Vector3 normal = Quaternion.Inverse(this.RelativeTo.rotation) * Direction;
Vector3 tangent = Quaternion.Inverse(this.RelativeTo.rotation) * (Rotation * Vector3.up);
return pose.MirrorPoseRotation(normal, tangent);
}
public ISnapSurface CreateMirroredSurface(GameObject gameObject)
{
BoxSurface surface = gameObject.AddComponent<BoxSurface>();
surface.Data = _data.Mirror();
return surface;
}
public ISnapSurface CreateDuplicatedSurface(GameObject gameObject)
{
BoxSurface surface = gameObject.AddComponent<BoxSurface>();
surface.Data = _data;
return surface;
}
public float CalculateBestPoseAtSurface(in Pose targetPose, in Pose reference, out Pose bestPose, in PoseMeasureParameters scoringModifier)
{
return SnapSurfaceHelper.CalculateBestPoseAtSurface(targetPose, reference, out bestPose,
scoringModifier, MinimalTranslationPoseAtSurface, MinimalRotationPoseAtSurface);
}
private void CalculateCorners(out Vector3 bottomLeft, out Vector3 bottomRight, out Vector3 topLeft, out Vector3 topRight)
{
Vector3 rightRot = Rotation * Vector3.right;
bottomLeft = GripPoint.position - rightRot * _data.size.x * (1f - _data.widthOffset);
bottomRight = GripPoint.position + rightRot * _data.size.x * (_data.widthOffset);
Vector3 forwardOffset = Rotation * Vector3.forward * _data.size.z;
topLeft = bottomLeft + forwardOffset;
topRight = bottomRight + forwardOffset;
}
private Vector3 ProjectOnSegment(Vector3 point, (Vector3, Vector3) segment)
{
Vector3 line = segment.Item2 - segment.Item1;
Vector3 projection = Vector3.Project(point - segment.Item1, line);
if (Vector3.Dot(projection, line) < 0f)
{
projection = segment.Item1;
}
else if (projection.magnitude > line.magnitude)
{
projection = segment.Item2;
}
else
{
projection += segment.Item1;
}
return projection;
}
public bool CalculateBestPoseAtSurface(Ray targetRay, in Pose recordedPose, out Pose bestPose)
{
Plane plane = new Plane(Rotation * Vector3.up, this.transform.position);
plane.Raycast(targetRay, out float rayDistance);
Vector3 proximalPoint = targetRay.origin + targetRay.direction * rayDistance;
Vector3 surfacePoint = NearestPointInSurface(proximalPoint);
Pose desiredPose = new Pose(surfacePoint, recordedPose.rotation);
bestPose = MinimalTranslationPoseAtSurface(desiredPose, recordedPose);
return true;
}
protected Vector3 NearestPointInSurface(Vector3 targetPosition)
{
NearestPointAndAngleInSurface(targetPosition, out Vector3 surfacePoint, out float angle);
return surfacePoint;
}
private void NearestPointAndAngleInSurface(Vector3 targetPosition, out Vector3 surfacePoint, out float angle)
{
Vector3 rightDir = Rotation * Vector3.right;
Vector3 forwardDir = Rotation * Vector3.forward;
Vector3 bottomLeft, bottomRight, topLeft, topRight;
CalculateCorners(out bottomLeft, out bottomRight, out topLeft, out topRight);
Vector3 bottomP = ProjectOnSegment(targetPosition, (bottomLeft + rightDir * SnapOffset.y, bottomRight + rightDir * SnapOffset.x));
Vector3 topP = ProjectOnSegment(targetPosition, (topLeft - rightDir * SnapOffset.x, topRight - rightDir * SnapOffset.y));
Vector3 leftP = ProjectOnSegment(targetPosition, (bottomLeft - forwardDir * SnapOffset.z, topLeft - forwardDir * SnapOffset.w));
Vector3 rightP = ProjectOnSegment(targetPosition, (bottomRight + forwardDir * SnapOffset.w, topRight + forwardDir * SnapOffset.z));
float bottomDistance = Vector3.Distance(bottomP, targetPosition);
float topDistance = Vector3.Distance(topP, targetPosition);
float leftDistance = Vector3.Distance(leftP, targetPosition);
float rightDistance = Vector3.Distance(rightP, targetPosition);
float minDistance = Mathf.Min(bottomDistance, Mathf.Min(topDistance, Mathf.Min(leftDistance, rightDistance)));
if (bottomDistance == minDistance)
{
surfacePoint = bottomP;
angle = 0f;
return;
}
if (topDistance == minDistance)
{
surfacePoint = topP;
angle = 180f;
return;
}
if (leftDistance == minDistance)
{
surfacePoint = leftP;
angle = 90f;
return;
}
surfacePoint = rightP;
angle = -90f;
}
protected Pose MinimalRotationPoseAtSurface(in Pose userPose, in Pose snapPose)
{
Vector3 desiredPos = userPose.position;
Quaternion baseRot = snapPose.rotation;
Quaternion desiredRot = userPose.rotation;
Vector3 up = Rotation * Vector3.up;
Quaternion bottomRot = baseRot;
Quaternion topRot = Quaternion.AngleAxis(180f, up) * baseRot;
Quaternion leftRot = Quaternion.AngleAxis(90f, up) * baseRot;
Quaternion rightRot = Quaternion.AngleAxis(-90f, up) * baseRot;
float bottomDot = PoseUtils.RotationalSimilarity(bottomRot, desiredRot);
float topDot = PoseUtils.RotationalSimilarity(topRot, desiredRot);
float leftDot = PoseUtils.RotationalSimilarity(leftRot, desiredRot);
float rightDot = PoseUtils.RotationalSimilarity(rightRot, desiredRot);
Vector3 rightDir = Rotation * Vector3.right;
Vector3 forwardDir = Rotation * Vector3.forward;
Vector3 bottomLeft, bottomRight, topLeft, topRight;
CalculateCorners(out bottomLeft, out bottomRight, out topLeft, out topRight);
float maxDot = Mathf.Max(bottomDot, Mathf.Max(topDot, Mathf.Max(leftDot, rightDot)));
if (bottomDot == maxDot)
{
Vector3 projBottom = ProjectOnSegment(desiredPos, (bottomLeft + rightDir * SnapOffset.y, bottomRight + rightDir * SnapOffset.x));
return new Pose(projBottom, bottomRot);
}
if (topDot == maxDot)
{
Vector3 projTop = ProjectOnSegment(desiredPos, (topLeft - rightDir * SnapOffset.x, topRight - rightDir * SnapOffset.y));
return new Pose(projTop, topRot);
}
if (leftDot == maxDot)
{
Vector3 projLeft = ProjectOnSegment(desiredPos, (bottomLeft - forwardDir * SnapOffset.z, topLeft - forwardDir * SnapOffset.w));
return new Pose(projLeft, leftRot);
}
Vector3 projRight = ProjectOnSegment(desiredPos, (bottomRight + forwardDir * SnapOffset.w, topRight + forwardDir * SnapOffset.z));
return new Pose(projRight, rightRot);
}
protected Pose MinimalTranslationPoseAtSurface(in Pose userPose, in Pose snapPose)
{
Vector3 desiredPos = userPose.position;
Quaternion baseRot = snapPose.rotation;
Vector3 surfacePoint;
float surfaceAngle;
NearestPointAndAngleInSurface(desiredPos, out surfacePoint, out surfaceAngle);
Quaternion surfaceRotation = RotateUp(baseRot, surfaceAngle);
return new Pose(surfacePoint, surfaceRotation);
}
protected Quaternion RotateUp(Quaternion baseRot, float angle)
{
Quaternion offset = Quaternion.AngleAxis(angle, Rotation * Vector3.up);
return offset * baseRot;
}
#region Inject
public void InjectAllBoxSurface(BoxSurfaceData data,
Transform relativeTo, Transform gripPoint)
{
InjectData(data);
InjectRelativeTo(relativeTo);
InjectGripPoint(gripPoint);
}
public void InjectData(BoxSurfaceData data)
{
_data = data;
}
public void InjectRelativeTo(Transform relativeTo)
{
_relativeTo = relativeTo;
}
public void InjectGripPoint(Transform gripPoint)
{
_gripPoint = gripPoint;
}
#endregion
}
}

View File

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

View File

@@ -0,0 +1,96 @@
/************************************************************************************
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.HandPosing.SnapSurfaces
{
public class ColliderSurface : MonoBehaviour, ISnapSurface
{
[SerializeField]
private Collider _collider;
protected virtual void Start()
{
Assert.IsNotNull(_collider);
}
private Vector3 NearestPointInSurface(Vector3 targetPosition)
{
if (_collider.bounds.Contains(targetPosition))
{
targetPosition = _collider.ClosestPointOnBounds(targetPosition);
}
return _collider.ClosestPoint(targetPosition);
}
public float CalculateBestPoseAtSurface(in Pose targetPose, in Pose snapPose, out Pose bestPose, in PoseMeasureParameters scoringModifier)
{
Vector3 surfacePoint = NearestPointInSurface(targetPose.position);
float bestScore = 1f;
if (scoringModifier.MaxDistance > 0)
{
bestScore = PoseUtils.PositionalSimilarity(surfacePoint, targetPose.position, scoringModifier.MaxDistance);
}
bestPose = new Pose(surfacePoint, targetPose.rotation);
return bestScore;
}
public bool CalculateBestPoseAtSurface(Ray targetRay, in Pose recordedPose, out Pose bestPose)
{
if (_collider.Raycast(targetRay, out RaycastHit hit, Mathf.Infinity))
{
bestPose.position = hit.point;
bestPose.rotation = recordedPose.rotation;
return true;
}
bestPose = Pose.identity;
return false;
}
public Pose MirrorPose(in Pose gripPose)
{
return gripPose;
}
public ISnapSurface CreateMirroredSurface(GameObject gameObject)
{
return CreateDuplicatedSurface(gameObject);
}
public ISnapSurface CreateDuplicatedSurface(GameObject gameObject)
{
ColliderSurface colliderSurface = gameObject.AddComponent<ColliderSurface>();
colliderSurface.InjectAllColliderSurface(_collider);
return colliderSurface;
}
#region inject
public void InjectCollider(Collider collider)
{
_collider = collider;
}
public void InjectAllColliderSurface(Collider collider)
{
InjectCollider(collider);
}
#endregion
}
}

View File

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

View File

@@ -0,0 +1,426 @@
/************************************************************************************
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 System;
namespace Oculus.Interaction.HandPosing.SnapSurfaces
{
[Serializable]
public class CylinderSurfaceData : ICloneable
{
public object Clone()
{
CylinderSurfaceData clone = new CylinderSurfaceData();
clone.startPoint = this.startPoint;
clone.endPoint = this.endPoint;
clone.angle = this.angle;
return clone;
}
public CylinderSurfaceData Mirror()
{
CylinderSurfaceData mirror = Clone() as CylinderSurfaceData;
return mirror;
}
public Vector3 startPoint = new Vector3(0f, 0.1f, 0f);
public Vector3 endPoint = new Vector3(0f, -0.1f, 0f);
[Range(0f, 360f)]
public float angle = 120f;
}
/// <summary>
/// This type of surface defines a cylinder in which the grip pose is valid around an object.
/// An angle can be used to constrain the cylinder and not use a full circle.
/// The radius is automatically specified as the distance from the axis of the cylinder to the original grip position.
/// </summary>
[Serializable]
public class CylinderSurface : MonoBehaviour, ISnapSurface
{
[SerializeField]
protected CylinderSurfaceData _data = new CylinderSurfaceData();
/// <summary>
/// Getter for the data-only version of this surface. Used so it can be stored when created
/// at Play-Mode.
/// </summary>
public CylinderSurfaceData Data
{
get
{
return _data;
}
set
{
_data = value;
}
}
[SerializeField]
private Transform _relativeTo;
[SerializeField]
private Transform _gripPoint;
/// <summary>
/// Transform to which the surface refers to.
/// </summary>
public Transform RelativeTo
{
get => _relativeTo;
set => _relativeTo = value;
}
/// <summary>
/// Valid point at which the hand can snap, typically the SnapPoint position itself.
/// </summary>
public Transform GripPoint
{
get => _gripPoint;
set => _gripPoint = value;
}
/// <summary>
/// Direction from the axis of the cylinder to the original grip position.
/// </summary>
public Vector3 StartAngleDir
{
get
{
if (this.GripPoint == null)
{
return Vector3.forward;
}
return Vector3.ProjectOnPlane(GripPoint.transform.position - StartPoint, Direction).normalized;
}
}
/// <summary>
/// Direction from the axis of the cylinder to the maximum angle allowance.
/// </summary>
public Vector3 EndAngleDir
{
get
{
return Quaternion.AngleAxis(Angle, Direction) * StartAngleDir;
}
}
/// <summary>
/// Base cap of the cylinder, in world coordinates.
/// </summary>
public Vector3 StartPoint
{
get
{
if (this.RelativeTo != null)
{
return this.RelativeTo.TransformPoint(_data.startPoint);
}
else
{
return _data.startPoint;
}
}
set
{
if (this.RelativeTo != null)
{
_data.startPoint = this.RelativeTo.InverseTransformPoint(value);
}
else
{
_data.startPoint = value;
}
}
}
/// <summary>
/// End cap of the cylinder, in world coordinates.
/// </summary>
public Vector3 EndPoint
{
get
{
if (this.RelativeTo != null)
{
return this.RelativeTo.TransformPoint(_data.endPoint);
}
else
{
return _data.endPoint;
}
}
set
{
if (this.RelativeTo != null)
{
_data.endPoint = this.RelativeTo.InverseTransformPoint(value);
}
else
{
_data.endPoint = value;
}
}
}
/// <summary>
/// The maximum angle for the surface of the cylinder, starting from the original grip position.
/// To invert the direction of the angle, swap the caps order.
/// </summary>
public float Angle
{
get
{
return _data.angle;
}
set
{
_data.angle = Mathf.Repeat(value, 360f);
}
}
/// <summary>
/// The generated radius of the cylinder.
/// Represents the distance from the axis of the cylinder to the original grip position.
/// </summary>
public float Radius
{
get
{
if (this.GripPoint == null)
{
return 0f;
}
Vector3 start = StartPoint;
Vector3 projectedPoint = start + Vector3.Project(this.GripPoint.position - start, Direction);
return Vector3.Distance(projectedPoint, this.GripPoint.position);
}
}
/// <summary>
/// The direction of the central axis of the cylinder.
/// </summary>
public Vector3 Direction
{
get
{
Vector3 dir = (EndPoint - StartPoint);
if (dir.sqrMagnitude == 0f)
{
return this.RelativeTo ? this.RelativeTo.up : Vector3.up;
}
return dir.normalized;
}
}
private float Height
{
get
{
return (EndPoint - StartPoint).magnitude;
}
}
/// <summary>
/// The rotation of the central axis of the cylinder.
/// </summary>
private Quaternion Rotation
{
get
{
if (_data.startPoint == _data.endPoint)
{
return Quaternion.LookRotation(Vector3.forward);
}
return Quaternion.LookRotation(StartAngleDir, Direction);
}
}
#region editor events
private void Reset()
{
_gripPoint = this.transform;
if (this.TryGetComponent(out HandGrabPoint grabPoint))
{
_relativeTo = grabPoint.RelativeTo;
}
}
#endregion
protected virtual void Start()
{
Assert.IsNotNull(_relativeTo);
Assert.IsNotNull(_gripPoint);
Assert.IsNotNull(_data);
}
public Pose MirrorPose(in Pose pose)
{
Vector3 normal = Quaternion.Inverse(this.RelativeTo.rotation) * StartAngleDir;
Vector3 tangent = Quaternion.Inverse(this.RelativeTo.rotation) * Direction;
return pose.MirrorPoseRotation(normal, tangent);
}
private Vector3 PointAltitude(Vector3 point)
{
Vector3 start = StartPoint;
Vector3 projectedPoint = start + Vector3.Project(point - start, Direction);
return projectedPoint;
}
public float CalculateBestPoseAtSurface(in Pose targetPose, in Pose reference, out Pose bestPose, in PoseMeasureParameters scoringModifier)
{
return SnapSurfaceHelper.CalculateBestPoseAtSurface(targetPose, reference, out bestPose,
scoringModifier, MinimalTranslationPoseAtSurface, MinimalRotationPoseAtSurface);
}
public ISnapSurface CreateMirroredSurface(GameObject gameObject)
{
CylinderSurface surface = gameObject.AddComponent<CylinderSurface>();
surface.Data = _data.Mirror();
return surface;
}
public ISnapSurface CreateDuplicatedSurface(GameObject gameObject)
{
CylinderSurface surface = gameObject.AddComponent<CylinderSurface>();
surface.Data = _data;
return surface;
}
protected Vector3 NearestPointInSurface(Vector3 targetPosition)
{
Vector3 start = StartPoint;
Vector3 dir = Direction;
Vector3 projectedVector = Vector3.Project(targetPosition - start, dir);
if (projectedVector.magnitude > Height)
{
projectedVector = projectedVector.normalized * Height;
}
if (Vector3.Dot(projectedVector, dir) < 0f)
{
projectedVector = Vector3.zero;
}
Vector3 projectedPoint = StartPoint + projectedVector;
Vector3 targetDirection = Vector3.ProjectOnPlane((targetPosition - projectedPoint), dir).normalized;
//clamp of the surface
float desiredAngle = Mathf.Repeat(Vector3.SignedAngle(StartAngleDir, targetDirection, dir), 360f);
if (desiredAngle > Angle)
{
if (Mathf.Abs(desiredAngle - Angle) >= Mathf.Abs(360f - desiredAngle))
{
targetDirection = StartAngleDir;
}
else
{
targetDirection = EndAngleDir;
}
}
Vector3 surfacePoint = projectedPoint + targetDirection * Radius;
return surfacePoint;
}
public bool CalculateBestPoseAtSurface(Ray targetRay, in Pose recordedPose, out Pose bestPose)
{
Vector3 lineToCylinder = StartPoint - targetRay.origin;
float perpendiculiarity = Vector3.Dot(targetRay.direction, Direction);
float rayToLineDiff = Vector3.Dot(lineToCylinder, targetRay.direction);
float cylinderToLineDiff = Vector3.Dot(lineToCylinder, Direction);
float determinant = 1f / (perpendiculiarity * perpendiculiarity - 1f);
float lineOffset = (perpendiculiarity * cylinderToLineDiff - rayToLineDiff) * determinant;
float cylinderOffset = (cylinderToLineDiff - perpendiculiarity * rayToLineDiff) * determinant;
Vector3 pointInLine = targetRay.origin + targetRay.direction * lineOffset;
Vector3 pointInCylinder = StartPoint + Direction * cylinderOffset;
float distanceToSurface = Mathf.Max(Vector3.Distance(pointInCylinder, pointInLine) - Radius);
if (distanceToSurface < Radius)
{
float adjustedDistance = Mathf.Sqrt(Radius * Radius - distanceToSurface * distanceToSurface);
pointInLine -= targetRay.direction * adjustedDistance;
}
Vector3 surfacePoint = NearestPointInSurface(pointInLine);
Pose desiredPose = new Pose(surfacePoint, recordedPose.rotation);
bestPose = MinimalTranslationPoseAtSurface(desiredPose, recordedPose);
return true;
}
protected Pose MinimalRotationPoseAtSurface(in Pose userPose, in Pose snapPose)
{
Vector3 desiredPos = userPose.position;
Quaternion desiredRot = userPose.rotation;
Quaternion baseRot = snapPose.rotation;
Quaternion rotDif = (desiredRot) * Quaternion.Inverse(baseRot);
Vector3 desiredDirection = (rotDif * Rotation) * Vector3.forward;
Vector3 projectedDirection = Vector3.ProjectOnPlane(desiredDirection, Direction).normalized;
Vector3 altitudePoint = PointAltitude(desiredPos);
Vector3 surfacePoint = NearestPointInSurface(altitudePoint + projectedDirection * Radius);
Quaternion surfaceRotation = CalculateRotationOffset(surfacePoint) * baseRot;
return new Pose(surfacePoint, surfaceRotation);
}
protected Pose MinimalTranslationPoseAtSurface(in Pose userPose, in Pose snapPose)
{
Vector3 desiredPos = userPose.position;
Quaternion baseRot = snapPose.rotation;
Vector3 surfacePoint = NearestPointInSurface(desiredPos);
Quaternion surfaceRotation = CalculateRotationOffset(surfacePoint) * baseRot;
return new Pose(surfacePoint, surfaceRotation);
}
protected Quaternion CalculateRotationOffset(Vector3 surfacePoint)
{
Vector3 recordedDirection = Vector3.ProjectOnPlane(this.GripPoint.position - StartPoint, Direction);
Vector3 desiredDirection = Vector3.ProjectOnPlane(surfacePoint - StartPoint, Direction);
return Quaternion.FromToRotation(recordedDirection, desiredDirection);
}
#region Inject
public void InjectAllCylinderSurface(CylinderSurfaceData data,
Transform relativeTo, Transform gripPoint)
{
InjectData(data);
InjectRelativeTo(relativeTo);
InjectGripPoint(gripPoint);
}
public void InjectData(CylinderSurfaceData data)
{
_data = data;
}
public void InjectRelativeTo(Transform relativeTo)
{
_relativeTo = relativeTo;
}
public void InjectGripPoint(Transform gripPoint)
{
_gripPoint = gripPoint;
}
#endregion
}
}

View File

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

View File

@@ -0,0 +1,66 @@
/************************************************************************************
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.HandPosing.SnapSurfaces
{
/// <summary>
/// This interface defines the method needed to use snap surfaces. They allow finding the
/// nearest poses at the surface to a given set of parameters as well as duplicating and
/// mirroring the surface.
/// </summary>
public interface ISnapSurface
{
/// <summary>
/// Finds the Pose at the surface that is the closest to the given pose.
/// </summary>
/// <param name="targetPose">The pose to find the nearest to.</param>
/// <param name="reference">The reference snap point to use for measuring at the surface.</param>
/// <param name="bestPose">The best found pose at the surface.<</param>
/// <returns>The score indicating how good the found pose was, -1 for invalid result.</returns>
float CalculateBestPoseAtSurface(in Pose targetPose, in Pose reference, out Pose bestPose, in PoseMeasureParameters scoringModifier);
/// <summary>
/// Finds the Pose at the surface that is the closest to the given ray.
/// </summary>
/// <param name="targetRay">Ray searching for the nearest snap pose</param>
/// <param name="reference">The reference snap point to use for measuring at the surface.</param>
/// <param name="bestPose">The best found pose at the surface.</param>
/// <returns>True if the pose was found</returns>
bool CalculateBestPoseAtSurface(Ray targetRay, in Pose reference, out Pose bestPose);
/// <summary>
/// Method for mirroring a Pose around the surface.
/// Different surfaces will prefer mirroring along different axis.
/// </summary>
/// <param name="gripPose">The Pose to be mirrored.</param>
/// <returns>A new pose mirrored at this surface.</returns>
Pose MirrorPose(in Pose gripPose);
/// <summary>
/// Creates a new ISnapSurface under the selected gameobject
/// that is a mirror version of the current.
/// </summary>
/// <param name="gameObject">The gameobject in which to place the new ISnapSurface.</param>
/// <returns>A mirror of this ISnapSurface.</returns>
ISnapSurface CreateMirroredSurface(GameObject gameObject);
/// <summary>
/// Creates a new ISnapSurface under the selected gameobject
/// with the same data as this one.
/// </summary>
/// <param name="gameObject">The gameobject in which to place the new ISnapSurface.</param>
/// <returns>A clone of this ISnapSurface.</returns>
ISnapSurface CreateDuplicatedSurface(GameObject gameObject);
}
}

View File

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

View File

@@ -0,0 +1,76 @@
/************************************************************************************
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.HandPosing.SnapSurfaces
{
public static class SnapSurfaceHelper
{
public delegate Pose PoseCalculator(in Pose desiredPose, in Pose snapPose);
/// <summary>
/// Finds the best pose comparing the one that requires the minimum rotation
/// and minimum translation.
/// </summary>
/// <param name="desiredPose">Pose to measure from.</param>
/// <param name="snapPose">Reference pose of the surface.</param>
/// <param name="bestPose">Nearest pose to the desired one at the surface.</param>
/// <param name="maxDistance">Max distance to consider for scoring.</param>
/// <param name="positionRotationWeight">Ratio of position and rotation to select between poses.</param>
/// <param name="minimalTranslationPoseCalculator">Delegate to calculate the nearest, by position, pose at a surface.</param>
/// <param name="minimalRotationPoseCalculator">Delegate to calculate the nearest, by rotation, pose at a surface.</param>
/// <returns>The score, normalized, of the best pose.</returns>
public static float CalculateBestPoseAtSurface(in Pose desiredPose, in Pose snapPose, out Pose bestPose,
in PoseMeasureParameters scoringModifier,
PoseCalculator minimalTranslationPoseCalculator, PoseCalculator minimalRotationPoseCalculator)
{
float bestScore;
Pose minimalRotationPose = minimalRotationPoseCalculator(desiredPose, snapPose);
if (scoringModifier.MaxDistance > 0)
{
Pose minimalTranslationPose = minimalTranslationPoseCalculator(desiredPose, snapPose);
bestPose = SelectBestPose(minimalRotationPose, minimalTranslationPose, desiredPose, scoringModifier, out bestScore);
}
else
{
bestPose = minimalRotationPose;
bestScore = PoseUtils.RotationalSimilarity(desiredPose.rotation, bestPose.rotation);
}
return bestScore;
}
/// <summary>
/// Compares two poses to a reference and returns the most similar one
/// </summary>
/// <param name="a">First pose to compare with the reference.</param>
/// <param name="b">Second pose to compare with the reference.</param>
/// <param name="reference">Reference pose to measure from.</param>
/// <param name="normalizedWeight">Position to rotation scoring ratio.</param>
/// <param name="maxDistance">Max distance to measure the score.</param>
/// <param name="bestScore">Out value with the score of the best pose.</param>
/// <returns>The most similar pose to reference out of a and b</returns>
private static Pose SelectBestPose(in Pose a, in Pose b, in Pose reference, PoseMeasureParameters scoringModifier, out float bestScore)
{
float aScore = PoseUtils.Similarity(reference, a, scoringModifier);
float bScore = PoseUtils.Similarity(reference, b, scoringModifier);
if (aScore >= bScore)
{
bestScore = aScore;
return a;
}
bestScore = bScore;
return b;
}
}
}

View File

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

View File

@@ -0,0 +1,281 @@
/************************************************************************************
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 System;
namespace Oculus.Interaction.HandPosing.SnapSurfaces
{
[Serializable]
public class SphereSurfaceData : ICloneable
{
public object Clone()
{
SphereSurfaceData clone = new SphereSurfaceData();
clone.centre = this.centre;
return clone;
}
public SphereSurfaceData Mirror()
{
SphereSurfaceData mirror = Clone() as SphereSurfaceData;
return mirror;
}
public Vector3 centre;
}
/// <summary>
/// Specifies an entire sphere around an object in which the grip point is valid.
///
/// One of the main advantages of spheres is that the rotation of the hand pose does
/// not really matters, as it will always fit the surface correctly.
/// </summary>
[Serializable]
public class SphereSurface : MonoBehaviour, ISnapSurface
{
[SerializeField]
protected SphereSurfaceData _data = new SphereSurfaceData();
/// <summary>
/// Getter for the data-only version of this surface. Used so it can be stored when created
/// at Play-Mode.
/// </summary>
public SphereSurfaceData Data
{
get
{
return _data;
}
set
{
_data = value;
}
}
[SerializeField]
private Transform _relativeTo;
[SerializeField]
private Transform _gripPoint;
/// <summary>
/// Transform to which the surface refers to.
/// </summary>
public Transform RelativeTo
{
get => _relativeTo;
set => _relativeTo = value;
}
/// <summary>
/// Valid point at which the hand can snap, typically the SnapPoint position itself.
/// </summary>
public Transform GripPoint
{
get => _gripPoint;
set => _gripPoint = value;
}
/// <summary>
/// The center of the sphere in world coordinates.
/// </summary>
public Vector3 Centre
{
get
{
if (RelativeTo != null)
{
return RelativeTo.TransformPoint(_data.centre);
}
else
{
return _data.centre;
}
}
set
{
if (RelativeTo != null)
{
_data.centre = RelativeTo.InverseTransformPoint(value);
}
else
{
_data.centre = value;
}
}
}
/// <summary>
/// The radius of the sphere, this is automatically calculated as the distance between
/// the center and the original grip pose.
/// </summary>
public float Radius
{
get
{
if (this.GripPoint == null)
{
return 0f;
}
return Vector3.Distance(Centre, this.GripPoint.position);
}
}
/// <summary>
/// The direction of the sphere, measured from the center to the original grip position.
/// </summary>
public Vector3 Direction
{
get
{
return (this.GripPoint.position - Centre).normalized;
}
}
/// <summary>
/// The rotation of the sphere from the recorded grip position.
/// </summary>
public Quaternion Rotation
{
get
{
return Quaternion.LookRotation(Direction, this.GripPoint.forward);
}
}
#region editor events
private void Reset()
{
_gripPoint = this.transform;
if (this.TryGetComponent(out HandGrabPoint grabPoint))
{
_relativeTo = grabPoint.RelativeTo;
}
}
#endregion
protected virtual void Start()
{
Assert.IsNotNull(_relativeTo);
Assert.IsNotNull(_gripPoint);
Assert.IsNotNull(_data);
}
public Pose MirrorPose(in Pose pose)
{
Vector3 normal = Quaternion.Inverse(RelativeTo.rotation) * Direction;
Vector3 tangent = Vector3.Cross(normal, Vector3.up);
return pose.MirrorPoseRotation(normal, tangent);
}
public bool CalculateBestPoseAtSurface(Ray targetRay, in Pose recordedPose, out Pose bestPose)
{
Vector3 projection = Vector3.Project(Centre - targetRay.origin, targetRay.direction);
Vector3 nearestCentre = targetRay.origin + projection;
float distanceToSurface = Mathf.Max(Vector3.Distance(Centre, nearestCentre) - Radius);
if (distanceToSurface < Radius)
{
float adjustedDistance = Mathf.Sqrt(Radius * Radius - distanceToSurface * distanceToSurface);
nearestCentre -= targetRay.direction * adjustedDistance;
}
Vector3 surfacePoint = NearestPointInSurface(nearestCentre);
Pose desiredPose = new Pose(surfacePoint, recordedPose.rotation);
bestPose = MinimalTranslationPoseAtSurface(desiredPose, recordedPose);
return true;
}
public float CalculateBestPoseAtSurface(in Pose targetPose, in Pose reference, out Pose bestPose, in PoseMeasureParameters scoringModifier)
{
return SnapSurfaceHelper.CalculateBestPoseAtSurface(targetPose, reference, out bestPose,
scoringModifier, MinimalTranslationPoseAtSurface, MinimalRotationPoseAtSurface);
}
public ISnapSurface CreateMirroredSurface(GameObject gameObject)
{
SphereSurface surface = gameObject.AddComponent<SphereSurface>();
surface.Data = _data.Mirror();
return surface;
}
public ISnapSurface CreateDuplicatedSurface(GameObject gameObject)
{
SphereSurface surface = gameObject.AddComponent<SphereSurface>();
surface.Data = _data;
return surface;
}
protected Vector3 NearestPointInSurface(Vector3 targetPosition)
{
Vector3 direction = (targetPosition - Centre).normalized;
return Centre + direction * Radius;
}
protected Pose MinimalRotationPoseAtSurface(in Pose userPose, in Pose snapPose)
{
Quaternion rotCorrection = Quaternion.FromToRotation(snapPose.up, Direction);
Vector3 correctedDir = (rotCorrection * userPose.up).normalized;
Vector3 surfacePoint = NearestPointInSurface(Centre + correctedDir * Radius);
Quaternion surfaceRotation = RotationAtPoint(surfacePoint, snapPose.rotation, userPose.rotation);
return new Pose(surfacePoint, surfaceRotation);
}
protected Pose MinimalTranslationPoseAtSurface(in Pose userPose, in Pose snapPose)
{
Vector3 desiredPos = userPose.position;
Quaternion baseRot = snapPose.rotation;
Vector3 surfacePoint = NearestPointInSurface(desiredPos);
Quaternion surfaceRotation = RotationAtPoint(surfacePoint, baseRot, userPose.rotation);
return new Pose(surfacePoint, surfaceRotation);
}
protected Quaternion RotationAtPoint(Vector3 surfacePoint, Quaternion baseRot, Quaternion desiredRotation)
{
Vector3 desiredDirection = (surfacePoint - Centre).normalized;
Quaternion targetRotation = Quaternion.FromToRotation(Direction, desiredDirection) * baseRot;
Vector3 targetProjected = Vector3.ProjectOnPlane(targetRotation * Vector3.forward, desiredDirection).normalized;
Vector3 desiredProjected = Vector3.ProjectOnPlane(desiredRotation * Vector3.forward, desiredDirection).normalized;
Quaternion rotCorrection = Quaternion.FromToRotation(targetProjected, desiredProjected);
return rotCorrection * targetRotation;
}
#region Inject
public void InjectAllSphereSurface(SphereSurfaceData data,
Transform relativeTo, Transform gripPoint)
{
InjectData(data);
InjectRelativeTo(relativeTo);
InjectGripPoint(gripPoint);
}
public void InjectData(SphereSurfaceData data)
{
_data = data;
}
public void InjectRelativeTo(Transform relativeTo)
{
_relativeTo = relativeTo;
}
public void InjectGripPoint(Transform gripPoint)
{
_gripPoint = gripPoint;
}
#endregion
}
}

View File

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