Blender 之 入門


KAlO2

隨筆 - 24  文章 - 2  評論 - 23  閱讀 - 73554

Blender 之 Splash 代碼分析


  
  注:以下內容基於 Blender 2.7x 版本工程,其它低版本可能有改動。

  Blender啟動完成時,會出現一個畫面,英文叫Splash。默認是打開的,可以在設置里關閉。在文件菜單里點擊用戶首選項(快捷鍵Ctrl + Alt + U),在彈出的窗口第一個Tab頁面,也就是界面(Interface)的右下角,有一個選項 Show Splash,默認打了勾,關閉然后最下一行的 Save User Settings。這樣,下次啟動的時候就不會出現Splash

  假設你已經下載好了blender工程代碼,下面通過Splash講解C語言Operator的實現,前一篇是關於PythonOperator

 

datatoc

  Splash資源所在的文件夾是 blender/release/datafiles/ ,一起的還有各種圖標、字體、SVG矢量圖、畫筆以及matcap效果圖。
  source/blender/editors/datafiles/CMakeLists.txt 會調用 data_to_c_simple 函數從圖片格式轉換成C代碼(其實就是長度加二進制數據),blender 需要在源代碼路徑外編譯(out of source build) ,對應生成在 blender-build/release/datafiles/
data_to_c_simple(../../../../release/datafiles/splash.png SRC)
  data_to_c_simple 函數(cmake的宏)定義在 build_files/cmake/macros.cmake
  data_to_c 需要提供file_fromfile_to參數,data_to_c_simple 則僅提供 file_from 參數,file_to 的值為 ${file_from}.c
  調用的命令是 datatoc 其工程在 source/blender/datatoc/

  該 CMakeLists.txt 的最后一句指明生成 bf_editor_datafiles.lib
blender_add_lib(bf_editor_datafiles "${SRC}" "${INC}" "${INC_SYS}")

bf_editor_datafiles.vcxproj -> blender-build/lib/Debug/bf_editor_datafiles.lib


  blender/source/blenderplayer/CMakeLists.txt
  bf_editor_datafiles 被包含在 BLENDER_SORTED_LIBS 里,blender.exe blenderplayer.exe 會依賴這些工程庫。
target_link_libraries(blenderplayer ${BLENDER_SORTED_LIBS})
target_link_libraries(blender ${BLENDER_SORTED_LIBS})

  這些圖片資源最終轉換成C數組數據鏈接到.exe文件里。
好處是:如果缺少相關資源(寫錯名字、用了中文字符、或者圖片格式誤寫),編譯期就會報錯;如果僅僅是替換掉一張圖片的話,錯誤只能在運行時被發現,導致出錯。
壞處是:不僅僅是換掉圖片資源就好了的,還需要重新編譯。這讓一些想把splash換成自己作品的藝術家望而卻步。
后話:Google Summer Of Code 2016 列出了可配置的Splash想法(Configuration Splash Screen)。

 

main函數

  Blender.sln 解決方案包含多個工程,cmake工具會額外生成 ALL_BUILD / INSTALL / PACKAGE / RUN_TESTS / ZERO_CHECK 等幾個工程。其中,ALL_BUILDINSTALL相當於makefile里面的makeinstall命令。
  編譯完成,在運行的時候,需要將啟動工程從 ALL_BUILD 修改成 blender,否則會提示 Unable to start program 'build\x64\Debug\ALL_BUILD' 拒絕訪問。(在blender工程上鼠標右鍵后,選擇 Set as StartUp Project 即可)

  一切的一切,要從main函數開始……
  main函數在 blender 工程里的 source/creator/creator.c ,初始化子系統(圖像、修改器、畫筆、Python、節點、材質等)、處理命令行參數、進入消息循環WM_main()或者退出循環在后台運行(-b參數可以指定在后台渲染)。
BLI_argsAdd(ba, 1, "-b", "--background", "\n\tRun in background (often used for UI-less rendering)", background_mode, NULL);

  所有有UI的應用程序會有消息循環機制。Blender 的是在 WM_main(C);
  WM_main 的實現在 source/blender/windowmanager/intern/wm.c ,很簡單的幾行代碼。

 

void WM_main(bContext *C)

{

    while (1) {

        

        /* get events from ghost, handle window events, add to window queues */

        wm_window_process_events(C);

        

        /* per window, all events to the window, screen, area and region handlers */

        wm_event_do_handlers(C);

        

        /* events have left notes about changes, we handle and cache it */

        wm_event_do_notifiers(C);

        

        /* execute cached changes draw */

        wm_draw_update(C);

    }

}

 

WM_main(C); 一行的上面是關於splash的,

if(!G.file_loaded)

    WM_init_splash(C);

  Blender 有兩個重要的數據結構 Global G; UserDef U; ,見名知意。
  Global 的字段 file_loaded bool 類型的,但是字符串全局搜索到的是賦值為整形1,其實就是true
source/blender/windowmanager/intern/wm_operators.c: G.file_loaded = 1; /* prevents splash to show */
  file_loaded true 則阻止加載splash,否則啟動時加載splash

 

Splash

  關於 splash 的代碼,就在 WM_init_splash(C); 這一行了。
  WMWindowManager的縮寫,C語言缺少 C++ namespace 概念,這樣附帶模塊命名以防沖突。
  來看看代碼中有關splash的地方,Blender一個很常見的概念是Operator
source/blender/windowmanager/intern/wm_init_exit.c

 

void WM_init_splash(bContext *C)

{

    if ((U.uiflag & USER_SPLASH_DISABLE) == 0) {

        wmWindowManager *wm = CTX_wm_manager(C);

        wmWindow *prevwin = CTX_wm_window(C);

    

        if (wm->windows.first) {

            CTX_wm_window_set(C, wm->windows.first);

            WM_operator_name_call(C, "WM_OT_splash", WM_OP_INVOKE_DEFAULT, NULL);

            CTX_wm_window_set(C, prevwin);

        }

    }

}

 

  U.uiflag的比特位差不多用光了,又開了uiflag2。其中,USER_SPLASH_DISABLE 對應上面用戶偏好里的 Show Splash
  bContext 是很重要的數據結構,通過指針傳遞,函數定義在 source/blender/blenkernel/intern/context.c,很多地方都引用了它,應該定義在 .h 文件里的。

  給變量取好名字,更方便讀代碼。WM_operator_name_call 見名知意,根據Operator的名字來調用函數,比如上面就是想調用 "WM_OT_splash" 函數。

 

int WM_operator_name_call(bContext *C, const char *opstring, short context, PointerRNA *properties)

{

    wmOperatorType *ot = WM_operatortype_find(opstring, 0);

    if (ot) {

        return WM_operator_name_call_ptr(C, ot, context, properties);

    }

 

    return 0;

}

 

  在 blender/source/blender/windowmanager/intern/wm_operators.c 你可以看到關於 Operator 的各種操作,通過函數 WM_operatortype_append 可以添加新的 Operator,由於有很多 OperatorBlender 用自己的哈希表 GHash *global_ops_hash 管理,WM_OT_splash 是在 WM_init() 初始化時添加的。

 

/* called on initialize WM_init() */void wm_operatortype_init(void)

{

    /* reserve size is set based on blender default setup */

    global_ops_hash = BLI_ghash_str_new_ex("wm_operatortype_init gh", 2048);

    

    ...

    WM_operatortype_append(WM_OT_splash);

    ...

}

 

調用的棧是這樣的
int main(int argc, const char **argv)
  WM_init(C, argc, (const char **)argv);
    wm_operatortype_init();
      WM_operatortype_append(WM_OT_splash);

  WM_OT_splashWMOperator的種類,_OT_ Operator Type,構成Operator ID名稱的一部分,該函數填充 wmOperatorType 里的字段。

 

static void WM_OT_splash(wmOperatorType *ot)

{

    ot->name = "Splash Screen";

    ot->idname = "WM_OT_splash";

    ot->description = "Open the splash screen with release info";

    

    ot->invoke = wm_splash_invoke;

    ot->poll = WM_operator_winactive;

}

 

 

  前一篇講到過 nameidnamedescriptionstruct wmOperatorType 也給了注釋。name 會在UI上顯示出來的。idname 名字應該和函數名字一致,這里可以用 __func__ 宏的。description 是提示信息,鼠標放在上面會顯示出來。
  poll回調函數用來測試該Operator是否可以在當前環境(context)執行。我發現有些人在讀代碼的時候,對變量或函數的取名不在意。poll是輪詢的意思,通過名稱就能猜到要完成的功能。有關函數WM_operator_poll
  invoke 就是函數調用了。

  因為是static函數,所以只需要在本文件內搜索調用處,其他文件是不能調用的。這也算是一種搜索技巧。

static int wm_splash_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))

{

    UI_popup_block_invoke(C, wm_block_create_splash, NULL);

    

    return OPERATOR_FINISHED;

}

  C返回 OPERATOR_FINISHED 的狀態,對應 Python 返回 {"FINISHED"}
  接着就是 wm_block_create_splash 函數了,畫出Splash的地方,Splash上面的跳轉鏈接也寫在這個函數里。
// blender/source/blender/windowmanager/intern/wm_operators.c

 splash.png

  WITH_HEADLESS 名字看不懂,CMakeLists.txt 里解釋說是不帶圖形界面的編譯(渲染農場,服務端模式),默認是關閉的。
  這里引用到了 splash.png 的圖,工程datatoc用來將splash.png圖片資源轉換成長度datatoc_splash_png_size 和二進制的dump datatoc_splash_png,上面講過。

  有關函數wm_operator_invoke,在 source/blender/windowmanager/intern/wm_event_system.c,調用棧是這樣的:
int main(int argc, const char **argv)
  WM_main(C);
    WM_init_splash(C);
      WM_operator_name_call(C, "WM_OT_splash", WM_OP_INVOKE_DEFAULT, NULL);
        WM_operator_name_call_ptr(C, ot, context, properties);
          wm_operator_call_internal(C, ot, properties, NULL, context, false);
            wm_operator_invoke(C, ot, event, properties, reports, poll_only);

 wm_operator_invoke

 

  invokeexec是函數指針,要二選一填充,否則就是非法的Operator調用。上面的Splash Operator用的是invoke,它們的函數原型是:
int (*exec)(struct bContext *, struct wmOperator *);
int (*invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *);

  invoke exec 多出一個 struct wmEvent* 參數,返回類型是int,其實是下面的無名enum類型。
  調用execinvoke后,都會 OPERATOR_RETVAL_CHECK(ret) 測試一下返回值。
  invokeexec多出的一句是:wm_region_mouse_co(C, event);

 OPERATOR_RETVAL_CHECK

  Blender的用戶偏好設置是可以保存在.blend文件里的,這是關於Splash的。
source/blender/makesrna/intern/rna_userdef.c
  prop = RNA_def_property(srna, "show_splash", PROP_BOOLEAN, PROP_NONE);
  RNA_def_property_boolean_negative_sdna(prop, NULL, "uiflag", USER_SPLASH_DISABLE);
  RNA_def_property_ui_text(prop, "Show Splash", "Display splash screen on startup");

source/blender/makesdna/DNA_userdef_types.h
  USER_SPLASH_DISABLE = (1 << 27),

 

參考:
Context + Operator = Action!

 

 

 

 

 

blender工程_blender插件開發入門

 

金門走狗 2020-12-27 03:33:07  825  收藏 5

文章標簽: blender工程

版權

 

身為游戲開發者,不想只用blender建模,想寫插件提升工作效率?

 

一、介紹

我希望這篇文章可以讓你快速入門,早知道插件的套路,少走彎路,這篇文章將先直接快速演示一遍如何創建插件工程,從為blender添加一個簡單實用小功能開始,開始帶大家在接下來的時間逐漸熟悉blender插件開發,然后才是回過頭來,介紹必要的常識資料。

 

(我想大家在blender畫貼圖后,一定會一遍一遍不厭其煩的手動保存貼圖-UV/Image_Editor-Image-Save All Images,因為blender文件保存時不會保存貼圖等數據,一旦什么時候忘記保存貼圖,在心安理得保存完blender文件后關閉blender猛然想起貼圖沒了,可謂欲吐血。這次要添加的簡單又極其實用的功能便是:保存blender文件時自動保存所有已修改圖片)

 

建議跟隨本文章演示做一遍,本篇文章創建的基礎工程將在未來不斷填充擴展功能。

 

本文章使用2.79版本,建議插件入門不要使用2.8版本。

 

二、創建第一個插件工程

1、進入blender的用戶插件文件夾,創建工程文件

 

 

上兩圖貼出了blender的兩個插件路徑。

 

第一個路徑是用戶目錄插件,目錄:userAppDataRoamingBlender FoundationBlenderscriptsaddons,代表非系統原生插件,blender所有安裝的外置插件最終都會被解壓放置到這個文件夾下。安裝插件可以在blenderaddon界面直接選擇zip文件安裝,也可以把zip文件中文件夾直接拖入此目錄完成安裝。。

 

第二個是系統插件路徑,不建議將自己寫的插件放入此地,此地不少系統插件的代碼可在以后做參考用,值得了解。

 

請在userAppDataRoamingBlender FoundationBlenderscriptsaddons文件夾下新建工程文件夾HelloAddon,並在HelloAddon文件夾下再次新建三個文件夾“command_operators"model_data""view_panels"

 

工程文件布局仿造mvc,在前期,我們會經常與command_operatorsview panels打交道,組合blender自身的命令與編寫相關界面,至於數據層自然也都是blender內置的各種數據了,基本不需要自定義數據層,暫不關注model_data文件夾。

 

我使用的文本編輯器為sublime3,僅有方便打開工程文件與python語法高亮功能:

 

 

2、新建基礎腳本

a.HelloAddon文件夾下新建入口腳本__init__.py

 

 

bl_info = {

    "name": "HelloAddon",

    "author": "作者",

    "version": (1, 0),

    "blender": (2, 79, 0),

    "location": "View3D > Tool Shelf >HelloAddon Panel",

    "description": "插件描述",

    "warning": "",

    "wiki_url": "",

    "category": "3D View",

}

 

import bpy

import logging

from . import model_data

from . import command_operators

from . import view_panels

 

 

def register():

    bpy.utils.register_module(__name__)

    command_operators.register()

    view_panels.register()

 

 

def unregister():

    bpy.utils.unregister_module(__name__)

    command_operators.unregister()

    view_panels.unregister()

 

if __name__ == "__main__":

    register()

以上代碼就是套路,不需要理解,主體為bpy.utils.register_module(__name_),作用是注冊import進來的所有模塊。至於command_operators.register() view_panels.register()則代表其他非模塊相關的注冊。這里的代碼以后要新建工程直接ctrl c即可。

 

view_panels文件夾底新建腳本_init__.py

 

 

import bpy

 

 

def register():

    pass

 

 

def unregister():

    pass

 

3、開始添加自動保存圖片功能

command_operators文件夾下新建腳本save_dirty_images.py

 

 

import bpy

from bpy.app.handlers import persistent

from bpy.types import Operator

 

 

@persistent

def save_dirty_images(dummy):

    bpy.ops.image.save_dirty()

    print('save image')

保存文件時自動保存圖片的其中一句關鍵代碼就在這里,即使用了系統命令bpy.ops.image.savedirty()

 

擴展:可以在blender的系統腳本中找到此命令的類SaveDirty(Operator) 查看實現path:blender/release/scripts/startup/bl_operators/image.py

 

這個類的參數Operator,代表此類為blender可調用的操作類,其他函數中可根據bl_idname中的值直接調用執行此類的execute方法,bl_labelblender界面中直接調用執行此方法的命令名稱,可在blender2.79中空格鍵鍵入SaveAllDirtyImages直接執行此類中的execute中的函數功能。

我們的腳本中首先使用了一個空函數save_dirty_imagesdummy)調用命令bpy.ops.image.save_dirty(),即執行系統類SaveDirtyoperator)的execute方法,這樣包裝起來是為了后續要將此函數傳入blender的保存文件回調方法中做參數,該方法接受一個函數而不是方法,且@persistent與(dummy)是必須的參數。此外我們在save_dirty_images函數底下 print('save image')輸出語句,以便待會能在控制台看到執行成功的消息。

 

這里雖然創建了可直接執行的命令,但要使得保存blender時自動保存修改過的圖片,還差了一步:找到blender保存文件的回調函數,並將此類附加上去。

 

commandoperators文件夾下新建_init__.py腳本

 

 

import bpy

 

from . import(

    save_dirty_images,

)

 

 

def register():

    #bpy.app.handlers.save_pre.appendblender保存文件時的回調

    bpy.app.handlers.save_pre.append(save_dirty_images.save_dirty_images)

 

 

def unregister():

    bpy.app.handlers.save_pre.append(save_dirty_images.save_dirty_images)

好了,我們的目的已經達到了,接下來打開blender,開始看效果!

 

4、打開blender,啟用插件,測試功能

ctrl+alt+U打開配置界面,啟用HelloAddon,並點擊左下按鈕SaveUserSettings保存設置。

 

 

Window/Toggle System Console打開控制台,待會可看到命令執行成功我們要輸出的語句。

 

 

 

回到blender主界面,空格鍵后輸入SaveAllDirtyImages,可以看到我們剛才寫的函數:

 

 

回車鍵執行,可看到控制台輸出了save image

 

 

也可以直接ctrl-s保存blender文件,也會在控制台輸出save image,代表確實執行了保存圖片命令,不過我們目前還未創建圖片,沒能看到效果,創建圖片的步驟留給讀者自行嘗試,在image editor創建圖片后切換到paint模式抹兩筆,先手動將圖片保存到自己要的目錄,然后就可以開始測試了,繼續往圖片上抹,然后ctrl-s保存blender文件,將能觀察到圖片也自動保存更新了。

 

保存blender文件時自動保存所有更改圖片,從此再無忘記保存圖片的煩惱,各位讀者用起來!

 

5、功能升級

上述雖然實現了保存文件自動保存圖片功能,但唯一的缺點是其只對已有保存路徑的圖片而言有效,若是新建圖片還未保存指定保存路徑,那么此方法會將其直接忽視掉,原因見前面的系統腳本實現。

 

所以我們現在來改寫系統的方法,當然不是直接更改系統文件,我們將其實現copy出來,加上一個提示功能:若有新建圖片未指定保存路徑,則自動將圖片保存到blender文件的根目錄下。

 

代碼如下:

 

 

import bpy

import os

from bpy.app.handlers import persistent

from bpy.types import Operator

 

 

@persistent

def save_dirty_images(dummy):

    unique_paths = set()

    for image in bpy.data.images:

        if image.is_dirty:

            if image.packed_file:

                if image.library:

                    self.report({'WARNING'},

                                "Packed library image: %r from library %r"

                                " can't be re-packed" %

                                (image.name, image.library.filepath))

                else:

                    image.pack(as_png=True)

            else:

                # blender與圖片均無路徑,則忽略此圖片自動保存

                # blender有路徑而圖片無路徑,根目錄上自動保存

                if image.filepath == "":

                    if not bpy.data.filepath == "":

                        filepath = CreateUniquePath(os.path.split(bpy.data.filepath)[0] + "", image.name, ".png")

                        image.filepath = filepath

                else:

                    filepath = bpy.path.abspath(image.filepath,

                                                library=image.library)

 

                if "" not in filepath and "/" not in filepath:

                    print("Invalid path: " + filepath)

                elif filepath in unique_paths:

                    print("Path used by more than one image: %r" %

                          filepath)

                else:

                    unique_paths.add(filepath)

                    image.save()

                    print('save image')

 

 

def CreateUniquePath(base_path, file_name, extension):

    path = base_path + file_name + extension

    while os.path.isfile(path):

        file_name += ".001"

        path = base_path + file_name + extension

    return path

 

 

class SaveDirty(Operator):

    """Save all modified textures"""

    bl_idname = "image.save_dirty_images"

    bl_label = "SaveAllDirtyImages"

 

    def execute(self, context):

        save_dirty_images(None)

        return {'FINISHED'}

將代碼更改后,現在能保存新建未指定路徑的圖片,路徑圖片名稱將與blender文件內的圖片名稱相同,若根目錄下已有相同名稱圖片,則保存名稱往后疊加.001

 

到這里為止,一個完整而實用的小功能就完成了!

 

6、為下一篇文章做准備

只有一個看不見摸不着的命令怎么行,本着全都要的原則,下面我們來實現一個UIhello world!下面先來寫一個界面函數。

 

view_panels文件夾底下新建腳本hello_panel.py,並修改viewpanels/_init__.py,添加語句

 

from . import(hello_panel)

 

view_panels文件夾底下新建腳本hello_panel.py

 

 

import bpy

from bpy.types import Panel, Menu, UIList, PropertyGroup

from HelloAddon import command_operators

 

 

class HelloWorld(Panel):

    bl_space_type = 'VIEW_3D'

    bl_region_type = 'TOOLS'

    bl_category = 'HelloAddon'

    bl_idname = 'hello_world'

    bl_label = 'HelloWorld'

    # bl_options = {'DEFAULT_CLOSED'}

 

    def draw(self, context):

        layout = self.layout

        layout.label("你好UI")

        layout.operator("image.save_dirty_images", text="保存圖片")

重新打開blender(注意blender插件更改后需要重啟blender):

 

 

可以看到T面板已經出現HelloAddon面板,包含HelloWorld標題(由bl_label決定)與Label“你好UI”以及按鈕“保存圖片”。

 

三、blender腳本插件入門心得

跟着上面做完一個插件功能,現在開始介紹如何自行深入學習blender腳本:

 

途徑1:打開blendertext editor,很多模板文件可供復讀(制):

 

 

途徑2:活用python console中的.后代碼提示快捷鍵自動補全查看方法

 

 

默認的智能提示快捷鍵未ctrl+space,對中國人而言實在不友好,我改為了ctrl+alt+/,建議讀者也改為此鍵位。

途徑3:關注OutlinerData-Blocks面板,極其方便,新手時對blender數據塊摸不着頭腦時務必打開此面板,直接http://bpy.data.xxx點出來,如bpy.data.images['myimage']....bpy.data.objects['myobj'].data...,此面板下要找什么數據一路沿着+號點下去即可看到,可以說是可視化的代碼自動補全!

 

 

途徑4:查詢api(實用性不高)

 

 

途徑5blender python 全球最大愛好者論壇:Stack Exchange

 

 

途徑6:查看各類開源插件

 

blender插件那么多,隨便拿起一個找到想學的功能就可以開始copy了,不需要自己從零走,何樂不為

 

本篇文章到此結束,有什么想法歡迎提出,下一篇文章內容將根據評論區而定,當然這第一篇文章很可能根本沒什么人看到,那我就按照自己想法繼續走啦。

 

相關資源:blender:自行編寫或修改的Blender插件-源碼_blender插件開發...

————————————————

版權聲明:本文為CSDN博主「金門走狗」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。

原文鏈接:https://blog.csdn.net/weixin_32768455/article/details/112126216

 

 

Blender插件初始化范例

 

目標

  • [x] 總結Blender插件初始化范例

總結

插件模板

Blender內部插件實現方式模板功能總結如下:

  1. 定義了子模塊重加載方式
  2. 定義了批量加載子模塊的方式
  3. 插件注冊函數
  4. 插件注銷函數

模塊總體結構如下:

# 支持子模塊重加載(support reloading sub-modules)if "bpy" in locals():

    from importlib import reload

    _modules_loaded[:] = [reload(val) for val in _modules_loaded]

    del reload

# 定義要加載的模塊

_modules = [

    "add_mesh_torus",

    ...

    ]

import bpy

# 模塊加載, __import__()相當於 from __name__ import _modules__import__(name=__name__, fromlist=_modules)

_namespace = globals()

_modules_loaded = [_namespace[name] for name in _modules]del _namespace

 

def register():

    from bpy.utils import register_class

    for mod in _modules_loaded:

        for cls in mod.classes:

            register_class(cls)

 

def unregister():

    from bpy.utils import unregister_class

    for mod in reversed(_modules_loaded):

        for cls in reversed(mod.classes):

            if cls.is_registered:

                unregister_class(cls)

范例

Blender Foundation\Blender\2.79\scripts\startup\bl_operators\__init__.py

# ##### BEGIN GPL LICENSE BLOCK #######  This program is free software; you can redistribute it and/or#  modify it under the terms of the GNU General Public License#  as published by the Free Software Foundation; either version 2#  of the License, or (at your option) any later version.##  This program is distributed in the hope that it will be useful,#  but WITHOUT ANY WARRANTY; without even the implied warranty of#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the#  GNU General Public License for more details.##  You should have received a copy of the GNU General Public License#  along with this program; if not, write to the Free Software Foundation,#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.## ##### END GPL LICENSE BLOCK #####

# <pep8 compliant>

# support reloading sub-modulesif "bpy" in locals():

    from importlib import reload

    _modules_loaded[:] = [reload(val) for val in _modules_loaded]

    del reload

 

_modules = [

    "add_mesh_torus",

    "anim",

    "clip",

    "console",

    "file",

    "image",

    "mask",

    "mesh",

    "node",

    "object_align",

    "object",

    "object_randomize_transform",

    "object_quick_effects",

    "presets",

    "rigidbody",

    "screen_play_rendered_anim",

    "sequencer",

    "uvcalc_follow_active",

    "uvcalc_lightmap",

    "uvcalc_smart_project",

    "vertexpaint_dirt",

    "view3d",

    "wm",

    ]

import bpy

if bpy.app.build_options.freestyle:

    _modules.append("freestyle")

__import__(name=__name__, fromlist=_modules)

_namespace = globals()

_modules_loaded = [_namespace[name] for name in _modules]del _namespace

 

def register():

    from bpy.utils import register_class

    for mod in _modules_loaded:

        for cls in mod.classes:

            register_class(cls)

 

def unregister():

    from bpy.utils import unregister_class

    for mod in reversed(_modules_loaded):

        for cls in reversed(mod.classes):

            if cls.is_registered:

                unregister_class(cls)

 

 

Blender插件編寫指南

 

前言

Blender插件是Blender的利器, 用戶可以使用各種插件擴充Blender的功能.

Blender Python插件以bpy.props, bpy.types.Operator, bpy.types.Panel, bpy.types.UILayout, (...)為基礎, 通過用戶自定義包來實現.

插件要點

  1. 定義操作器
  2. 定義操作器控制面板(或菜單)
  3. 注冊/注銷操作器和面板

簡單實例

bl_info = {

    "name": "Move X Axis",

    "category": "Object",

}

import bpy

 

class ObjectMoveX(bpy.types.Operator):

    """My Object Moving Script"""      # blender will 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 by blender when running the operator.

 

        # The original script

        scene = context.scene

        for obj in scene.objects:

            obj.location.x += 1.0

 

        return {'FINISHED'}            # this 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 blenders text editor# to test the addon without having to install it.if __name__ == "__main__":

    register()

參考

  1. Blender插件之操作器(Operator)實戰 1
  2. BlenderUILayout 2
  3. Blender插件之Panel 3
  4. BlenderProperty 4
  5. Addon Tutorial 5

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM