Interaction System
QWR SDK provides a powerful physics-based interaction system that allows users to grab, manipulate, and interact with objects in your XR application. This page explains how to use and customize the interaction system.
Interaction System Overview
The interaction system in QWR SDK includes:
- Physics-based grabbing and manipulation
- Distance grabbing with ray interaction
- Object snapping and placement
- Two-handed interactions
- Custom interaction behaviors
- Integration with Unity's physics system
Core Components
QWRInteractionManager
The QWRInteractionManager is the central component that coordinates all interactions between hands/controllers and objects in the scene.
// Access the interaction manager
QWRInteractionManager interactionManager = QWRInteractionManager.Instance;
// Register interactable objects
interactionManager.RegisterInteractable(myInteractable);
// Query interactions
bool isInteracting = interactionManager.IsInteracting(HandType.Right);
QWRInteractable currentObject = interactionManager.GetInteractedObject(HandType.Left);
QWRInteractor
The QWRInteractor component represents an entity that can interact with objects (like hands or controllers).
// Get interactors
QWRInteractor leftHandInteractor = QWRHandController.LeftHand.GetComponent<QWRInteractor>();
QWRInteractor rightHandInteractor = QWRHandController.RightHand.GetComponent<QWRInteractor>();
// Check if interactor is grabbing
bool isGrabbing = leftHandInteractor.IsGrabbing;
// Get currently grabbed object
QWRInteractable grabbedObject = leftHandInteractor.CurrentInteractable;
// Subscribe to interaction events
leftHandInteractor.OnGrabBegin += HandleGrabBegin;
leftHandInteractor.OnGrabEnd += HandleGrabEnd;
QWRInteractable
The QWRInteractable component makes an object interactable with hands and controllers.
// Create an interactable object
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
Rigidbody rb = cube.AddComponent<Rigidbody>();
QWRInteractable interactable = cube.AddComponent<QWRInteractable>();
// Configure interactable properties
interactable.grabType = GrabType.Both; // Can be grabbed by hands or controllers
interactable.twoHandedGrabEnabled = true; // Enable two-handed grabbing
interactable.throwVelocityMultiplier = 1.5f; // Increase throw velocity
// Subscribe to events
interactable.OnGrabbed += HandleObjectGrabbed;
interactable.OnReleased += HandleObjectReleased;
Making Objects Interactable
Basic Setup
To make an object interactable:
- Add a Rigidbody component to your object
- Add the
QWRInteractablecomponent - Configure the interaction settings
// Example: Setting up an interactable object
public GameObject CreateInteractableObject(Vector3 position)
{
// Create a cube
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.position = position;
// Add rigidbody
Rigidbody rb = cube.AddComponent<Rigidbody>();
rb.mass = 1.0f;
// Add interactable component
QWRInteractable interactable = cube.AddComponent<QWRInteractable>();
// Configure interactable properties
interactable.grabType = GrabType.Both;
interactable.snapToHand = true;
return cube;
}
Grab Types
The QWRInteractable component supports different grab types:
GrabType.Hand: Can only be grabbed by handsGrabType.Controller: Can only be grabbed by controllersGrabType.Both: Can be grabbed by both hands and controllersGrabType.None: Cannot be grabbed (but can still be touched)
Grab Points
You can define specific grab points on an object:
- Create empty GameObjects as children of your interactable object
- Position them where you want the hand/controller to grab
- Add the
QWRGrabPointcomponent to each grab point - Configure the grab point settings
// Example: Adding grab points programmatically
public void AddGrabPoints(QWRInteractable interactable)
{
// Create a grab point for the left hand
GameObject leftGrabPoint = new GameObject("LeftGrabPoint");
leftGrabPoint.transform.SetParent(interactable.transform);
leftGrabPoint.transform.localPosition = new Vector3(-0.1f, 0, 0);
QWRGrabPoint leftPoint = leftGrabPoint.AddComponent<QWRGrabPoint>();
leftPoint.handType = HandType.Left;
leftPoint.handPose = HandPose.Grab;
// Create a grab point for the right hand
GameObject rightGrabPoint = new GameObject("RightGrabPoint");
rightGrabPoint.transform.SetParent(interactable.transform);
rightGrabPoint.transform.localPosition = new Vector3(0.1f, 0, 0);
QWRGrabPoint rightPoint = rightGrabPoint.AddComponent<QWRGrabPoint>();
rightPoint.handType = HandType.Right;
rightPoint.handPose = HandPose.Grab;
}
Interaction Types
Direct Grabbing
Direct grabbing occurs when a hand or controller directly touches an interactable object.
// Configure direct grab settings
interactable.directGrabEnabled = true;
interactable.grabPriority = 10; // Higher priority objects are grabbed first
Ray Grabbing
Ray grabbing allows users to grab objects from a distance using a ray.
// Configure ray grab settings
interactable.rayGrabEnabled = true;
interactable.maxRayGrabDistance = 5.0f;
interactable.rayGrabOffset = new Vector3(0, 0, -0.2f);
Two-Handed Grabbing
Two-handed grabbing allows users to manipulate objects with both hands simultaneously.
// Configure two-handed grab settings
interactable.twoHandedGrabEnabled = true;
interactable.rotationMode = TwoHandedRotationMode.First; // First hand controls rotation
interactable.scaleEnabled = true; // Allow scaling with two hands
interactable.minScale = 0.5f;
interactable.maxScale = 2.0f;
Physics Interactions
Physics Grab Modes
The QWRInteractable component supports different physics grab modes:
PhysicsGrabMode.Kinematic: Object becomes kinematic when grabbed (default)PhysicsGrabMode.Velocity: Uses velocity to move the object (more physics-based)PhysicsGrabMode.Joint: Uses a configurable joint (most realistic)
// Configure physics grab mode
interactable.physicsGrabMode = PhysicsGrabMode.Joint;
// Configure joint settings (for Joint mode)
interactable.jointDamping = 10f;
interactable.jointSpring = 100f;
Throwing Objects
When releasing objects, velocity is applied to simulate throwing:
// Configure throwing behavior
interactable.throwVelocityMultiplier = 1.5f; // Increase throw velocity
interactable.throwAngularVelocityMultiplier = 1.0f; // Normal angular velocity
Advanced Interaction Features
Snapping and Placement
Objects can snap to predefined positions or surfaces:
// Configure snapping behavior
interactable.snapToSurface = true;
interactable.snapRotation = true;
interactable.snapDistance = 0.1f;
Custom Hand Poses
You can define custom hand poses for specific objects:
- Create a
QWRHandPoseDefinitionscriptable object - Configure the finger positions and rotations
- Assign it to the
QWRGrabPointcomponent
// Assign a custom hand pose
QWRGrabPoint grabPoint = GetComponent<QWRGrabPoint>();
grabPoint.customPose = myCustomPose;
Interaction Constraints
You can constrain how objects can be moved and rotated:
// Configure movement constraints
interactable.constrainMovement = true;
interactable.movementConstraints = new Vector3(1, 0, 1); // Only move on X and Z axes
// Configure rotation constraints
interactable.constrainRotation = true;
interactable.rotationConstraints = new Vector3(0, 1, 0); // Only rotate around Y axis
Custom Interaction Behaviors
Creating Custom Interactables
You can create custom interactable behaviors by inheriting from QWRInteractable:
public class CustomInteractable : QWRInteractable
{
// Override grab behavior
protected override void OnGrab(QWRInteractor interactor)
{
base.OnGrab(interactor);
// Custom grab behavior
Debug.Log("Custom grab behavior");
}
// Override release behavior
protected override void OnRelease(QWRInteractor interactor)
{
base.OnRelease(interactor);
// Custom release behavior
Debug.Log("Custom release behavior");
}
}
Creating Custom Interactors
You can create custom interactor behaviors by inheriting from QWRInteractor:
public class CustomInteractor : QWRInteractor
{
// Override hover behavior
protected override void OnHoverEnter(QWRInteractable interactable)
{
base.OnHoverEnter(interactable);
// Custom hover behavior
Debug.Log("Custom hover behavior");
}
// Override grab detection
protected override bool ShouldGrab()
{
// Custom grab detection logic
return base.ShouldGrab() && CustomCondition();
}
private bool CustomCondition()
{
// Your custom condition
return true;
}
}
UI Interaction
The interaction system integrates with Unity's UI system for XR interfaces.
UI Interaction Components
QWRUIInteractor: Allows hands/controllers to interact with UI elementsQWRUICanvas: Makes a Canvas interactable in XR
// Configure UI interaction
QWRUIInteractor uiInteractor = GetComponent<QWRUIInteractor>();
uiInteractor.uiLayerMask = LayerMask.GetMask("UI");
uiInteractor.pointerTriggerType = PointerTriggerType.ButtonPress;
Performance Considerations
Interactions can be performance-intensive. Here are some optimization tips:
- Use simpler colliders for interaction detection
- Adjust physics update rates based on your target platform
- Use the
PhysicsGrabMode.Kinematicfor better performance - Limit the number of simultaneously interactable objects
Troubleshooting
Objects Not Grabbable
If objects can't be grabbed:
- Ensure the object has a Rigidbody component
- Check that the
QWRInteractablecomponent is properly configured - Verify that the object's layer is included in the interaction layer mask
- Check for collider issues (missing collider or trigger collider)
Physics Issues
If you experience physics issues:
- Adjust the physics grab mode to suit your needs
- Check for collider overlaps or interpenetration
- Adjust Unity's physics settings (solver iterations, etc.)
- Consider using a different physics grab mode
Two-Handed Interaction Problems
If two-handed interactions aren't working correctly:
- Ensure
twoHandedGrabEnabledis set to true - Check that both hands can reach the object simultaneously
- Verify that the rotation and scaling modes are configured correctly
Next Steps
Now that you understand the interaction system, you can explore:
- UI Interaction: Learn how to create XR user interfaces
- Multiplayer: Discover how to synchronize interactions in multiplayer
- Hand Tracking: Explore advanced hand tracking features