Skip to content

Instantly share code, notes, and snippets.

@prnthp
Last active January 4, 2023 14:24
Show Gist options
  • Save prnthp/aa4d264bfcd951f39f54ede6ccb8d011 to your computer and use it in GitHub Desktop.
Save prnthp/aa4d264bfcd951f39f54ede6ccb8d011 to your computer and use it in GitHub Desktop.
Transformer for on axis rotations such as knobs. It is better than OneGrabRotateTransformer for this use case.
/************************************************************************************
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.Serialization;
namespace Oculus.Interaction
{
/// <summary>
/// A Transformer that rotates the target about the up axis.
/// Updates apply relative rotational changes of a GrabPoint about the up vector
/// of the pivot.
/// </summary>
public class OneGrabKnobTransformer : MonoBehaviour, ITransformer
{
[SerializeField, Optional]
private Transform _pivotTransform = null;
[SerializeField]
private Vector3 referencePoint;
[Serializable]
public class OneGrabRotateConstraints
{
public FloatConstraint MinAngle;
public FloatConstraint MaxAngle;
}
[SerializeField]
private OneGrabRotateConstraints _constraints;
public OneGrabRotateConstraints Constraints
{
get
{
return _constraints;
}
set
{
_constraints = value;
}
}
private float _relativeAngle = 0.0f;
private float _constrainedRelativeAngle = 0.0f;
private IGrabbable _grabbable;
private Pose _initialPose;
private Pose _previousGrabPose;
public void Initialize(IGrabbable grabbable)
{
_grabbable = grabbable;
}
public void BeginTransform()
{
var grabPoint = _grabbable.GrabPoints[0];
Transform pivot = _pivotTransform != null ? _pivotTransform : _grabbable.Transform;;
Vector3 rotationAxis = pivot.TransformDirection(Vector3.up);
_initialPose = new Pose(pivot.position, Quaternion.LookRotation(pivot.position - grabPoint.position, rotationAxis));
_previousGrabPose = grabPoint;
}
public void UpdateTransform()
{
var grabPoint = _grabbable.GrabPoints[0];
var targetTransform = _grabbable.Transform;
Transform pivot = _pivotTransform != null ? _pivotTransform : targetTransform;
Vector3 rotationAxis = pivot.TransformDirection(Vector3.up);
var targetPose = grabPoint.GetTransformedBy(_initialPose);
var previousPose = _previousGrabPose.GetTransformedBy(_initialPose);
var angleDelta = Vector3.SignedAngle(targetPose.up, previousPose.up, _initialPose.forward);
float previousAngle = _constrainedRelativeAngle;
_relativeAngle += angleDelta;
_constrainedRelativeAngle = _relativeAngle;
if (_constraints.MinAngle.Constrain)
{
_constrainedRelativeAngle = Mathf.Max(_constrainedRelativeAngle, _constraints.MinAngle.Value);
}
if (_constraints.MaxAngle.Constrain)
{
_constrainedRelativeAngle = Mathf.Min(_constrainedRelativeAngle, _constraints.MaxAngle.Value);
}
angleDelta = _constrainedRelativeAngle - previousAngle;
// Apply this angle rotation about the axis to our transform
targetTransform.RotateAround(pivot.position, rotationAxis, angleDelta);
_previousGrabPose = grabPoint;
}
public void EndTransform()
{
// Clamps relative angle to constraints to remove windup
if (_constraints.MinAngle.Constrain)
{
_relativeAngle = Mathf.Max(_constrainedRelativeAngle, _constraints.MinAngle.Value);
}
if (_constraints.MaxAngle.Constrain)
{
_relativeAngle = Mathf.Min(_constrainedRelativeAngle, _constraints.MaxAngle.Value);
}
}
#region Inject
public void InjectOptionalPivotTransform(Transform pivotTransform)
{
_pivotTransform = pivotTransform;
}
public void InjectOptionalConstraints(OneGrabRotateConstraints constraints)
{
_constraints = constraints;
}
#endregion
}
}

This Transfomer is useful for creating knob-style interactions where the user would typically rotate their wrist with a fixed pose to twist something.

Only the Up axis (green) is supported as the rotation axis with the up arrow pointing in the direction of the user.

Knobs1080.mp4

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment