320 likes | 746 Views
Oculus Rift DK2 + Leap Motion Unity Tutorial. Chris Zaharia @ chrisjz. Content. Leap Motion VR Hand tracking using Leap SDK V2 (Skeletal Tracking) Object interaction Movement using Rift DK2 positional tracking. Leap Motion SDK V2. Currently in beta Introduces skeletal tracking.
E N D
Oculus Rift DK2 + Leap Motion Unity Tutorial Chris Zaharia @chrisjz
Content • Leap Motion VR • Hand tracking using Leap SDK V2 (Skeletal Tracking) • Object interaction • Movement using Rift DK2 positional tracking
Leap Motion SDK V2 • Currently in beta • Introduces skeletal tracking
Augmented Reality • Image API • Infrared & Night Vision • Enable in Leap Motion Control Panel > Settings > General > Allow Images • Leap Oculus Passthrough Unity Package • Next Leap Motion may have colour camera
Requirements • IDE • Unity Pro • Leap • Leap Motion Driver • Leap Motion V2 Tracking Beta (v.2.1.1.21671+) • Leap Motion V2 Skeletal Assets (beta) • Rift DK2 • Unity 4 Pro Integration
Scope • Map physical hand and finger movements to 3D hand model and physics • Grab physics objects (rigidbodies) by pinching • Movement and jump using DK2’s positional tracker
Leap Motion - Unity File Structure • LeapMotion • Materials • Blinn2.mat • Gloves.mat • Hands_Alt_blinn1.mat • Models • HandsRealistic.fbx • Prefabs • Hand Graphics • RigidLeftHand.prefab • RigidRightHand.prefab • Hand Physics • ThickRigidHand.prefab • HandController.prefab
LeapMotion • … • Scripts • Hand • FingerModel.cs • HandModel.cs • RiggedFinger.cs • RiggedHand.cs • RigidFinder.cs • RigidHand.cs • SkeletalFinger.cs • SkeletalHand.cs • Tools • ToolModel.cs • Utils • LeapRecorder.cs • LeapUnityExtensions.cs • MagneticPinch.cs • HandController.cs
Plugins • [Include all files]
Attach hands to player • Assumed that you’ve already integrated Rift with player • Is compatible with Sixense’sRazer Hydra integration via script (see LeapHandExtendController.cs in tutorial)
Create empty GameObject called “LeapHandController” and place under OvrCameraController. • Either attach the HandControllerprefab to game object or attach HandController.cs script. • Fill out variables with the following:
Setup RigidLeftHand + RigidRightHand prefabs • Check if both prefabs are set as follows or change accordingly. MagneticPinch.cs script allows user to grab rigidbodies by pinching fingers
Each finger must have the following variables, based on type of finger (i.e. index, pinky) and if it’s left (starts with L) or right (starts with R): For right hand, choose the [..]Arm3 mesh
Setup ThickRigidHand prefab • Gives the hand collisions and physics • Can therefore push objects
Magnetic Pinch Script • Allows user to grab closest object which has a rigidbody • Force Spring Constant sets the elasticity of the grip to object • Magnetic Distance determines how close an object must be from a hand for it to be grabbed Warning: There is a conflict between Magnetic Pinch and enabling the Left/Right Physics Models. You’d need to fix this conflict by making the magnetic script ignore the hand’s physics
Grab Hand and Grabbable scripts • As an alternative to Magnetic Pinch script • Assign GrabHand.cs to hand graphic prefab • Assign Grabbable.cs to rigidbody object to be grabbed
Hand Physics • Interact with objects in a realistic way • Grab small objects with one hand • Grab larger objects with multiple hands • Push/Pull other objects • Other possibilities • Grabbable objects must have colliders Currently, grasping objects with hands is still quite jittery. Future SDK or Leap hardware updates should improve on this hopefully.
Handle conflicts with other hand trackers • This approach will hide/disable Sixense hands if leap motion detects leap hands in scene • Start by extending Leap Motion’s HandController.cs
LeapHandExtendController.cs (1) using UnityEngine; using System.Collections; using Leap; public class LeapHandExtendController : HandController { protected Controller leap_controller_; protected void Awake () { leap_controller_ = new Controller(); }
LeapHandExtendController.cs (2) protected void LateUpdate () { if (leap_controller_ == null) return; CheckIfHandsEnabled (); }
LeapHandExtendController.cs (3) protected void CheckIfHandsEnabled () { Frame frame = leap_controller_.Frame(); HandList hands = frame.Hands; intnum_hands = hands.Count; if (num_hands > 0) { TriggerSixenseHands (false); } else { TriggerSixenseHands (true); } }
Movement - DK2 Positional Tracking • Move/Jump by using DK2’s positional tracking • Move forward or backward by moving head in those directions • Either rotate or strafe sideways by moving head left/right • Jump by popping head upwards • Could crouch too by popping head downwards • User should normally be positioned directly in front of DK2’s tracker
Logic - Positional Tracking Movement • Create/modify your player input controller script, attached to player • Head position is calculated by subtracting the initial local position of the main camera, of when scene is loaded, from its current position • Create configurable Vector3 variables for: • Sensitivity – strength multiplier of movement or jump actions • Minimum – The minimum position that the Rift must be away from the centre position, for the action to actually be triggered • Movement will use the X (-left/+right) and Z axis (+forward/-backward) in the direction of the camera as a variable sent to the Character Motor’s inputMoveDirection variable • Jump will use the Y axis and will be mapped to the Character Motor’s inputJump variable
Code – Positional Track Movement [RequireComponent(typeof(CharacterMotor))] public class FPSInputController : MonoBehaviour { … public boolovrMovement = false; // Enable move player by moving head on X and Z axis public boolovrJump = false; // Enable player jumps by moving head on Y axis upwards public Vector3 ovrControlSensitivity = new Vector3(1, 1, 1); // Multiplier of positiona tracking move/jump actions public Vector3 ovrControlMinimum = new Vector3(0, 0, 0); // Min distance of head from centre to move/jump public enumOvrXAxisAction { Strafe = 0, Rotate = 1 } public OvrXAxisActionovrXAxisAction = OvrXAxisAction.Rotate; // Whether x axis positional tracking performs strafing or rotation private GameObjectmainCamera; // Camera where movement orientation is done and audio listener enabled private CharacterMotor motor; // OVR positional tracking, currently works via tilting head private Vector3 initPosTrackDir; private Vector3 curPosTrackDir; private Vector3 diffPosTrackDir;
Start + Update void Start() { … initPosTrackDir = mainCamera.transform.localPosition; } void Update() { // Get the input vector from OVR positional tracking if (ovrMovement || ovrJump) { curPosTrackDir = mainCamera.transform.localPosition; diffPosTrackDir = curPosTrackDir - initPosTrackDir; }
Update (continued) … if (ovrMovement) { if (diffPosTrackDir.x <= -ovrControlMinimum.x || diffPosTrackDir.x >= ovrControlMinimum.x) { if (ovrXAxisAction == OvrXAxisAction.Strafe) { diffPosTrackDir.x *= ovrControlSensitivity.x; } else { transform.Rotate(0, diffPosTrackDir.x * ovrControlSensitivity.x, 0); diffPosTrackDir.x = 0; } } else { diffPosTrackDir.x = 0; }
Update (continued) … if (diffPosTrackDir.z <= -ovrControlMinimum.z || diffPosTrackDir.z >= ovrControlMinimum.z) { diffPosTrackDir.z *= ovrControlSensitivity.z; } else { diffPosTrackDir.z = 0; } directionVector = new Vector3(diffPosTrackDir.x, 0, diffPosTrackDir.z); }
Update (continued) if (ovrJump) { if (diffPosTrackDir.y > ovrControlMinimum.y) { motor.inputJump = true; } else { motor.inputJump = false; } } else { motor.inputJump = Input.GetButton ("Jump"); } … motor.inputMoveDirection = mainCamera.transform.rotation * directionVector; // performs actual movement