什麼是插件?
插件只是一個帶有一些附加要求的Python模塊,所以Blender能夠在包含有用信息的列表中顯示它。數組
舉個例子,這是最簡單的插件:app
bl_info = {"name": "My Test Add-on", "category": "Object"} def register(): print("Hello World") def unregister(): print("Goodbye World") bl_info
是一個包含附加元數據的字典,例如要在「用戶首選項」附加列表中顯示的標題,版本和做者。
register
是一個僅在啓用加載項時運行的函數,這意味着能夠在不激活加載項的狀況下加載模塊。
unregister
是一個卸載任何設置的函數register,當加載項被禁用時調用。
請注意,此附加組件不會執行與Blender相關的任何操做(bpy例如,未導入模塊)。編輯器
這是一個附加組件的設計示例,用於說明附加組件的基本要求很簡單。ide
附加組件一般會註冊操做符,面板,菜單項等,但值得注意的是,當從文本編輯器甚至交互式控制檯執行時,任何腳本均可以執行此操做 - 附加組件沒有任何本質上不一樣的內容容許它與Blender集成,這些功能只是由bpy模塊提供,可供任何腳本訪問。函數
所以,附加組件只是以用戶能夠輕鬆利用的方式封裝Python模塊的一種方式。工具
注意佈局
在文本編輯器中運行此腳本將不會打印任何內容,以查看必須經過「用戶首選項」安裝的輸出。啓用和禁用時將打印消息。測試
上面最簡單的附加組件做爲示例頗有用,但不是不少。下一個附加組件很簡單,但展現瞭如何使用一個腳本將腳本集成到Blender中,Operator 這是定義從菜單,按鈕和鍵盤快捷鍵訪問的工具的典型方法。this
對於第一個示例,咱們將建立一個簡單地移動場景中全部對象的腳本。spa
將如下腳本添加到Blender中的文本編輯器:
import bpy
scene = bpy.context.scene
for obj in scene.objects:
obj.location.x += 1.0
單擊「 運行腳本」按鈕,活動場景中的全部對象都將由1.0 Blender單元移動。
此附加組件使用上面腳本的主體,並將其添加到操做員的execute()功能中。
bl_info = { "name": "Move X Axis", "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 register(): bpy.utils.register_class(ObjectMoveX) 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()
注意
bl_info 分爲多行,這只是一種用於更輕鬆添加項目的樣式約定。
注意
bpy.context.scene咱們使用context.scene傳遞給的參數而不是使用execute()。在大多數狀況下,這些都是相同的。可是在某些狀況下,運算符將被傳遞給自定義上下文,所以腳本做者應該更喜歡context傳遞給運算符的參數。
要測試腳本,您能夠將其複製並粘貼到Blender的文本編輯器中並運行它。這將直接執行腳本並當即調用寄存器。
可是,運行腳本不會移動任何對象。爲此,您須要執行新註冊的運算符。
../../_images/advanced_scripting_addon-tutorial_operator-search-menu.png
操做員搜索菜單。
經過按下Spacebar以調出操做員搜索菜單並輸入「Move X by One」(the bl_label),而後執行此操做Return。
對象應該像之前同樣移動。
在Blender中打開此附加組件以進行下一步 - 安裝。
在Blender的文本編輯器中添加了加載項以後,您將但願可以安裝它,以即可以在用戶首選項中啓用它以在啓動時加載。
即便上面的附加組件是一個測試,可是咱們仍然要完成這些步驟,以便您知道如何在之後執行此操做。
要將Blender文本做爲加載項安裝,首先必須將其保存到磁盤。請注意遵照適用於Python模塊的命名限制,並以.py擴展名結束。
一旦文件在磁盤上,您就能夠像在線下載的加載項同樣安裝它。
打開用戶文件‣用戶首選項,選擇加載項選項卡,按安裝加載項...並選擇文件。
如今將列出加載項,您能夠經過按複選框啓用加載項,若是要在從新啓動時啓用加載項,請按「 另存爲默認值」。
注意
附加組件的目標取決於您的Blender配置。安裝附加組件時,將在控制檯中打印源和目標路徑。您還能夠經過在Python控制檯中運行此命令來查找加載項路徑位置。
import addon_utils
print(addon_utils.paths())
這裏有關於此主題的更多內容: 目錄佈局。
對於咱們的第二個附加組件,咱們將專一於對象實例化 - 這是 - 以與您可能在數組修飾符中看到的方式相似的方式建立對象的連接副本。
和之前同樣,首先咱們將從腳本開始,開發它,而後將其轉換爲附加組件。
import bpy from bpy import context # Get the current scene scene = context.scene # Get the 3D cursor cursor = scene.cursor_location # Get the active object (assume we have one) obj = scene.objects.active # Now make a copy of the object obj_new = obj.copy() # The object won't automatically get into a new scene scene.objects.link(obj_new) # Now we can place the object obj_new.location = cursor
如今嘗試將此腳本複製到Blender並在默認多維數據集上運行它。確保在運行以前單擊以移動3D光標,由於副本將出如今光標的位置。
運行後,請注意當您進入編輯模式以更改多維數據集時 - 全部副本都會更改。在Blender中,這稱爲Linked Duplicates。
接下來,咱們將在循環中執行此操做,以在活動對象和遊標之間建立對象數組。
import bpy from bpy import context scene = context.scene cursor = scene.cursor_location obj = scene.objects.active # 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.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))
嘗試使用活動對象運行此腳本,並將光標間隔開以查看結果。
使用這個腳本,您會注意到咱們正在使用對象位置和光標進行一些數學計算,這是有效的,由於它們都是3D 實例,模塊提供了一個方便的類,它容許向量乘以數字和矩陣。mathutils. Vectormathutils
若是您對這個領域感興趣,請閱讀mathutils.Vector - 有許多方便的實用功能,例如獲取矢量,交叉積,點積之間的角度以及mathutils.geometry Bézier樣條插值和光線三角交叉等更高級的函數。
目前咱們將專一於使這個腳本成爲一個附加組件,但很高興知道這個3D數學模塊可用,並能夠在之後幫助您使用更高級的功能。
第一步是將腳本按原樣轉換爲附加組件:
bl_info = { "name": "Cursor Array", "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 = scene.objects.active total = 10 for i in range(total): obj_new = obj.copy() scene.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()
這裏的全部內容都已在前面的步驟中介紹過,您可能還想嘗試運行附加組件,並考慮能夠採起哪些措施使其更有用。
兩個最明顯的缺失是 - 總固定爲10,而且不得不從太空杆訪問操做員不是很方便。
接下來將解釋這些添加內容,而後是最終腳本。
有許多屬性類型用於工具設置,常見的屬性類型包括:int,float,vector,color,boolean和string。
這些屬性的處理方式與典型的Python類屬性不一樣,由於Blender須要在界面中顯示它們,將它們的設置存儲在鍵映射中並保留設置以便重用。
雖然這是以至關Pythonic的方式處理的,但請注意,您實際上定義的是加載到Blender中的工具設置,而且在Python以外由Blender的其餘部分訪問。
爲了擺脫文字10 total,咱們將使用運算符屬性。運算符屬性是經過bpy.props模塊定義的,它被添加到類主體中:
# 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
這些屬性bpy.props由Blender在註冊類時專門處理,所以它們在用戶界面中顯示爲按鈕。您能夠將許多參數傳遞給屬性以設置限制,更改默認值並顯示工具提示。
也能夠看看
bpy.props.IntProperty
本文檔不會詳細介紹如何使用其餘屬性類型。可是,上面的連接包含更高級的屬性使用示例。
附加組件能夠添加到Python中定義的現有面板,標題和菜單的用戶界面。
對於此示例,咱們將添加到現有菜單。
../../_images/advanced_scripting_addon-tutorial_menu-id.png
菜單標識符。
要查找菜單的標識符,能夠將鼠標懸停在菜單項上,並顯示標識符。
用於添加菜單項的方法是將繪圖函數附加到現有類中:
def menu_func(self, context):
self.layout.operator(ObjectCursorArray.bl_idname)
def register():
bpy.types.VIEW3D_MT_object.append(menu_func)
有關擴展菜單的文檔,請參閱:菜單(bpy_struct)。
在Blender中,附加組件有本身的鍵盤映射,以避免干擾Blender的內置鍵映射。
在下面的示例中,bpy.types.KeyMap添加了一個新的對象模式,而後將a bpy.types.KeyMapItem添加到引用咱們新添加的運算符的鍵映射中,使用它Shift-Ctrl-Spacebar做爲激活它的鍵快捷鍵。
# 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, 'SPACE', '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()
請注意,鍵盤映射項的total設置不一樣於操做員設置的默認設置,這容許您使用不一樣設置訪問同一運算符的多個鍵。
注意
雖然Shift-Ctrl-Spacebar不是默認的Blender鍵快捷鍵,但很難確保加載項不會覆蓋彼此的鍵盤圖,至少在分配鍵時不要與Blender中的重要功能衝突。
有關上面列出的函數的API文檔,請參閱:
把它們一塊兒
bl_info = { "name": "Cursor Array", "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 = scene.objects.active for i in range(self.total): obj_new = obj.copy() scene.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, 'SPACE', '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
在菜單中。
運行腳本(或保存它並經過以前的用戶首選項添加它),它將出如今菜單中。
../../_images/advanced_scripting_addon-tutorial_op-prop.png
運營商財產。
從菜單中選擇它後,您能夠選擇要建立的多維數據集的實例數。
注意
屢次直接執行腳本也會每次添加菜單。雖然沒有用處,但沒有什麼可擔憂的,由於當經過用戶首選項啓用時,加載項不會屢次註冊。
附加組件能夠巧妙地封裝某些功能,以便編寫工具來改進工做流程或編寫實用程序以供其餘人使用。
雖然Python在Blender中能夠作的事情有限,可是在沒必要深刻研究Blender的C / C ++代碼的狀況下確定能夠實現不少。
本教程中給出的示例是有限的,但顯示了用於常見任務的Blender API,您能夠將其擴展爲編寫本身的工具。
進一步閱讀Blender帶有註釋模板,能夠從文本編輯器的標題中訪問。若是您想要查看示例代碼的特定區域,這是一個很好的起點