Übung 3 - Operatoren & Addons
Bisher sind alle Funktionalitäten, die wir mit unseren Scripten erstellt haben auch nur als solche ausführbar - als Script im Texteditor. In dieser Übung wollen wir das ändern und Blender selbst um eine Benutzeroberfläche für die Generierung unseres Turms erweitern
Operatoren
Wir haben bereits die ops
Kategorie des bpy
Moduls kennengelernt. Nun wollen wir unseren eigenen Operator schreiben, der dann auch über die API aufgerufen und mit der F3
-Suche gefunden werden kann.
- öffne im Text Editor das “Operator Simple” Template.
Sehen wir uns hier nun ersteinmal die Klasse SimpleOperator an
class SimpleOperator(bpy.types.Operator):
"""Tooltip"""
bl_idname = "object.simple_operator"
bl_label = "Simple Object Operator"
@classmethod
def poll(cls, context):
return context.active_object is not None
def execute(self, context):
main(context)
return {'FINISHED'}
- Mit der Deklaration
class SimpleOperator(bpy.types.Operator)
geben wir an, dass unsere Klasse ein Operator ist - also vonbpy.types.Operator
erbt. - Darunter können wir mit
"""Mein Tooltipp"""
eine Beschreibung angeben, die dem Nutzer beim überfahren des Operators mit dem Cursor angezeigt wird. bl_idname
ist der pfad API-Pfad unter dem der Operator aufrufbar sein wird"object.simple_operator"
lässt sich dann mitbpy.ops.object.simple_operator()
aufrufen.bl_label
-
Die
poll
Methode ist optional. Sie ist eine statische Methode (daher@classmethod
) und benötigt daher keine Instanz der Klasse, um aufgerufen zu werden.cls
ist hier die Referenz auf die sie beinhaltende Klasse selbst (währendself
immer eine Instanz referenziert). Poll empfängt zudem den aktuellen Kontex -
Die
execute
Methode ist der tatsächlich ausgeführte Code beim aufrufen des Operators. Ihr wird hierself
übergeben (in Python wird überself.meine_variable
auf Membervariablen der aktuellen Klasseninstanz zugegriffen) und wiederum der aktuelle Kontext.
Der ausgeführte Code wurde hier in die main
Methode ausgelagert. Diese könnte auch anders heißen und andere Parameter haben. In diesem Beispiel wird über jedes Objekt in der aktuellen Szene context.scene.objects
iteriert und dieses in der Konsole ausgegeben. for
lässt dich in Python nutzen wie foreach
in anderen Sprachen.
Schließlich fallen noch die beiden Methoden register
und unregister
auf. Diese sind außerhalb des Klassenrumpfes und dienen zur Registrierung der Klassen in der API bzw zur Deregistrierung bei Deaktivierung des Addons.
Wenn viele Klassen zu registrieren sind, lässt sich auch die
register_classes_factory
nutzen, der ein Tuple an Klassen übergeben wird.register, unregister = bpy.utils.register_classes_factory( (MeineKlasse1, MeineKlasse2, MeineKlasse3,) )
- Zu guter Letzt folgen die etwas kryptische Zeilen
if __name__ == "__main__":
register()
# test call
bpy.ops.object.simple_operator()
Die Überprüfung if __name__ == "__main__"
überprüft dabei lediglich, ob das Script gerade über den Texteditor gestartet wird oder einfach nur als Modul importiert wurde. Hier kann also Code untergebracht werden, der nicht ausgeführt wird, wenn das Script als Addon installiert wird. In diesem Fall also die Registrierung des Operators in der API und ein Testlauf.
- Stelle sicher, dass Preferences → Interface → Developer Extras aktiviert ist (nur dann lassen sich so erstellte Operatoren mit F3 suchen)
- Führe das Skript Operator Simple im Texteditor aus
- Öffne die Systemkonsole mit Window → Toggle System Console
- Suche im mit F3 nach Simple Object Operator
In der Systemkonsole wird nun eine Liste der Objekte in der Szene ausgegeben.
blender.exe
found bundled python: C:\Blender\daily\blender-2.91.0-7ff6bfd1e0af-windows64\2.91\python <bpy_struct, Object("Cube") at 0x000001D2821FC088> <bpy_struct, Object("Light") at 0x000001D2821FC608> <bpy_struct, Object("Camera") at 0x000001D2821FBB08>>}}
Properties
Die wenigsten Operatoren sind einfach so ohne weitere Angaben ausführbar. Fast alle Operatoren lassen sich in ihrer Funktionalität durch Parameter beeinflussen. In Blender heißen solche Parameter von Operatoren Properties.
Properties lassen sich ganz einfach als Eigenschaften der Klasse, die den Operator definiert implementieren (also die Klasse, die von bpy.types.Operator
erbt und die eine execute
-Methode definiert). Hierzu können innerhalb des Klassenrumpfes Eigenschaften definiert werden, denen ein Aufruf einer der folgenden Funktionen zugewiesen wird.
bpy.props.IntProperty
bpy.props.BoolProperty
bpy.props.FloatProperty
bpy.props.FloatVectorProperty
Diesem Funktionsaufruf werden dann name
(Label des Operators in der GUI), sowie optional eine description
und ein default
- Wert zugewiesen.
my_float: bpy.props.FloatProperty(
name="My Float",
description="does stuff with the thing.",
default = 1)
Es handelt sich hierbei nicht um klassische Variablendeklaration. Wir weisen keinen Wert einer Python-Variablen hinzu, wir sagen Blender nur: “Erstelle in deiner internen Datenstruktur eine Float-Variable mit diesem Namen etc.”
import bpy
def main(context, loc):
for ob in context.scene.objects:
ob.location = loc
Passt das Operator Simple Template folgendermaßen an:
Zunächst legen wir in der Operatorklasse eine
FloatVectorProperty
an und weisen ihr Name, Beschreibung und Defaultwert zu.Nun können wir unsere Property anwenden. Diese sind innerhalb der Klasse über das Schlüsselwort
self
(ähnlich wiethis
in anderen Sprachen) aufrufbar. In diesem Beispiel Fügen wir unserermain
Methode einen Parametervalue
hinzu und übergeben bei deren Aufruf in derexecute
Methodeself.my_vector
.Damit beim Ausführen des Operators auch etwas passiert, ändern wir in
main
die Position jedes Objekts zu diesem Wert.Sind die Properties so der Operatorklasse hinzugefügt, sind sie bei Aufruf des Operators über die Python Konsole bereits einstellbar.
- Führe das Script aus und teste den Operator mit der Python-Konsole:
>>> bpy.ops.object.simple_operator(my_vec=(2,2,2))
Alle Objekte in der Szene sollten nun an die Position (2, 2, 2) verschoben werden.
import bpy
def main(context, loc):
for ob in context.scene.objects: ob.location = loc
class SimpleOperator(bpy.types.Operator): """Tooltip""" bl_idname = "object.simple_operator" bl_label = "Simple Object Operator" bl_options = {"REGISTER", "UNDO"}
@classmethod def poll(cls, context): return context.active_object is not None def execute(self, context): main(context, self.my_vec) return {'FINISHED'} my_vec: bpy.props.FloatVectorProperty( name='My Vector', description='does stuff with the thing.', default = (1, 1, 1))
def register(): bpy.utils.register_class(SimpleOperator)
def unregister(): bpy.utils.unregister_class(SimpleOperator)
if name == "main": register()
# test call bpy.ops.object.simple_operator()
- Damit Properties nun auch in einem Menü beim Aufruf des Operators eingestellt werden können, müssen wir das Blender in der Operatorklasse mit einer weiteren bl_… Zeile:
bl_options = {"REGISTER", "UNDO"}
sagen.- Testet den Operator mit dem
F3
Suchmenü im Viewport
Wandelt das Turmgenerator-Skript vom letzten mal in einen Operator um und macht dessen Parameter zu Operator-Properties.
Addons
bl_info
Dictionary (rechts) angegeben, dass wir ganz oben in unser Skript einfügen. Verpflichtend anzugeben sind dabei nur Name, Author und Kategorie.bl_info = {
"name": "Cubedimension",
"author": "Ich <ich@webmail.hs-furtwangen.de>",
"version": (1, 0),
"blender": (2, 91, 0),
"location": "View3D > Search Menu > Cubedimension",
"description": "Creates a cool Cube Dimension",
"warning": "Nur ausfüllen falls es etwas zu warnen gibt",
"doc_url": "",
"category": "Add Mesh",
}
Nicht selbsterklärende Parameter von bl_info
version |
gibt die (frei wählbare) Versionsnummer des Addons an. |
blender |
ist die Blender Version, mit der das Addon getestet wurde (was nicht heißt, dass es nicht auch in anderen Versionen funktionieren kann) |
location |
zeigt den Weg zur UI des Addons (nur als Anleitung für den Nutzer) |
doc_url |
Link zur Dokumentation, falls diese existiert (was meist wünschenswert ist) |
category |
Gibt die Kategorie unter der das Addon in den Einstellungen angezeigt wird |
Wandelt das Turmgenerator-Skript nun in ein Addon um und installiert es. Auch die Deinstallation sollte reibungslos klappen.
Ressourcen & Tutorials zum Thema
Art/Länge | Titel | Beschreibung | Quelle |
---|---|---|---|
22min | Your Own Operator - Scripting for Artists [8] | Operators | Blender Cloud - Dr. Sybren A. Stüvel |
10min | From Script to Add-on - Scripting for Artists [9] | Operators | Blender Cloud - Dr. Sybren A. Stüvel |