Tutoriál pre doplnky#

Zamýšľaní poslucháči#

Tento tutoriál je určený na pomoc technickým umelcom alebo vývojárom, aby sa naučili rozširovať Blender. Od tých, ktorí budú pracovať s týmto tutoriálom, sa očakáva znalosť základov jazyka Python.

Podmienka#

Predtým, ako si prejdete tutoriál, mali by ste…

  • Poznať základy práce v Blenderi.

  • Vedieť, ako spustiť skript v textovom editore Blenderu.

  • Rozumieť primitívnym typom jazyka Python (celé číslo, logická hodnota, reťazec, zoznam, tuple, slovník a sústava).

  • Byť oboznámený s konceptom modulov jazyka Python.

  • Mať základné znalosti tried (objektovej orientácie) v jazyku Python.

Odporúčané čítanie pred začatím tohto tutoriálu.

Ak chcete čo najlepšie vyriešiť chybové hlásenie, ktoré Python vypíše pri písaní skriptov, spustite Blender z terminálu. Pozrite si časť Použitie terminálu.

Tip

V predvoľbách môžete povoliť Extra pre vývojárov a povoliť tak funkcie, ktoré uľahčujú vývoj doplnkov.

Čo je doplnok?#

Doplnok je jednoducho modul Pythonu s niektorými dodatočnými požiadavkami, aby ho Blender mohol zobraziť v zozname s užitočnými informáciami.

Ako príklad uvádzame najjednoduchší možný doplnok:

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

je slovník obsahujúci meta údaje doplnku, ako napríklad názov, verziu a autora, ktoré sa majú zobrazovať v zozname doplnkov Predvoľby. Určuje tiež minimálnu verziu Blenderu potrebnú na spustenie skriptu; staršie verzie nezobrazia doplnok v zozname.

register

je funkcia, ktorá sa spustí len pri zapnutí doplnku, to znamená, že modul možno načítať bez aktivácie doplnku.

unregister

je funkcia na zrušenie všetkého, čo bolo nastavené funkciou register, ktorá sa zavolá, keď je doplnok vypnutý.

Všimnite si, že tento doplnok nerobí nič, čo by súviselo s Blenderom (napríklad modul blender_api:bpy nie je importovaný).

Toto je vymyslený príklad doplnku, ktorý slúži na ilustráciu toho, že základné požiadavky doplnku sú jednoduché.

Doplnok zvyčajne registruje operátory, panely, položky ponuky atď., ale stojí za zmienku, že toto môže robiť každý skript spustený z textového editora alebo dokonca z interaktívnej konzoly – doplnok sa vo svojej podstate ničím nelíši, čo by mu umožňovalo integrovať sa s Blenderom, takúto funkcionalitu len poskytuje modul blender_api:bpy, ku ktorému má prístup každý skript.

Doplnok je teda len spôsob, ako zapuzdriť modul Pythonu spôsobom, ktorý môže užívateľ ľahko použiť.

Poznámka

Spustením tohto skriptu v textovom editore sa nič nevytlačí, ak chcete vidieť výstup, je potrebné ho nainštalovať prostredníctvom predvolieb. Správy sa vypíšu pri zapnutí a vypnutí.

Váš prvý doplnok#

Uvedený najjednoduchší možný doplnok je užitočný ako príklad, ale nič viac. Tento ďalší doplnok je jednoduchý, ale ukazuje, ako integrovať skript do Blenderu použitím Operátora, čo je typický spôsob definovania nástroja prístupného z ponuky, tlačidiel a klávesových skratiek.

V prvom príklade vytvoríme skript, ktorý jednoducho presunie všetky objekty v scéne.

Napísanie skriptu#

Do textového editora v Blenderi pridajte nasledujúci skript:

import bpy

scene = bpy.context.scene
for obj in scene.objects:
    obj.location.x += 1.0

Kliknutím na tlačidlo Spustiť skript sa všetky objekty v aktívnej scéne posunú o 1,0 jednotky.

Napísanie doplnku (jednoduchého)#

Tento doplnok prevezme telo vyššie uvedeného skriptu a pridá ho do operátora funkcie 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()

Poznámka

bl_info je rozdelené na viac riadkov, je to len štýlová konvencia používaná na jednoduchšie pridávanie položiek.

Poznámka

Namiesto použitia bpy.context.scene použijeme argument context.scene odovzdaný príkazu execute(). Vo väčšine prípadov budú rovnaké. V niektorých prípadoch sa však operátorom odovzdá vlastný kontext, takže autori skriptov by mali uprednostniť argument context odovzdávaný operátorom.

Ak chcete otestovať skript, môžete ho skopírovať a vložiť do textového editora Blenderu a spustiť ho. Tým sa skript spustí priamo a okamžite sa zavolá register.

Spustením skriptu sa však nepresunú žiadne objekty. Na to je potrebné spustiť novo zaregistrovaný operátor.

../../_images/advanced_scripting_addon-tutorial_operator-search-menu.png

Ponuka Vyhľadávanie operátora.#

Otvorte ponuku Operátor vyhľadávania a zadajte „Presunúť X jedným“ (označenie bl_label), potom Enter.

Objekty by sa mali pohybovať ako predtým.

Tento doplnok nechajte otvorený v Blenderi pre ďalší krok - Inštalácia.

Inštalácia doplnku#

Keď už máte svoj doplnok v textovom editore Blenderu, budete ho chcieť nainštalovať s povolením v Predvoľbách Načítať pri spustení.

Aj keď je vyššie uvedený doplnok testom, aj tak si prejdeme jednotlivé kroky, aby ste vedeli, ako to urobiť neskôr.

Ak chcete nainštalovať text Blenderu ako doplnok, musíte ho najprv uložiť na disk. Dbajte na to, aby ste dodržali obmedzenia týkajúce sa názvov, ktoré platia pre moduly Python a aby boli ukončené príponou .py.

Keď je súbor na disku, môžete ho nainštalovať rovnako ako doplnok stiahnutý online.

Otvorte Predvoľby ‣ Doplnky ‣ Inštalovať… a vyberte súbor.

Teraz sa doplnok zobrazí v zozname a môžete ho povoliť stlačením zaškrtávacieho políčka, ak chcete, aby bol povolený pri reštarte, stlačte tlačidlo Uložiť ako predvolené. Operátor je možné spustiť rovnakým spôsobom, ako je popísané v predošlej časti.

Keď je doplnok povolený, Blender vykoná kód a spustí funkciu register()`. Keď je doplnok vypnutý, Blender spustí funkciu unregistrer() (zrušiť registráciu).

Poznámka

Cieľ doplnku závisí od konfigurácie Blenderu. Pri inštalácii doplnku sa v konzole vypíšu zdrojové a cieľové cesty. Umiestnenie cesty k doplnku môžete zistiť aj spustením tohto príkazu v konzole Python:

import addon_utils
print(addon_utils.paths())

Viac sa o tejto téme píše tu: Rozvrhnutie priečinkov.

Váš druhý doplnok#

V našom druhom doplnku sa zameriame na vytvorenie inštancie objektov - to je vytváranie prepojených kópií objektu podobným spôsobom, aký ste mohli vidieť pri modifikátore Pole.

Napísanie skriptu#

Tak ako predtým, najprv začneme so skriptom, rozvinieme ho a potom ho konvertujeme na doplnok

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

Teraz skúste skopírovať tento skript do Blenderu a spustiť ho na pôvodnej kocke. Pred spustením sa uistite, že ste kliknutím presunuli 3D kurzor, pretože duplikát sa objaví na mieste kurzora.

Po spustení si všimnite, že keď prejdete do režimu editácie a zmeníte kocku, všetky kópie sa zmenia. V Blenderi sa to nazýva Spojené duplikáty.

Ďalej to urobíme v slučke, aby sme vytvorili pole objektov medzi aktívnym objektom a kurzorom.

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))

Skúste spustiť tento skript s aktívnym objektom a kurzorom vzdialeným od seba, aby ste videli výsledok.

V tomto skripte si všimnete, že robíme nejaké matematické výpočty s polohou objektu a kurzora, čo funguje, pretože obidve sú inštancie 3D mathutils.Vector, čo je pohodlná trieda poskytovaná modulom mathutils, ktorý umožňuje násobiť vektory číslami a matricami.

Ak vás táto oblasť zaujíma, prečítajte si mathutils.Vector – je tam veľa užitočných funkcií, ako napríklad získanie uhla medzi vektormi, krížový súčin, bodový súčin, ako aj pokročilejšie funkcie v mathutils.geometry, ako napríklad interpolácia Bézierovej drážky a priesečník lúčov a trojuholníkov.

Zatiaľ sa zameriame na vytvorenie tohto skriptu ako doplnku, ale je dobré vedieť, že tento 3D matematický modul je k dispozícii a neskôr vám môže pomôcť s pokročilejšími funkciami.

Napísanie doplnku#

Prvým krokom je konvertovať skript ako taký na doplnok:

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()

Všetko tu bolo uvedené v predošlých krokoch, možno budete chcieť vyskúšať spustiť doplnok a zvážiť, čo by sa dalo urobiť, aby bol užitočnejší.

Dve najzjavnejšie chýbajúce veci sú – celkový počet je pevne stanovený na 10 a prístup k operátorovi pomocou vyhľadávania nie je veľmi pohodlné.

Obe tieto doplnenia sú vysvetlené v ďalšom texte, po ktorom nasleduje záverečný skript.

Vlastnosť operátora#

Na nastavenie nástroja sa používajú rôzne typy vlastností, medzi ktoré patria: celé číslo, hodnota na pohyblivej čiarke, vektor, farba, logická hodnota a reťazec.

S týmito vlastnosťami sa zaobchádza inak ako s typickými atribútmi tried jazyka Python, pretože Blender ich musí zobrazovať v rozhraní, ukladať ich nastavenia v priradení kláves a uchovávať nastavenia pre opakované použitie.

Hoci sa to rieši prevažne cestou Pythonu, nezabúdajte, že v skutočnosti definujete nastavenia nástroja, ktoré sa načítavajú do Blenderu a pristupujú k nim iné časti Blenderu mimo jazyka Python.

Aby sme sa zbavili doslovného čísla 10 pre total, použijeme vlastnosť operátora. Vlastnosti operátora sa definujú prostredníctvom modulu bpy.props, ktorý sa pridáva do tela triedy:

# 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

Tieto vlastnosti z bpy.props sú špeciálne spracované Blenderom pri registrácii triedy, takže sa zobrazujú ako tlačidlá v užívateľskom rozhraní. Vlastnostiam môžete odovzdať mnoho argumentov na nastavenie limitov, zmenu predvoleného nastavenia a zobrazenie popisu.

Tento dokument sa podrobne nezaoberá používaním iných typov vlastností. Uvedený odkaz však obsahuje príklady pokročilejšieho používania vlastností.

Priradenie kláves#

V Blenderi majú doplnky vlastné priradenie kláves, aby nezasahovali do integrovaných priradení kláves Blenderu.

V nasledujúcom príklade sa pridá nový objektový mód bpy.types.KeyMap, potom sa do priradenia kláves pridá trieda bpy.types.KeyMapItem, ktorá odkazuje na náš novo pridaný operátor, pričom sa použije Shift+Ctrl+T ako klávesová skratka na jeho aktiváciu.

# 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()

Všimnite si, že položka priradenia kláves môže mať nastavenie total odlišné od predvoleného nastavenia operátora, čo vám umožňuje mať viacero kláves pristupujúcich k rovnakému operátoru s rôznymi nastaveniami.

Poznámka

Hoci Shift+Ctrl+T nie je predvolenou klávesovou skratkou Blenderu, je ťažké zabezpečiť, aby si doplnky navzájom neprepisovali priradenia kláves. Preto aspoň pri priradzovaní kláves dbajte na to, aby neboli v rozpore s dôležitými funkciami Blenderu (pozri tiež Is Key Free).

Dokumentáciu API k vyššie uvedeným funkciám nájdete na adrese:

Spojenie všetkého dohromady#

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()
../../_images/advanced_scripting_addon-tutorial_in-menu.png

V ponuke.#

Spustite skript (alebo ho uložte a pridajte cez Predvoľby ako predtým) a objaví sa v ponuke Objekt.

../../_images/advanced_scripting_addon-tutorial_op-prop.png

Vlastnosť operátora.#

Po výbere z ponuky môžete vybrať, koľko inštancií kocky chcete vytvoriť.

Poznámka

Priame spustenie skriptu viackrát pridá ponuku zakaždým. Aj keď to nie je užitočné správanie, nie je sa čoho obávať, pretože doplnky sa pri zapnutí cez predvoľby viackrát nezaregistrujú.

Závery#

Doplnky môžu elegantne zapuzdriť určitú funkcionalitu na písanie nástrojov na zlepšenie vášho pracovného postupu alebo na písanie nástrojov, ktoré môžu používať iní.

Aj keď existujú obmedzenia, ktoré Python v rámci Blenderu dokáže, určite sa dá veľa dosiahnuť bez toho, aby ste sa museli ponoriť do kódu C/C++ Blenderu.

Príklad uvedený v učebnici je obmedzený, ale ukazuje API Blenderu používané na bežné úlohy, ktoré môžete rozšíriť a napísať si vlastné nástroje.

Ďalšie čítanie#

Blender sa dodáva s komentovanými šablónami, ktoré sú prístupné v záhlaví textového editora. Ak máte konkrétne oblasti, pre ktoré chcete vidieť príklad kódu, je to dobré miesto, kde môžete začať.

Tu je niekoľko lokalít, ktoré by ste si po dokončení tohto návodu mohli pozrieť.