Tutorial sobre complements¶
Públic objectiu¶
Aquest tutorial està dissenyat perquè artistes tècniques o desenvolupadores aprenguin a estendre els usos de Blender. S’espera una comprensió dels conceptes bàsics de Python per a aquelles que vulguin seguir i treballar amb aquest tutorial.
Prerequisits¶
Abans de passar pel tutorial, cal que…
Conegueu les bases de com es treballa amb el Blender.
Sapigueu executar un protocol a l’Editor de text de Blender.
Proveu de tenir alguna idea dels tipus de primitius de Python (enter(integer), booleà(Boolean), cadena(string), llista(list), tupla(tuple), diccionari(dictionary) i conjunt(set).
Conegueu els conceptes dels mòduls de Python.
Tingueu una comprensió bàsica de les classes (orientació a objecte) en Python.
Lectures recomanades abans d’iniciar el tutorial.
Dive Into Python seccions (1, 2, 3, 4 i 7).
Blender API Quickstart ajuda a familiaritzar-se amb les bases de Blender/Python.
Per a prevenir millor incidències amb la impressió de missatges d’error de Python mentres escriviu protocols, executeu Blender des d’un terminal. Vegeu Ús del terminal.
Truc
Podeu habilitar Extres de desenvolupadores a les preferències per a habilitar funcionalitats que faciliten el desenvolupament de complements.
Enllaços de documentació¶
Mentre feu el tutorial, és possible que vulgueu consultar la nostra documentació de referència.
Blender API Overview: aquest document és bastant detallat però útil si voleu saber més sobre un tema.
Referència de l’API
bpy.context– pràctica per a tenir una llista d’elements disponibles amb què eventualment operi el vostre protocol.bpy.types.Operator– els següents complements defineixen els operadors, aquests documents donen detalls i més exemples d’operadors.
Què és un complement?¶
Un complement és simplement un mòdul de Python amb alguns requisits addicionals perquè el Blender el pugui mostrar en una llista amb informació útil.
Per posar un exemple, aquí hi ha el complement més simple possible:
bl_info = {
"name": "My Test Add-on",
"blender": (2, 80, 0),
"category": "Object",
}
def register():
print("Hello World")
def unregister():
print("Goodbye World")
bl_infoés un diccionari que conté metadades de complements, com el títol, la versió i l’autor, que es mostraran a la llista de complements a Preferències. També especifica la versió mínima de Blender necessària per a executar el protocol; les versions més antigues no mostraran el complement a la llista.
registerés una funció que només s’executa quan s’habilita el complement, que vol dir que el mòdul es pot carregar sense activar el complement.
unregisterés una funció per a descarregar qualsevol element de
register. S’invoca quan el complement està inhabilitat.
Fixeu-vos que aquest complement no fa res relacionat amb el Blender (no s’importa el mòdul blender_api:bpy, per exemple).
Aquí hi ha un exemple d’un complement imaginari que serveix per il·lustrar la idea que els requisits bàsics d’un complement són simples.
Un complement normalment registrarà operadors, plafons, elements de menú, etc., però val la pena assenyalar que qualsevol protocol pot fer això, quan s’executa des de l’Editor de text o fins i tot la consola interactiva – no hi ha res inherentment diferent en un complement que li permeti d’integrar-se amb el Blender, aquesta funcionalitat només és proporcionada pel mòdul blender_api:bpy perquè qualsevol protocol hi pugui accedir.
Per tant, un complement és només una manera d’encapsular un mòdul de Python d’una manera que una usuària pot utilitzar fàcilment.
Nota
L’execució d’aquest protocol dins de l’Editor de text no imprimirà res. Per a veure l’egressió, s’ha d’instal·lar a través de les Preferències. Els missatges s’imprimiran quan s’habiliti i es deshabiliti.
El vostre primer complement¶
El complement susdit és el més simple possible i és útil com a exemple i poca cosa més. Aquest següent complement és senzill però mostra com integrar un protocol al Blender utilitzant un Operator, que és la manera típica de definir una eina a la qual s’accedeix des de menús, botons i dreceres de teclat.
Per al primer exemple farem un protocol que simplement mogui tots els objectes d’una escena.
Escriure el protocol¶
Afegiu el següent protocol a l’Editor de text de Blender:
import bpy
scene = bpy.context.scene
for obj in scene.objects:
obj.location.x += 1.0
Feu clic al Botó execució de protocol. Tots els objectes de l’escena activa es mouen d’1,0 unitat.
Escriure el complement (senzill)¶
Aquest complement agafa el cos del protocol anterior i l’afegeix a la funció d’un operador execute(). :
bl_info = {
"name": "Move X Axis",
"blender": (2, 80, 0),
"category": "Object",
}
import bpy
class ObjectMoveX(bpy.types.Operator):
"""My Object Moving Script""" # Use this as a tooltip for menu items and buttons.
bl_idname = "object.move_x" # Unique identifier for buttons and menu items to reference.
bl_label = "Move X by One" # Display name in the interface.
bl_options = {'REGISTER', 'UNDO'} # Enable undo for the operator.
def execute(self, context): # execute() is called when running the operator.
# The original script
scene = context.scene
for obj in scene.objects:
obj.location.x += 1.0
return {'FINISHED'} # Lets Blender know the operator finished successfully.
def menu_func(self, context):
self.layout.operator(ObjectMoveX.bl_idname)
def register():
bpy.utils.register_class(ObjectMoveX)
bpy.types.VIEW3D_MT_object.append(menu_func) # Adds the new operator to an existing menu.
def unregister():
bpy.utils.unregister_class(ObjectMoveX)
# This allows you to run the script directly from Blender's Text editor
# to test the add-on without having to install it.
if __name__ == "__main__":
register()
Nota
bl_info es divideix en múltiples línies; és només una convenció d’estil utilitzada per a afegir elements amb més facilitat.
Nota
En lloc d’utilitzar bpy.context.scene, utilitzem l’argument context.scene passat a execute(). En la majoria dels casos, seran la mateixa cosa. No obstant això, en alguns casos, els operadors passaran un context personalitzat, de manera que els autors del protocol haurien de preferir l’argument context passat als operadors.
Per provar el protocol, podeu copiar-lo i enganxar-lo a l’Editor de text de Blender i executar-lo. Això executarà el protocol directament i invocarà immediatament el registre.
No obstant això, executar el protocol no mourà pas cap objecte. Per a això, cal executar l’operador que acabem de registrar.
Menú de cerca d’operadors.¶
Obriu el menú Cerca d’operadors i escriviu «Move X by One» (la bl_label) i després Retorn.
Els objectes s’haurien de moure com abans.
Mantingueu obert aquest complement al Blender per al pas següent - Instal·lació.
Instal·lar el complement¶
Un cop tingueu el complement a l’Editor de text del Blender, voldreu poder-lo instal·lar perquè es pugui habilitar a les Preferències i així es carregui a l’inici.
Tot i que el complement susdit és de prova, fem tots els passos de totes maneres, perquè sapigueu com fer-ho després.
Per a instal·lar el text del Blender com a complement, primer haureu de desar-lo al disc. Vigileu de seguir les restriccions de noms que s’apliquen als mòduls de Python i acabeu-lo amb una extensió .py.
Un cop el document sigui al disc, el podreu instal·lar com ho faríeu per a un complement descarregat en línia.
Obriu les i seleccioneu el document.
Ara es llistarà el complement i podreu habilitar-lo marcant la casella i, si el voleu habilitat en reiniciar, pitgeu Desar com a predeterminat. L’operador es pot executar de la mateixa manera que s’ha descrit a la secció anterior.
Quan el complement està habilitat, el Blender executa el codi i executa la funció register(). Quan el complement està deshabilitat, el Blender executa la funció unregister().
Nota
La destinació del complement depèn de la configuració del Blender. Quan s’instal·la un complement, les rutes d’origen i de destinació s’imprimeixen a la consola. També podeu trobar les ubicacions de les rutes dels complements executant això a la Consola de Python:
import addon_utils
print(addon_utils.paths())
Hi ha més informació sobre aquest tema aquí: Disposició de directoris.
El vostre segon complement¶
Per al nostre segon complement, ens centrarem en la instanciació d’objectes – és a dir – en fer còpies connectades d’un objecte d’una manera similar al que podeu haver vist amb el modificador Corrua.
Escriure el protocol¶
Com abans, primer començarem amb un protocol, el desenvoluparem i després el convertirem en un complement.
import bpy
from bpy import context
# Get the current scene
scene = context.scene
# Get the 3D cursor location
cursor = scene.cursor.location
# Get the active object (assume we have one)
obj = context.active_object
# Now make a copy of the object
obj_new = obj.copy()
# The new object has to be added to a collection in the scene
scene.collection.objects.link(obj_new)
# Now we can place the object
obj_new.location = cursor
Ara proveu de copiar aquest protocol al Blender i executeu-lo sobre el Cub per defecte. Assegureu-vos que feu clic per a moure el cursor 3D abans d’executar-lo, ja que el duplicat apareixerà a la ubicació del cursor.
Després d’executar-se, tingueu en compte que quan aneu a Mode edició per a canviar el cub – totes les còpies canvien. A Blender, això es coneix com a Duplicats vinculats.
A continuació, en farem en un bucle a fi de crear una corrua d’objectes entre l’objecte actiu i el cursor.
import bpy
from bpy import context
scene = context.scene
cursor = scene.cursor.location
obj = context.active_object
# Use a fixed value for now, eventually make this user adjustable
total = 10
# Add 'total' objects into the scene
for i in range(total):
obj_new = obj.copy()
scene.collection.objects.link(obj_new)
# Now place the object in between the cursor
# and the active object based on 'i'
factor = i / total
obj_new.location = (obj.location * factor) + (cursor * (1.0 - factor))
Proveu d’executar aquest protocol amb l’objecte actiu i el cursor separats per veure’n el resultat.
Amb aquest protocol notareu que estem fent alguns càlculs amb la ubicació de l’objecte i el cursor. Això funciona perquè tots dos són instàncies de mathutils.Vector en 3D, una classe molt pràctica proporcionada pel mòdul mathutils que permet multiplicar els vectors per nombres i matrius.
Si us interessa aquesta àrea, llegiu mathutils.Vector – hi ha moltes funcions útils com ara obtenir l’angle entre vectors, producte vectorial, productes escalars, així com funcions més avançades a mathutils.geometry, com són interpolacions de spline de Bézier i les interseccions de raigs-triangle.
De moment ens centrarem en fer d’aquest protocol un complement, però és bo saber que aquest mòdul de càlcul 3D està disponible i pot ajudar-vos amb funcionalitats més avançades en un futur.
Escriure el complement¶
El primer pas és convertir el protocol tal qual està en un complement:
bl_info = {
"name": "Cursor Array",
"blender": (2, 80, 0),
"category": "Object",
}
import bpy
class ObjectCursorArray(bpy.types.Operator):
"""Object Cursor Array"""
bl_idname = "object.cursor_array"
bl_label = "Cursor Array"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
scene = context.scene
cursor = scene.cursor.location
obj = context.active_object
total = 10
for i in range(total):
obj_new = obj.copy()
scene.collection.objects.link(obj_new)
factor = i / total
obj_new.location = (obj.location * factor) + (cursor * (1.0 - factor))
return {'FINISHED'}
def register():
bpy.utils.register_class(ObjectCursorArray)
def unregister():
bpy.utils.unregister_class(ObjectCursorArray)
if __name__ == "__main__":
register()
Tot el que hi ha aquí ho hem tractat en els passos anteriors. Tot i així, podeu provar d’executar el complement per rumiar què es podria fer per fer-lo més útil.
Les dues coses més òbvies que falten són – tenir el total fixat a 10 i el fet que no és gaire còmode haver d’accedir a l’operador amb una Cerca d’operadors.
Aquestes dos afegits s’expliquen a continuació, amb el protocol final després.
Propietat de l’operador¶
Hi ha una diversitat de tipus de propietats que s’utilitzen per a la configuració d’eines. Els tipus de propietats habituals inclouen: int (enter), float (flotant), vector, color, Boolean (booleà) i string (cadena).
Aquestes propietats es gestionen de manera diferent al que són atributs típics de classe amb Python perquè el Blender necessita mostrar-les a la interfície, emmagatzemar la seva configuració en teclaris i mantenir paràmetres per a la seva reutilització.
Tot i que es gestiona d’una manera força pythònica, vigileu ja que al capdavall esteu definint paràmetres d’una eina que es carreguen al Blender i que s’hi accedeix des d’altres parts del Blender, fora de Python.
Per a desfer-nos del literal 10 com a total, farem ús d’una propietat d’operador. Les propietats d’operador es defineixen mitjançant el mòdul bpy.props, que s’afegeix al cos de classe:
# moved assignment from execute() to the body of the class...
total: bpy.props.IntProperty(name="Steps", default=2, min=1, max=100)
# and this is accessed on the class
# instance within the execute() function as...
self.total
Aquestes propietats de bpy.props són gestionades especialment per Blender quan la classe està registrada, de manera que es mostren com a botons a la interfície d’usuària. Hi ha molts arguments que podeu passar a propietats per a establir límits, canviar el valor per defecte i mostrar una pista de funcionament.
Vegeu també
Aquest document no entra en detalls sobre l’ús d’altres tipus de propietats. No obstant això, l’enllaç anterior inclou exemples d’usos de propietats més avançades.
Teclari¶
A Blender, els complements tenen els seus propis teclaris per no interferir amb els teclaris integrats amb Blender.
En l’exemple següent, s’afegeix un nou mode d’objecte bpy.types.KeyMap, després un bpy.types.KeyMapItem s’afegeix al teclari que referencia l’operador que hem just afegit, mitjançant Maj-Ctrl-T com a drecera de tecla per a activar-lo.
# store keymaps here to access after registration
addon_keymaps = []
def register():
# handle the keymap
wm = bpy.context.window_manager
km = wm.keyconfigs.addon.keymaps.new(name='Object Mode', space_type='EMPTY')
kmi = km.keymap_items.new(ObjectCursorArray.bl_idname, 'T', 'PRESS', ctrl=True, shift=True)
kmi.properties.total = 4
addon_keymaps.append((km, kmi))
def unregister():
# handle the keymap
for km, kmi in addon_keymaps:
km.keymap_items.remove(kmi)
addon_keymaps.clear()
Observeu com l’element teclari pot tenir un paràmetre total diferent de la predeterminat establert per l’operador. Això permet tenir múltiples tecles que accedeixen al mateix operador amb diferents paràmetres.
Nota
Per bé que Maj-Ctrl-T no és una drecera predeterminada del Blender, és difícil assegurar-se que els complements no se sobreescriuran els teclaris els uns als altres. Per tant, almenys cal vigilar quan assignem tecles que no entrin en conflicte amb cap funcionalitat important de Blender (vegeu també complement de tecles lliures).
Per a la documentació de l’API sobre les funcions llistades més amunt, vegeu:
Ajuntem les peces¶
bl_info = {
"name": "Cursor Array",
"blender": (2, 80, 0),
"category": "Object",
}
import bpy
class ObjectCursorArray(bpy.types.Operator):
"""Object Cursor Array"""
bl_idname = "object.cursor_array"
bl_label = "Cursor Array"
bl_options = {'REGISTER', 'UNDO'}
total: bpy.props.IntProperty(name="Steps", default=2, min=1, max=100)
def execute(self, context):
scene = context.scene
cursor = scene.cursor.location
obj = context.active_object
for i in range(self.total):
obj_new = obj.copy()
scene.collection.objects.link(obj_new)
factor = i / self.total
obj_new.location = (obj.location * factor) + (cursor * (1.0 - factor))
return {'FINISHED'}
def menu_func(self, context):
self.layout.operator(ObjectCursorArray.bl_idname)
# store keymaps here to access after registration
addon_keymaps = []
def register():
bpy.utils.register_class(ObjectCursorArray)
bpy.types.VIEW3D_MT_object.append(menu_func)
# handle the keymap
wm = bpy.context.window_manager
# Note that in background mode (no GUI available), keyconfigs are not available either,
# so we have to check this to avoid nasty errors in background case.
kc = wm.keyconfigs.addon
if kc:
km = wm.keyconfigs.addon.keymaps.new(name='Object Mode', space_type='EMPTY')
kmi = km.keymap_items.new(ObjectCursorArray.bl_idname, 'T', 'PRESS', ctrl=True, shift=True)
kmi.properties.total = 4
addon_keymaps.append((km, kmi))
def unregister():
# Note: when unregistering, it's usually good practice to do it in reverse order you registered.
# Can avoid strange issues like keymap still referring to operators already unregistered...
# handle the keymap
for km, kmi in addon_keymaps:
km.keymap_items.remove(kmi)
addon_keymaps.clear()
bpy.utils.unregister_class(ObjectCursorArray)
bpy.types.VIEW3D_MT_object.remove(menu_func)
if __name__ == "__main__":
register()
Dins el menú.¶
Executeu el protocol (o deseu-lo i afegiu-lo a través de les Preferències com abans) i apareixerà al menú Objecte.
Propietat d’operador.¶
Després de seleccionar-lo des del menú, podeu triar quantes instàncies del cub voleu crear.
Nota
Si s’executa el protocol directament múltiples vegades, també s’anirà afegint repetidament al menú. Tot i que no és un comportament útil, tampoc no hi fa res, ja que els complements no es registren diverses vegades quan s’habiliten amb les Preferències.
Conclusions¶
Els complements poden encapsular una certa funcionalitat de manera neta per poder escriure eines que millorin la vostra procedimentació o per escriure utensilis per a altres persones.
Encara que hi hagi límits al que Python pot fer dins de Blender, sens dubte hi ha molt que es pot aconseguir sense haver de submergir-se en el codi C/C++ de Blender.
L’exemple que ofereix el tutorial és limitat, però mostra com es pot fer servir l’API de Blender per a tasques habituals i que es pot ampliar escrivint-vos eines vosaltres mateixes.
Més informació¶
El Blender ve amb plantilles comentades que són accessibles des de la capçalera de l’Editor de text. Si teniu àrees específiques per a les quals voleu veure el codi d’exemple, aquest és un bon lloc per on començar.
Aquí hi ha alguns llocs web que us poden ser útils després de completar el tutorial.
Resum de l’API de Blender/Python – per més detalls de context sobre la integració de Blender/Python.
Com pensar com un científic informàtic – bona informació per a aquells que encara estan aprenent Python.
Desenvolupament de Blender – desenvolupament de Blender, informació general i enllaços d’interès.
Fòrum de desenvolupadores de Blender – fòrum on la gent consulta temes de desenvolupament de Python.