Leap Motion®
ist ein eingetragenes Warenzeichen.
www.leapmotion.com
Fragen & Antworten
Python Forum: Leap Motion: animierte Hände

Blendpolis: Leap Motion

Blender Datei
Die Blender Datei mit dem kompletten Modellen und dem Quellcode: WrigglingFingers.blend

Making-of

Leap Motion für Python 3

Leap Motion hat eine Python-Schnittstelle. Jedoch nur für Python 2.7, nicht für Python 3, das in Blender benutzt wird.
In leapmotion.zendesk.com/entries/39433657-Generating-a-Python-3-3-0-Wrapper-with-SWIG-2-0-9
wird beschrieben, wie man sich die Schnittstelle für Python 3 mit swig und Visual Studio unter Windows selbst bauen kann.
In www.kobashicomputing.com/64-bit-c-development-under-visual-studio-2012-express
wird beschrieben, wie man mit dem kostenlosen Visual Studio 2012 Express 64bit dlls bauen kann.

Konstruktion der Hände

Die Hände werden in Blender aus mehreren Objekten konstruiert. Die Handfläche, die 5 Fingerspitzen und die 5 Fingerzwischenglieder sind jeweils eigene Blender-Objekte. Dadurch können alle diese Objekte unabhängig voneinnader animiert werden. Hände Blender Wireframe Hände Blender

Blender Game Engine

Ein Keyboard Sensor wird mit einem Python Controller verbunden. Der Python Controller enthält das Script StartupController.py. Nachdem die Blender Game Engine gestartet ist, beginnt die Animation der Hände erst nachdem der Benutzer eine Taste gedrückt hat.

Ein Always Sensor wird mit einem weiteren Python Controller verbunden. Der Python Controller enthält das Script StartupController.py. Das Plotten der Hände in der jeweils aktuellen Position wird damit ca. 24 Mal pro Sekunde angestoßen. Leap Motion Blender Game Engine Die Blender Datei mit dem kompletten Modellen und dem Quellcode: WrigglingFingers.blend

Python Code

StartupController.py
import Leap
import bge
from mathutils import Vector, Quaternion

# Relativ zu dieser Richtung werden die aktuellen Finger Richtungen berechnet.
DIRECTION_FINGER = Vector((1,0,0))

# Relativ zu dieser Richtung wird die Richtung der Normalen der handinnenflaeche berechnet.
DIRECTION_PALM   = Vector((0,0,-1))

# Umrechnung von LeapMotion Einheiten zu Blender Einheiten.
# Einheit von LeapMotion: mm
# Blender: Hand ist 5 Blender Units lang.
SCALE_LEAP_2_BGE = 1/20.

# Laenge in LeapMotion Koordinatensystem.
INTERMEDIATE_FINGER_SIZE = 30. # mm


def calcTrafo(leapPosition, leapDirection, e_i):
    """
    Umrechnung der LeapMotion Position und Richtung zu Blender Position und Drehmatrix.
        - Spiegelung der Z-Koordinate
        - Skallierung von Leap-Motion zu Blender Einheiten
        - Berechnung des Drehwinkels unf der Drehachse
        - Berechnung der Drehmatrix 
    """
    position  = Vector((leapPosition[ 0], leapPosition[ 1], 
                        -leapPosition[ 2]))*SCALE_LEAP_2_BGE
    direction = Vector((leapDirection[0], leapDirection[1], 
                        -leapDirection[2])).normalized()
    ang  = e_i.angle(direction)
    axis = e_i.cross(direction).normalized()
    return position, Quaternion(axis, ang).to_matrix()


class Hand(object):
    """
    Entaelt die Blender Objekte einer Hand:
        1 Handflaeche,
        5 Fingerspitzen,
        5 Fingerzwischenglieder (eine echte Hand hat 5x2 Zwischenglieder)
    """
    
    def __init__(self, palm, fingerTips, fingerIntermediates):
        self.palm = palm
        self.fingerTips = fingerTips
        self.fingerIntermediates = fingerIntermediates
        
        
    def plotHand(self, leapHand):
        """
        Plottet die Hand in der aktuellen Position.
        @param leapHand: Alle Infos von LeapMotion im aktuellen Frame zu dieser Hand.
        """
        usedFingers = 0
        palmValid = False
        if(leapHand and leapHand.is_valid):
            palmValid = True
            
            palmValid = True
            palm_position, palm_quat = calcTrafo(leapHand.palm_position, 
                                                 leapHand.palm_normal, DIRECTION_PALM)
            self.palm.worldPosition = palm_position
            self.palm.worldOrientation = palm_quat
            
            for leapFinger in leapHand.fingers:
                if leapFinger.is_valid:
                    fingerTip = self.fingerTips[usedFingers]
                    fingerIntermediate = self.fingerIntermediates[usedFingers]
                    usedFingers += 1
                    
                    fingerTip.visible = True
                    tip_position, tip_quat = calcTrafo(leapFinger.tip_position, 
                                                       leapFinger.direction, 
                                                       DIRECTION_FINGER)
                    fingerTip.worldPosition    = tip_position
                    fingerTip.worldOrientation = tip_quat
                    
                    fingerIntermediate.visible  = True
                    m1 = leapFinger.tip_position \
                        -leapFinger.direction*INTERMEDIATE_FINGER_SIZE
                    m2 = leapHand.palm_position-m1
                    m_position, m_quat = calcTrafo(m1, m2, DIRECTION_FINGER)
                    fingerIntermediate.worldPosition     = m_position
                    fingerIntermediate.worldOrientation  = m_quat

        self.palm.setVisible(palmValid)
        
        # nicht erkannte Finger verbergen
        for i in range(usedFingers,5):
            self.fingerTips[i].setVisible(  False)
            self.fingerIntermediates[i].setVisible(False)
            
            
class HandController(Leap.Listener):
    """
    Empfaengt Ereignisse von LeapMotion und von der Blender-Game-Engine
    und leitet diese an die Haende weiter.
    """
    
    def __init__(self, scene):
         super(HandController,self).__init__()
         self.frame = None
         self.hand_R = Hand( scene.objects["palm_R"],
                    [scene.objects["finger_tip_%i_R"          % (i+1)] for i in range(5)],
                    [scene.objects["finger_intermediate_%i_R" % (i+1)] for i in range(5)])
         self.hand_L = Hand( scene.objects["palm_L"],
                    [scene.objects["finger_tip_%i_L"          % (i+1)] for i in range(5)],
                    [scene.objects["finger_intermediate_%i_L" % (i+1)] for i in range(5)])

    def on_frame(self, leapMotionController):
        """
        Wird vom LeapMotionController aufgerufen.
        Aufruffrequenz: ca. 70 Hz
        """
        self.frame = leapMotionController.frame()
        
    def plotHands(self):
        """
        Wird von Blender-game-Engine aufgerufen.
        Aufruffrequenz: ca. 24 Hz
        """
        
        # Der aktuelle Frame self.frame wird sich vor dem Ende dieser Methode
        # eventuell mehrmals geaendert haben
        frame = self.frame
        
        if len(frame.hands)>0:  
            self.hand_R.plotHand(frame.hands[0])
            if len(frame.hands)>1:   
                self.hand_L.plotHand(frame.hands[1])
            else:
                self.hand_L.plotHand(None)
        else:
            self.hand_R.plotHand(None)
            self.hand_L.plotHand(None)

            
scene = bge.logic.getCurrentScene()
if "handController" not in scene:
    handController = HandController(scene)
    scene["handController"] = handController
    scene["leapMotionController"] = Leap.Controller(handController)
HandPlotter.py
import bge
scene = bge.logic.getCurrentScene()
if "handController" in scene:
    scene["handController"].plotHands()

Animierte Hände

Animierte Hände Animierte Hände Animierte Hände