Leap Motion

Fragen zu Gimp, Terragen und sonstigen Programmen.

Leap Motion

Beitragvon MagBen » 07.08.2013, 20:38

Seit einiger Zeit beschäftige ich mich Leap Motion in Zusammenhang mit OpenSceneGraph: https://code.google.com/p/osgleap/

Jetzt möchte ich es mit Leap Motion zusammen mit Blender versuchen. Für's Modellieren ist Leap Motion wohl noch zu unpräzise bzw. das Ergebnis zu Zufällig. Für die BGE könnte es aber reizvoll sein: Die rechte Hand ist die Waffe oder das Werkzeug und die linke Hand steuert die Bewegung.

Man findet ein bisschen was wenn man nach "Leap + Motion + Blender" sucht, aber ich habe noch nichts Funktionierendes gesehn. Kennt jemand einen Link zu einer Seite, einem Video oder Forum wo etwas Funktionierendes vorgestellt wird?

Ich wollte es über die Python-Schnittstelle probieren. Dabei gibt vor der eigentlich Programmierung des Bewegungs-Handlers zwei Probleme zu lösen:
  • Die mitgelieferte Python-Schnittstelle von Leap Motion ist für Python 2
  • Wenn man in Blender (unter Linux) eigene in C++ geschriebene Python-Module einbinden will, dann müssen diese auf die gleiche Art kompiliert werden wie Blender. Das kriegt man nur hin, wenn man auch Blender auf dem eigenen PC selbst baut.
Sobald ich diese Probleme gelöst habe, würde ich gerne mit einem Blender-Spieleentwickler zusammenarbeiten, der Interesse daran hat, sein Blender-Spiel um eine Gestensteuerung zu erweitern.
a fool with a tool is still a fool, www.magben.de, YouTube
Benutzeravatar
MagBen
 
Registriert:
27.05.2013, 19:57

Re: Leap Motion

Beitragvon MagBen » 15.08.2013, 19:26

Die Leap Motion Bibliothek habe ich in Blender nun am Laufen, d.h. ich konnte das Python Beispiel Sample.py von Leap Motion in Blender ausführen. Der Installationskram ist damit fertig, nun kann die eigentliche Programmierung beginnen.

Im Detail:
Ich arbeite unter Ubuntu 12.04, ich habe davon eine 32bit und eine 64bit Installation. Unter 64bit habe ich Leap Motion überhaupt nicht zum Laufen bekommen. Die Linux Unterstützung von Leap Motion ist etwas schlechter als die Windows und Apple Unterstützung. Aber unter 32bit läuft es immerhin, also versuche ich es unter 32bit in Blender zum Laufen zu bekommen.

Will man in C++ entwickelte und selbst kompilierte Python Module in Blender einbinden, dann müssen diese genauso kompiliert werden wie Blender selbst. Deshalb muss erstmal Blender selbst kompiliert werden. Also habe ich die Blender-Sourcen runtergeladen (blender-2.68.tar.gz, 40 MB) und cmake aufgerufen. cmake sagt einem dann was alles fehlt. Da ich sowieso schon auf dem Rechner mit C++ und OpenGL (d.h. OpenSceneGraph) entwickele fehlte nicht soviel:
  • Python 3.3. Auf Ubuntu 12.04 ist über Synaptic Paketverwaltung nur Python 3.2 erhältlich und das cmake Skript von Blender 2.68 besteht aber auf Python 3.3. Also habe ich auch die Python 3.3 Sourcen runtergeladen (Python-3.3.2.tar.bz2, 14 MB) und kompiliert.
  • Bei der Boost Bibliothek hat mir einiges gefehlt. Hier gilt es zu beachten, dass unter Ubuntu 12.04 in der Synaptic Paketverwaltung sowohl 1.46 als auch 1.48 verfügbar sind. Diese dürfen aber nicht gemischt werden und bei 1.46 fehlt das locale Modul. Mit libboost1.48-all-dev bekommt man alle benötigten Boost Module.
Danach konnte ich Blender 2.68 übersetzen.

Als nächstes muss die Python Schnittstelle von Leap Motion neu erstellt werden, unter http://www.warp1337.com/content/leap-motion-sdk-python3-python-33-ubuntu steht eine funktionierende Schritt für Schritt Anleitung wie das geht.

Fertig!

Ich kann nun in Python einen Listener implementieren und an den Leap Motion Controller übergeben. Die wichtigste zu implementierende Methode ist
Code: Alles auswählen
def on_frame(self, frame):
on_frame wird von Leap Motion 60-70 mal pro Sekunde aufgerufen. Über das frame Objekt kann man Hand Objekte bekommen und über die Hand Objekte kommt man an die Finger Objekte. Man bekommt somit 60-70 mal pro Sekunde die Position der Fingerspitzen und die Richtung des äußersten Fingergliedes. Daraus kann man sich dann seine Gestensteurung basteln. Als erstes Beispiel wollte ich in Blender eine sehr simple Hand modellieren und die Bewegungen zweier solcher Handmodelle in der BGE mit der Bewegung meiner Hände synchronisieren.
a fool with a tool is still a fool, www.magben.de, YouTube
Benutzeravatar
MagBen
 
Registriert:
27.05.2013, 19:57

Re: Leap Motion

Beitragvon MagBen » 24.08.2013, 20:25

Ein erstes kleines Beispiel habe ich nun am Laufen. Einige Besonderheiten der Leap Motion API habe ich hier bei BlendPolis schon in diesem Beitrag beschrieben: http://www.blendpolis.de/viewtopic.php?f=15&t=45461#p483614.

Ich habe zwei einfache Hände konstruiert und im 3DViewer per Leap Motion mit meinen Händen gesteuert:http://youtu.be/dhiCGVMnYPo

Jede Hand besteht aus 11 einzelnen Objekten (Handballen, 5 Fingerspitzen, 5 Fingerglieder) deren location und rotation ich in jedem Leap Motion Frame setze.
LeapMotionHand.jpg
animiert
LeapMotionHand2.jpg
Konstruktionsansicht
LeapMotionHand.blend
(754.46 KiB) 181-mal heruntergeladen

Das Python Skript:
Code: Alles auswählen
import Leap
import bpy
from mathutils import *

class Hand(object):
    def __init__(self, palm, fingerTips, fingerMiddles):
        self.palm = palm
        self.fingerTips = fingerTips
        self.fingerMiddles = fingerMiddles
       
        self.palm.rotation_mode = 'QUATERNION'
        for f in self.fingerTips:
            f.rotation_mode = 'QUATERNION'
        for f in self.fingerMiddles:
            f.rotation_mode = 'QUATERNION'

        self.scale = 20
        self.ex = Vector((1,0,0))
        self.ez = Vector((0,0,-1))
       
    def plotHand(self, leapHand):
        usedFingers = 0
        palmValid = False
        if(leapHand and leapHand.is_valid):
            palmValid = True
           
            palmValid = True
            palm_position, palm_quat = self.calcTrafo(leapHand.palm_position, leapHand.palm_normal, self.ez, self.scale)
            self.palm.location = palm_position
            self.palm.rotation_quaternion = palm_quat
           
            for i in range(len(leapHand.fingers)):
                lf = leapHand.fingers[i]
                if lf.is_valid:
                    bf = self.fingerTips[usedFingers]
                    bm = self.fingerMiddles[usedFingers]
                    usedFingers += 1
                   
                    bf.hide = False
                    tip_position, tip_quat = self.calcTrafo(lf.tip_position, lf.direction, self.ex, self.scale)
                    bf.location            = tip_position
                    bf.rotation_quaternion = tip_quat
                   
                    bm.hide = False
                    m1 = lf.tip_position-lf.direction*30.
                    m2 = leapHand.palm_position-m1
                    mid_position, mid_quat = self.calcTrafo(m1, m2, self.ex, self.scale)
                    bm.location            = mid_position
                    bm.rotation_quaternion = mid_quat

        self.palm.hide = not palmValid
        for i in range(usedFingers,5):
            self.fingerTips[i].hide = True
            self.fingerMiddles[i].hide = True
           
    def calcTrafo(self, leapPosition, leapDirection, e_i, scale):
        position = Vector((leapPosition[0], leapPosition[1], -leapPosition[2]))/scale
        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)

class HandListener(Leap.Listener):
    def __init__(self):
         super(HandListener,self).__init__()
         self.frame = None
         self.hand_R = Hand(bpy.data.objects["palm_R"],
                            [bpy.data.objects["fing%i_R" % (i+1)] for i in range(5)],
                            [bpy.data.objects["m%i_R"    % (i+1)] for i in range(5)])
         self.hand_L = Hand(bpy.data.objects["palm_L"],
                            [bpy.data.objects["fing%i_L" % (i+1)] for i in range(5)],
                            [bpy.data.objects["m%i_L"    % (i+1)] for i in range(5)])

    def on_frame(self, controller):
        self.frame = controller.frame()
        if len(self.frame.hands)>0: 
            self.hand_R.plotHand(self.frame.hands[0])
            if len(self.frame.hands)>1:   
                self.hand_L.plotHand(self.frame.hands[1])
            else:
                self.hand_L.plotHand(None)
        else:
            self.hand_R.plotHand(None)
            self.hand_L.plotHand(None)
       
l = HandListener()
c = Leap.Controller(l)
print(c.is_connected)
a fool with a tool is still a fool, www.magben.de, YouTube
Benutzeravatar
MagBen
 
Registriert:
27.05.2013, 19:57

Re: Leap Motion

Beitragvon MagBen » 25.08.2013, 11:10

Heute morgen habe ich Leap Motion in der BGE zum Laufen bekommen:
http://youtu.be/3Y6XCTqn3fw
http://youtu.be/OcysVd_X3qI
WrigglingFingers.jpg

In der BGE läuft es nun auch richtig stabil. Vorher geschah der Update der Geometrie im Leap Motion Thread und dabei stürzte Blender immer mal wieder ab. In der BGE wird der Update der Geometrie von einem Always Sensor getriggert und damit läuft der Update außerhalb des Leap Motion Threads.

Es gibt einen Keybord Sensor der mit der Leertaste die Leap Motion Initialisierung triggert und einen Always Sensor der den Geometrie Update triggert. Der Keybord Sensor ist verbunden mit einem Python Controller der das folgende Skript enthält, StartupController.py:
Code: Alles auswählen
import Leap
import bge
from mathutils import *

class Hand(object):
    def __init__(self, palm, fingerTips, fingerMiddles):
        self.palm = palm
        self.fingerTips = fingerTips
        self.fingerMiddles = fingerMiddles
       
        self.scale = 20
        self.ex = Vector((1,0,0))
        self.ez = Vector((0,0,-1))
       
    def plotHand(self, leapHand):
        usedFingers = 0
        palmValid = False
        if(leapHand and leapHand.is_valid):
            palmValid = True
           
            palmValid = True
            palm_position, palm_quat = self.calcTrafo(leapHand.palm_position, leapHand.palm_normal, self.ez, self.scale)
            self.palm.worldPosition = palm_position
            self.palm.worldOrientation = palm_quat
           
            for i in range(len(leapHand.fingers)):
                lf = leapHand.fingers[i]
                if lf.is_valid:
                    bf = self.fingerTips[usedFingers]
                    bm = self.fingerMiddles[usedFingers]
                    usedFingers += 1
                   
                    bf.visible = True
                    tip_position, tip_quat = self.calcTrafo(lf.tip_position, lf.direction, self.ex, self.scale)
                    bf.worldPosition = tip_position
                    bf.worldOrientation = tip_quat
                   
                    bm.visible  = True
                    m1 = lf.tip_position-lf.direction*30.
                    m2 = leapHand.palm_position-m1
                    mid_position, mid_quat = self.calcTrafo(m1, m2, self.ex, self.scale)
                    bm.worldPosition = mid_position
                    bm.worldOrientation  = mid_quat

        self.palm.setVisible(palmValid)
        for i in range(usedFingers,5):
            self.fingerTips[i].setVisible(  False)
            self.fingerMiddles[i].setVisible(False)
           
    def calcTrafo(self, leapPosition, leapDirection, e_i, scale):
        position = Vector((leapPosition[0], leapPosition[1], -leapPosition[2]))/scale
        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 HandListener(Leap.Listener):
    def __init__(self, scene):
         super(HandListener,self).__init__()
         self.frame = None
         self.hand_R = Hand(scene.objects["palm_R"],
                            [scene.objects["fing%i_R" % (i+1)] for i in range(5)],
                            [scene.objects["m%i_R"    % (i+1)] for i in range(5)])
         self.hand_L = Hand(scene.objects["palm_L"],
                            [scene.objects["fing%i_L" % (i+1)] for i in range(5)],
                            [scene.objects["m%i_L"    % (i+1)] for i in range(5)])

    def on_frame(self, controller):
        self.frame = controller.frame()
       
    def plotHands(self):
        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 "handListener" not in scene:
    handListener = HandListener(scene)
    scene["handListener"] = handListener
    scene["LeapMotionController"] = Leap.Controller(handListener)

Auch der Always Sensor ist mit einem Python Controller verbunden, dieser Python Controller enthält das folgende Skript, HandController.py
Code: Alles auswählen
import bge
scene = bge.logic.getCurrentScene()
if "handListener" in scene:
    handListener = scene["handListener"]
    handListener.plotHands()

Die Blend-Datei
WrigglingFingers.blend
(766.63 KiB) 230-mal heruntergeladen
a fool with a tool is still a fool, www.magben.de, YouTube
Benutzeravatar
MagBen
 
Registriert:
27.05.2013, 19:57

Re: Leap Motion

Beitragvon MagBen » 15.09.2013, 18:59

Leap Motion als Flight-Controller in Open-Street-Map Innenstadt
http://www.youtube.com/watch?v=GUoQDZb05to

In Open-Street-Map kann man eine komplette Innenstadt runterzuladen und diese dann in Blender importieren (hier für Bremen: http://www.blendpolis.de/viewtopic.php?f=25&t=33201&p=485194#p485194). Diesmal habe ich Landshut gewählt:
Landshut1.jpg

In der BGE habe ich nun mit Leap Motion einen Flight-Controller realisiert. Der Python Code ist im wesentlichen der gleiche wie bei der Handvisualisierung. Es wird nun zusätzlich zur Hand-Visualisierung die Kamera in Handrichtung gedreht und bewegt, fertig ist der Flight-Controller.

Die blend-Datei mit Innenstadt ist hier für das Forum zu groß (11MB). Ich lade hier deshalb eine blend-datei hoch, die nur den Flight-Controller enthält, die Innenstadt (oder irgendein anderes Modell) muss noch hinzugefügt werden.
stroll-in-empty-town.blend
(610.27 KiB) 198-mal heruntergeladen
a fool with a tool is still a fool, www.magben.de, YouTube
Benutzeravatar
MagBen
 
Registriert:
27.05.2013, 19:57


Zurück zu Andere Software


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste