Blender Dokumentation: Ein Beispielscript in Python
Diese Seite bezieht sich auf Blender v2.42a |
Ein Beispiel in Python
[Bearbeiten]Nun wissen Sie, dass Blender mit Python erweiterbar ist, wie man damit umgeht und ein Script ausführt. Bevor Sie Ihrem Gehirn nun die volle Breitseite mit der Python API Referenz geben, wollen wir uns erst ein kleines Beispiel zu Gemüte führen.
Wir bauen uns ein kleines Script, welches Polygone erzeugt. Das macht zwar so ziemlich das Gleiche wie die Space>>Add>>Mesh>>Circle Toolboxoption, es erzeugt aber 'gefüllte' Polygone - nicht nur die Aussenlinie.
Um das Script schön einfach bedienbar zu machen, spendieren wir ihm eine Benutzerschnittstelle (GUI), welche wir komplett mit der Blender API erzeugen.
Headers, Import von Modulen und globale Variablen
[Bearbeiten]Hier kommen die ersten 32 Zeilen des Scripts
Script Header
######################################################
#
# Demo Script für das Blender Handbuch
#
######################################################
# Diese Script erzeugt Polygone. Funktionell ist es
# überflüssig, da gefüllte Polygone mit
# ADD->Mesh->Circle erzeugt werden können. Aber es
# ist ein schönes, komplettes Beispielscript.
######################################################
######################################################
# Import der Module
######################################################
import Blender
from Blender import NMesh
from Blender.BGL import *
from Blender.Draw import *
import math
from math import *
# Polygon Parameters
T_NumberOfSides = Create(3)
T_Radius = Create(1.0)
# Events
EVENT_NOEVENT = 1
EVENT_DRAW = 2
EVENT_EXIT = 3
Zuerst kommt der Kommentar mit der Erklärung, was das Script macht. In den Zeilen 016-022 importieren wir die Pythonmodule:
- Blender ist das Blender-Python API Hauptmodul
- NMesh ist das Modul welches den Zugriff auf Blenders Meshes unterstützt,
- BGL gibt Zugriff auf die OpenGL Funktionen
- Draw gibt Zugriff auf Blenders Fensterschnittstelle
- Das math Modul ist, wie unschwer zu erraten, Pythons Mathemodul.
Wenn Sie Python nicht komplett installiert haben oder nicht wollen, dann ändern Sie die Zeilen
021 import math
022 from math import *
in
021 from Blender import Mathutils
022 from Blender.Mathutils import *
Die Polygone werden durch die Anzahl ihrer Seiten und ihren Radius definiert. Die Werte dieser Parameter werden durch den Benutzer über die GUI eingegeben. In den Zeilen 025-026 erzeugen wir zwei Generic Button Objekte mit ihren Startwerten.
Intern erzeugen die GUI-Objekte Events. Events IDs [Events identifier] sind Integer, die der Programmierer definiert. Es hat sich als sinnvoll erwiesen, den Events Mnemonic Namen zu geben, wie es hier in den Zeilen 029-031 gemacht wurde.
Zeichnen der GUI
[Bearbeiten]Der Code, der für das Zeichnen der GUI verantwortlich ist, wird in eine draw Funktion geschrieben.
######################################################
# Zeichnen der GUI
######################################################
def draw():
global T_NumberOfSides
global T_Radius
global EVENT_NOEVENT, EVENT_DRAW, EVENT_EXIT
########## Titel
glClear(GL_COLOR_BUFFER_BIT)
glRasterPos2d(8, 103)
Text('Demo Polygon Script')
######### Die Parameter der GUI Buttons
glRasterPos2d(8, 83)
Text("Parameter:")
T_NumberOfSides = Number('Anz. Seiten: ', EVENT_NOEVENT, 10, 55, 210, 18,
T_NumberOfSides.val, 3, 20, 'Anzahl der Polygonaussenkanten');
T_Radius = Slider('Radius: ', EVENT_NOEVENT, 10, 35, 210, 18,
T_Radius.val, 0.001, 20.0, 1, 'Radius des Polygons');
######### Zeichnen- und Exitbuttons
Button('Zeichnen',EVENT_DRAW , 10, 10, 80, 18)
Button('Exit',EVENT_EXIT , 140, 10, 80, 18)
Die Zeilen 037-039 gewähren lediglich Zugriff auf globale Daten. Wirklich interessant wird es erst ab den Zeilen 042-044. Hier wird das OpenGL Fenster initialisiert und auf die Position X=8 und Y=103 gesetzt. Dabei wird die linke untere Ecke des Scriptfensters als Ausgangspunkt angenommen. Dort wird der Titel Demo Polygon Script ausgegeben.
Unter dem String Parameter: (Zeilen 047-048) werden die Buttons für die Parameter erzeugt. Der Erste ist ein Number Buttom (Zeile 049-050), wie er in den verschiedenen Buttons Fenstern von Blender zu finden ist. Grundsätzliche Parameter sind:
- der Buttonname (das was draufsteht)
- das Event, welches durch den Button ausgelöst wird
- die Position (x,y), die Größe (Höhe, Breite)
- der Initialwert
- der minimal und maximal mögliche Wert
- einen String, welcher als Tooltip erscheint, wenn Sie mit der Maus darüberfahren.
Schauen Sie bitte in die API-Referenz für mehr Informationen über die Parameter.
In den Zeilen 051-052 wird ein Number Button mit einem Slider definiert. Die Zeilen 055-056 erzeugen einen Klickbutton mit dem Titel 'Zeichnen', welcher das Polygon generiert, und einen Exit Button.
Eventbehandlung
[Bearbeiten]Die GUI wird nicht ohne den dazugehörigen und registrierten Eventhandler gezeichnet.
def event(evt, val):
if (evt == QKEY and not val):
Exit()
def bevent(evt):
global T_NumberOfSides
global T_Radius
global EVENT_NOEVENT, EVENT_DRAW, EVENT_EXIT
######### GUI Events behandeln
if (evt == EVENT_EXIT):
Exit()
elif (evt== EVENT_DRAW):
Polygon(T_NumberOfSides.val, T_Radius.val)
Blender.Redraw()
Register(draw, event, bevent)
In den Zeilen 058-060 wird ein Eventhandler für die Tastatur definiert, welcher auf das Drücken der Q-Taste mit dem Aufruf der Funktion Exit() reagiert und das Script verlässt.
Viel interessanter sind die Zeilen 062-072, da sie die GUI Events steuern. Diese Funktion wird jedes Mal aufgerufen, wenn ein GUI Button benutzt wird. Ihr wird die Eventnummer der Buttons als Parameter übergeben. Der Kern dieser Funktion ist daher eine "Switch" Struktur, die je nach Event verschiedenen Code ausführt.
Als letztes wird die Register Funktion aufgerufen. Sie zeichnet schlußendlich die GUI und startet eine Dauerschleife für die Eventerfassung.
Meshes
[Bearbeiten]Am Ende kommen wir noch zur Hauptfunktion [main function], die das Polygon erzeugt. Hier wird eigentlich einfach nur ein Mesh editiert, aber es offenbart eine Menge wichtiger Punkte der internen Datenstruktur von Blender.
######################################################
# Hauptfunktion
######################################################
def Polygon(NumberOfSides,Radius):
######### Erstellt ein neues Mesh
poly = NMesh.GetRaw()
######### Fügt Vertices zu dem Mesh hinzu
for i in range(0,NumberOfSides):
phi = 3.141592653589 * 2 * i / NumberOfSides
x = Radius * cos(phi)
y = Radius * sin(phi)
z = 0
v = NMesh.Vert(x,y,z)
poly.verts.append(v)
######### Fügt einen neuen Vertex in die Mitte ein
v = NMesh.Vert(0.,0.,0.)
poly.verts.append(v)
######### Verbindet die Vertices zu einem Face
for i in range(0,NumberOfSides):
f = NMesh.Face()
f.v.append(poly.verts[i])
f.v.append(poly.verts[(i+1)%NumberOfSides])
f.v.append(poly.verts[NumberOfSides])
poly.faces.append(f)
######### Erstellt ein neues Objekt aus dem Mesh
polyObj = NMesh.PutRaw(poly)
Blender.Redraw()
Die erste wichtige Zeile ist 082. Hier wird ein neues Meshobjekt namens poly erzeugt. Das Meshobjekt besteht aus einer Reihe Vertices und Faces, plus einigen anderen interessanten Sachen. Für unsere Zwecke reichen die Vertices und Faces aus.
Naturgemäß ist ein neues Mesh leer. Die erste Schleife in den Zeilen 085-092 errechnet die x,y,z Position der NumberOfSides Vertices, welche für das Erzeugen des Polygons nötig sind. Weil z=0 ist, ist das Polygon flach.
Die Zeile 091 ruft die Methode vert von NMesh auf, die ein neues Vertexobjekt mit den Koordinaten (x,y,z) erzeugt. Dieses Objekt wird dann in die verts' Liste des Meshobjekts poly hinzugefügt (Zeile 092).
Zum Schluss wird noch ein letztes Vertex in die Mitte eingefügt (Zeilen 095-096).
Die Zeilen 099-104 verbinden die Vertices um ein Face zu erstellen. Es ist nicht notwendig zuerst alle Vertices und dann die Faces zu erstellen. Ein neues Face kann erstellt werden, wenn alle seine Vertices erstellt sind.
Die Zeile 100 erzeugt ein neues Faceobjekt. Ein Faceobjekt bringt seine eigene, leere, Liste v (mehr als 4 Vertices) mit, wodurch es definiert wird. Die Zeilen 101-103 fügen der leeren Liste f.v 3 Vertices hinzu. Die Vertices sind 2 nachfolgende Vertices des Polygons und des zentralen Vertice. Diese Vertices müssen von der Meshliste verts genommen werden. Die letzte Zeile der Schleife 104 fügt das neu erzeugte Face der faces Liste unseres Meshobjektes poly hinzu.
Ergebnis
[Bearbeiten]Erstellen Sie nun eine Datei polygon.py mit dem Code als Inhalt und laden Sie sie in Blenders Textfenster, wie es oben erklärt wurde. Drücken Sie nun Alt-P um das Script zu starten. Das Textfenster wird grau und in der linken unteren Ecke wird die GUI gezeichnet.
Wenn Sie nun, sagen wir mal, 5 Vertices und einen Radius von 0.5 einstellen und auf den Zeichnen Button drücken, erscheint eine XZ Ebene im 3D Fenster.
Scriptlisting
[Bearbeiten]Hier ist das Script ohne Zeilennummern:
import Blender
from Blender import NMesh
from Blender.BGL import *
from Blender.Draw import *
import math
from math import *
# Polygon Parameters
T_NumberOfSides = Create(3)
T_Radius = Create(1.0)
# Events
EVENT_NOEVENT = 1
EVENT_DRAW = 2
EVENT_EXIT = 3
######################################################
# Zeichnen der GUI
######################################################
def draw():
global T_NumberOfSides
global T_Radius
global EVENT_NOEVENT, EVENT_DRAW, EVENT_EXIT
########## Titel
glClear(GL_COLOR_BUFFER_BIT)
glRasterPos2d(8, 103)
Text('Demo Polygon Script')
######### Die Parameter der GUI Buttons
glRasterPos2d(8, 83)
Text("Parameter:")
T_NumberOfSides = Number('Anz. Seiten: ', EVENT_NOEVENT, 10, 55, 210, 18,
T_NumberOfSides.val, 3, 20, 'Anzahl der Polygonaussenkanten');
T_Radius = Slider('Radius: ', EVENT_NOEVENT, 10, 35, 210, 18,
T_Radius.val, 0.001, 20.0, 1, 'Radius des Polygons');
######### Zeichnen- und Exitbuttons
Button('Zeichnen',EVENT_DRAW , 10, 10, 80, 18)
Button('Exit',EVENT_EXIT , 140, 10, 80, 18)
def event(evt, val):
if (evt == QKEY and not val):
Exit()
def bevent(evt):
global T_NumberOfSides
global T_Radius
global EVENT_NOEVENT, EVENT_DRAW, EVENT_EXIT
######### GUI Events behandeln
if (evt == EVENT_EXIT):
Exit()
elif (evt== EVENT_DRAW):
Polygon(T_NumberOfSides.val, T_Radius.val)
Blender.Redraw()
Register(draw, event, bevent)
######################################################
# Main Body
######################################################
def Polygon(NumberOfSides,Radius):
######### Creates a new mesh
poly = NMesh.GetRaw()
######### Populates it of vertices
for i in range(0,NumberOfSides):
phi = pi * 2 * i / NumberOfSides
x = Radius * cos(phi)
y = Radius * sin(phi)
z = 0
v = NMesh.Vert(x,y,z)
poly.verts.append(v)
######### Adds a new vertex to the center
v = NMesh.Vert(0.,0.,0.)
poly.verts.append(v)
######### Connects the vertices to form faces
for i in range(0,NumberOfSides):
f = NMesh.Face()
f.v.append(poly.verts[i])
f.v.append(poly.verts[(i+1)%NumberOfSides])
f.v.append(poly.verts[NumberOfSides])
poly.faces.append(f)
######### Creates a new Object with the new Mesh
polyObj = NMesh.PutRaw(poly)
Blender.Redraw()