The HandController script is attached to the HandController prefab. The prefab serves as the anchor point for drawing hands. You can set the HandController properties, such as which hand prefabs to use, in the Inspector panel.


When you play the scene, any hands detected by the Leap Motion controller are drawn relative to the position and orientation of the prefab.


If your hand is 20cm above the Leap Motion device, the virtual hand is drawn 20cm above the prefab position (if the HandController transform scale is set to 1.0). Do note that the default scale is 20:1, so hands are drawn much larger than real-size. In the Unity Scene view, the approximate field of view of the Leap Motion sensors are shown.

class HandController

The Controller object that instantiates hands and tools to represent the hands and tools tracked by the Leap Motion device.

HandController is a Unity MonoBehavior instance that serves as the interface between your Unity application and the Leap Motion service.

The HandController script is attached to the HandController prefab. Drop a HandController prefab into a scene to add 3D, motion-controlled hands. The hands are placed above the prefab at their real-world relationship to the physical Leap device. You can change the transform of the prefab to adjust the orientation and the size of the hands in the scene. You can change the HandController.handMovementScale property to change the range of motion of the hands without changing the apparent model size.

When the HandController is active in a scene, it adds the specified 3D models for the hands to the scene whenever physical hands are tracked by the Leap Motion hardware. By default, these objects are destroyed when the physical hands are lost and recreated when tracking resumes. The asset package provides a variety of hands that you can use in conjunction with the hand controller.

Public Functions

void DestroyAllHands()

Destroys all hands owned by this HandController instance.

string FinishAndSaveRecording()

Saves the current recording to a new file, returns the path, and starts playback.

string The path to the saved recording.

HandModel [] GetAllGraphicsHands()

Returns a copy of the hand model list.

HandModel [] GetAllPhysicsHands()

Returns a copy of the physics model list.

LeapDeviceInfo GetDeviceInfo()

Returns information describing the device hardware.

Frame GetFixedFrame()

NOTE: This method should ONLY be called from within a FixedUpdate callback.

Unity Physics runs at a constant frame step, where the physics time between each FixedUpdate is the same. However there is a big difference between the physics timeline and the real timeline. In Unity, these timelines can be very skewed, where the actual times FixedUpdate is called can vary greatly. For example, the graph below shows the real times when FixedUpdate was called.


The graph shows major clustering occuring of FixedUpdate calls, rather than an even spread. Specifically, Unity always executes all of the FixedUpdate calls at the begining of an Update frame, and then performs interpolation to convert physics objects from the physics timeline to the real timeline.

This causes an issue when we need to aquire a Leap Frame from within FixedUpdate, since we need to provide a Frame to the physics timeline, but the Leap provides frames from the real timeline. The image below shows what happens when we simply sample controller.Frame() from within FixedUpdate. The X axis represents Time.fixedTime, and the Y axis represents the Frame.Timestamp


The graph shows how, from the perspective of the physics timeline, the Frames are arriving in a jagged way, staying the same for a large amount of time before jumping a large amount forward. Ideally we would be able to take advantage of the full 120FPS of frames the service provides, properly interpolated into the physics timeline.

GetFixedFrame attempts to establish a conversion from the real timeline to the physics timeline, to provide both uniformly sampled Frames, as well as not introducing latency. The graph below shows a comparison between the naive method of sampling the most recent frame (red), and the usage of GetFixedFrame (green). The X axis represents Time.fixedTime while the Y axis represents the Frame.Timestamp obtained by the 2 methods


As the graph shows, the GetFixedFrame method can significantly help solve the judder that can occur when sampling controller.Frame while in FixedUpdate.

ALSO: If the recorder object is playing a recording, then the frame is taken directly from the recording, with no timeline synchronization performed.

Frame GetFrame()

Returns the latest frame object.

If the recorder object is playing a recording, then the frame is taken from the recording. Otherwise, the frame comes from the Leap Motion Controller itself.

The returned frame does not contain any image data, use GetImageFrame() for that.

Controller GetLeapController()

Returns the Leap Controller instance.

LeapRecorder GetLeapRecorder()

Returns the Leap Recorder instance used by this Hand Controller.

float GetRecordingProgress()

The current frame position divided by the total number of frames in the recording.

void IgnoreCollisionsWithHands(GameObject to_ignore, bool ignore = true)

Turns off collisions between the specified GameObject and all hands.

Subject to the limitations of Unity Physics.IgnoreCollisions(). See .

bool IsConnected()

True, if the Leap Motion hardware is plugged in and this application is connected to the Leap Motion service.

void PauseRecording()

Stops playback or recording without resetting the frame counter.

void PlayRecording()

Start getting frames from the LeapRecorder object rather than the Leap service.

void Record()

Starts saving frames.

void ResetRecording()

Discards any frames recorded so far.

void StopRecording()

Stops recording or playback and resets the frame counter to the beginning.

Public Members

bool destroyHands

If hands are in charge of Destroying themselves, make this false.

bool enableRecordPlayback

Set true to enable recording.

Vector3 handMovementScale

The scale factors for hand movement.

Set greater than 1 to give the hands a greater range of motion.

bool isHeadMounted

Set true if the Leap Motion hardware is mounted on an HMD; otherwise, leave false.

bool isMain

There always should be exactly one main HandController in the scene, which is reffered to by the HandController.Main getter.

HandModel leftGraphicsModel

The GameObject containing graphics to use for the left hand or both hands if separateLeftRight is false.

HandModel leftPhysicsModel

The GameObject containing colliders to use for the left hand or both hands if separateLeftRight is false.

bool mirrorZAxis

Reverses the z axis.

bool overrideDeviceType

If enabled, do not query the controller to determine device type, but instead always return a specific device.

LeapDeviceType overrideDeviceTypeWith

If overrideDeviceType is enabled, the hand controller will return a device of this type.

bool recorderLoop

Whether to loop the playback.

float recorderSpeed

Playback speed.

Set to 1.0 for normal speed.

TextAsset recordingAsset

The file to record or playback from.

HandModel rightGraphicsModel

The graphics hand model to use for the right hand.

HandModel rightPhysicsModel

The physics hand model to use for the right hand.

bool separateLeftRight

Whether to use a separate model for left and right hands (true); or mirror the same model for both hands (false).

ToolModel toolModel

The GameObject containing both graphics and colliders for tools.