2018年6月18日 星期一

在Blender的script裡使用FileBrowser選取檔案

在Blender的script裡使用FileBrowser選取檔案

前言

  在上一篇初探Blender的script中,基本的使用了Blender的Script,因應日後要開發匯入/匯出3D模組的外掛,就來研究怎麼在Script裡使用FileBrowser選取檔案,在此做個紀錄。

內容

  在開始研究如何使用FileBrowser時,發現找不太到範例,在搜尋一陣子後才在Use Blender's file browser via python, without a UI panel裡發現原來Blender有自帶範例,開啟了方式如下
開啟範例
在開啟範例後,會看到以下的程式碼
import bpy


def write_some_data(context, filepath, use_some_setting):
    print("running write_some_data...")
    f = open(filepath, 'w', encoding='utf-8')
    f.write("Hello World %s" % use_some_setting)
    f.close()

    return {'FINISHED'}


# ExportHelper is a helper class, defines filename and
# invoke() function which calls the file selector.
from bpy_extras.io_utils import ExportHelper
from bpy.props import StringProperty, BoolProperty, EnumProperty
from bpy.types import Operator


class ExportSomeData(Operator, ExportHelper):
    """This appears in the tooltip of the operator and in the generated docs"""
    bl_idname = "export_test.some_data"  # important since its how bpy.ops.import_test.some_data is constructed
    bl_label = "Export Some Data"

    # ExportHelper mixin class uses this
    filename_ext = ".txt"

    filter_glob = StringProperty(
            default="*.txt",
            options={'HIDDEN'},
            maxlen=255,  # Max internal buffer length, longer would be clamped.
            )

    # List of operator properties, the attributes will be assigned
    # to the class instance from the operator settings before calling.
    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):
        return write_some_data(context, self.filepath, self.use_setting)


# 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.INFO_MT_file_export.append(menu_func_export)


def unregister():
    bpy.utils.unregister_class(ExportSomeData)
    bpy.types.INFO_MT_file_export.remove(menu_func_export)


if __name__ == "__main__":
    register()

    # test call
    bpy.ops.export_test.some_data('INVOKE_DEFAULT')

在第一次看時實在是看不太懂,所以我找了另一個教學Blender 3D: Noob to Pro/Advanced Tutorials/Blender Scripting/A User Interface For Your Addon,這個教學裡會教你用Script寫Operator,並且製作UI來啟動Operator,具體的程式碼如下
import math
import bpy
import mathutils

class TetrahedronMakerPanel(bpy.types.Panel):
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_context = "objectmode"
    bl_category = "Create"
    bl_label = "Add Tetrahedron"

    def draw(self, context):
        TheCol = self.layout.column(align=True)
        TheCol.operator("mesh.make_tetrahedron", text="Add Tetrahedron")
    #end draw

#end TetrahedronMakerPanel

class MakeTetrahedron(bpy.types.Operator):
    bl_idname = "mesh.make_tetrahedron"
    bl_label = "Add Tetrahedron"
    bl_options = {"UNDO"}

    def invoke(self, context, event):
        Vertices = \
          [
            mathutils.Vector((0, -1 / math.sqrt(3),0)),
            mathutils.Vector((0.5, 1 / (2 * math.sqrt(3)), 0)),
            mathutils.Vector((-0.5, 1 / (2 * math.sqrt(3)), 0)),
            mathutils.Vector((0, 0, math.sqrt(2 / 3))),
          ]
        NewMesh = bpy.data.meshes.new("Tetrahedron")
        NewMesh.from_pydata \
          (
            Vertices,
            [],
            [[0, 1, 2], [0, 1, 3], [1, 2, 3], [2, 0, 3]]
          )
        NewMesh.update()
        NewObj = bpy.data.objects.new("Tetrahedron", NewMesh)
        context.scene.objects.link(NewObj)
        return {"FINISHED"}
    #end invoke

#end MakeTetrahedron

bpy.utils.register_class(MakeTetrahedron)
bpy.utils.register_class(TetrahedronMakerPanel)

可以看到是Panel與Operator,TetrahedronMakerPanel是UI的部分,MakeTetrahedron則是Operator,接著最後透過register來註冊後使用。TetrahedronMakerPanel透過繼承Panel後再修改相關Property,接著透過Draw來新增一個按鍵來驅動Operator。bl_space_type是Editor的Type,在這個範例是註冊在3DView的Editor,bl_context代表的是在ObjectMode才會出現,bl_category 則是標籤的名稱,如果是不存在的標籤會自動新增,bl_label則是Panel的顯示名稱。接著是 MakeTetrahedron,透過繼承Operator後,修改相關的Property,接著透過invoke來執行程式碼。bl_idname是Operator要註冊的名稱,記住不要大寫! bl_label則是Operator的註解要顯示的字串。從這兩個例子可以看出Blender寫外掛時的模式是透過繼承後修改相關Property並重仔相關Method後,再透過register後使用。
  回到輸出檔案的範例, 可以看到ExportSomeData繼承Panel與ExportHelper,透過修改相關Property後,重載execute(),但這裡的重載Method的執行時機不太一樣,這個Method會在File browser裡的"Export Some Data"按下時才執行,如果是按下"Cancel"的話就不會被執行。在execute()裡可以在self.filepath這個Property取得儲存檔案的位置。write_some_data()這裡就是Python的基本開檔寫資料。在最後可以看到bpy.ops.export_test.some_data('INVOKE_DEFAULT')這行,這行是直接執行Operator的做法,不用透過UI驅動,可以學起來。

後記

  雖然第一次看到Blender的範例看不懂,但在經過學習後發現這個做法的程式碼相當簡潔,可真是學習了,本篇文章只看了export的範例,import的範例就不再寫了,因為作法是相像的。

參考資料

Use Blender's file browser via python, without a UI panel
Blender 3D: Noob to Pro/Advanced Tutorials/Blender Scripting/A User Interface For Your Addon

沒有留言:

張貼留言