在 Blender 開發 Addon 時載入自己的 Module
前言
由於需要從 Blender 匯出自製遊戲引擎的格式,所以就需要開發 Addon ,但由於要支援的規格越來越多,所以程式碼就越來越多,全部都塞在一個檔案寫起來並不是很舒服,之前不拆成其它 Module 來載入是因為找不到方法來載入,官方並沒有提供載入 Module 的範例,但最近在 Valve 的 Source 引擎提供給 Blender 的 Addon 裡發現它可以載入自己的 Module ,所以就來研究是如何做的,在此做個紀錄。
內容
Valve 的 Source 引擎提供給 Blender 的 Addon 可以在 [ steamreview.org ] Blender Source Tools 下載。在研究中發現以前從沒想過把 Addon 裝起來跟直接在 Blender 的文字介面有何不同,所以總是在文字介面裡做實驗,所以 Import 自己的 Module 總是會失敗,但我看了 Valve 提供的 Addon ,裡面遽然可以直接 Import 自己的 Module ,本以為事情解決了,但發現一些小毛病!如果在安裝的環境下開發,當程式被修改時, Blender 並不會去 Reload 它,這裡我找到兩種方法來 Reload ,一種是直接用 Blender 的操作介面來 Reload ,如下圖
|
Reload Addon 在 Blender 的介面 |
這個方法很簡潔,但不知為什麼每次 Reload 時會小小的頓一下,所以我個人比較建議第二種方法。第二種方法是利用 Addon 的啟動按鍵來 Reload ,如下圖
|
利用 Addon 的起用來 Reload |
這個方法有個麻煩, 只是單純的利用關閉後再啟用會發現其實它不會被 Relaod ,但如果主程式(__init__.py)的修改日期有變動時,它就會 Reload,這種 Reload 操作會負責一點,但可以確定只 Reload 這個 Addon。解決了不會 Reload 後又發現當自己的 Module 被修改時,也不會 Reload! Reload 似乎只針對主程式(__init__.py),所以需要在主程式增加 Reload 自己的 Module ,這段程式碼我在 Valve 的 Addon 裡找到了如下
# Python doesn't reload package sub-modules at the same time as __init__.py!
import importlib, sys
for filename in [ f for f in os.listdir(os.path.dirname(os.path.realpath(__file__))) if f.endswith(".py") ]:
if filename == os.path.basename(__file__): continue
module = sys.modules.get("{}.{}".format(__name__,filename[:-3]))
if module: importlib.reload(module)
# clear out any scene update funcs hanging around, e.g. after a script reload
from bpy.app.handlers import depsgraph_update_pre, depsgraph_update_post
for func in depsgraph_update_post:
if func.__module__.startswith(__name__):
depsgraph_update_post.remove(func)
要在主程式裡加這段才可以 Reload 自己的 Module 。完整的範例程式碼如下
__init__.py
bl_info = {
"name": "My export addon",
"author": "Hosee",
"version": (1, 0, 0),
"blender": (2, 80, 0),
"category": "Import-Export",
"location": "",
"wiki_url": "",
"tracker_url": "",
"description": "My custom export addon."
}
#
import bpy, os
from bpy_extras.io_utils import ExportHelper
from bpy.props import StringProperty, BoolProperty, EnumProperty
from bpy.types import Operator
#follow code from Valve
# Python doesn't reload package sub-modules at the same time as __init__.py!
import importlib, sys
for filename in [ f for f in os.listdir(os.path.dirname(os.path.realpath(__file__))) if f.endswith(".py") ]:
if filename == os.path.basename(__file__): continue
module = sys.modules.get("{}.{}".format(__name__,filename[:-3]))
if module: importlib.reload(module)
# clear out any scene update funcs hanging around, e.g. after a script reload
from bpy.app.handlers import depsgraph_update_pre, depsgraph_update_post
for func in depsgraph_update_post:
if func.__module__.startswith(__name__):
depsgraph_update_post.remove(func)
#
#import my module
from . import utility
#
class ExportSomeData(Operator, ExportHelper):
bl_idname = "export_test.something"
bl_label = "Export something"
filename_ext = ".txt"
filter_glob: StringProperty(
default="*.txt",
options={'HIDDEN'},
maxlen=255, # Max internal buffer length, longer would be clamped.
)
use_setting: BoolProperty(
name="Example Boolean",
description="Example Tooltip",
default=True,
)
type: EnumProperty(
name="Example Enum",
description="Choose between two items",
items=(
('OPT_A', "First Option", "Description one"),
('OPT_B', "Second Option", "Description two"),
),
default='OPT_A',
)
def execute(self, context):
utility.do_something()
return {"FINISHED"}
# Only needed if you want to add into a dynamic menu
def menu_func_export(self, context):
self.layout.operator(ExportSomeData.bl_idname, text="Text Export Operator")
def register():
bpy.utils.register_class(ExportSomeData)
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
def unregister():
bpy.utils.unregister_class(ExportSomeData)
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
if __name__ == "__main__":
register()
utility.py
def do_something():
print('Do something')
完整的程式碼可以在 [ Gitlab ] basic_export_addon 下載。
雖然照著上述的做法就可以載入自己的 Module ,但還是有些麻煩,如修改後要測試要經過 Reload 才能看到結果,或是修改後如果要搭配版本管理(Version control)時,要把修改的那一份(Blender 安裝的資料夾)複製到版本管理(Version control)才能 Commit ,這些麻煩目前還找不到方法解決,如果解決了會再寫一篇。
參考資料
[ steamreview.org ] Blender Source Tools
相關資料
[ Gitlab ] basic_export_addon