博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Blender的插件开发-Operator操作器(算子)
阅读量:5907 次
发布时间:2019-06-19

本文共 6458 字,大约阅读时间需要 21 分钟。

hot3.png

        毫无疑问,Operator是Blender中最为核心的一个对象,而且里面包罗万象(不仅可以操作几何对象,所有的菜单都可以控制,因为Blender其实就是一个三维图形的超级命令解释器嘛!)。

        我们先定义一个简单的Operator。把下面的代码复制到文本编辑中,点击“执行脚本”。

import bpyclass SimpleOperator(bpy.types.Operator):    bl_idname = "object.simple_operator"    bl_label = "Tool Name"    def execute(self, context):        print("Hello World")        return {'FINISHED'}bpy.utils.register_class(SimpleOperator)

        在三维视窗中,鼠标点击,按下空格键,输入“tool”,将会列出这个“Tool Name”的Operator工具。

        继续,选中“Tool Name”项,并没有出现上面的execute中定义的“Hello World”,怎么回事!?

        因为Blender把输出信息定义到标准输出了,如果从控制台窗口启动,将从控制台上看到输出的信息。Blender并没有把信息输出到信息窗口和python控制台,这是一个让图形界面使用者有点困惑的地方,先按下不表,后面再想办法解决。

        现在,换一种方式来定义Operator:

import bpyclass BaseOperator:    def execute(self, context):        print("Hello World BaseClass")        return {'FINISHED'}class SimpleOperator(bpy.types.Operator, BaseOperator):    bl_idname = "object.simple_operator"    bl_label = "Tool Name"bpy.utils.register_class(SimpleOperator)

        这里用到了python的类的继承特性。这是官方文档的例子,但我觉得更符合对象的定义应该是:

import bpyclass BaseOperator:    bl_idname = "object.simple_operator"    bl_label = "Tool subclass."class SimpleOperator(BaseOperator,bpy.types.Operator):    def execute(self, context):        print("Hello World,i am subclass.")        return {'FINISHED'}bpy.utils.register_class(SimpleOperator)

        酸菜萝卜,各有所爱。一种是行为优先,符合脚本化思路;第二种是标识优先,符合OO的习惯。测试了下,两种方式倒是都能运行。

        上面直接把Operator的执行类注册到系统了,下面采用更通用的做法:

import bpyclass SimpleOperator(bpy.types.Operator):    """ See example above """    def register():        bpy.utils.register_class(SimpleOperator)    def unregister():        bpy.utils.unregister_class(SimpleOperator)if __name__ == "__main__":    register()

        一个更综合一点的例子:

# Create new property group with a sub property# bpy.data.materials[0].my_custom_props.sub_group.my_floatimport bpyclass MyMaterialSubProps(bpy.types.PropertyGroup):    my_float = bpy.props.FloatProperty()class MyMaterialGroupProps(bpy.types.PropertyGroup):    sub_group = bpy.props.PointerProperty(type=MyMaterialSubProps)def register():    bpy.utils.register_class(MyMaterialSubProps)    bpy.utils.register_class(MyMaterialGroupProps)    bpy.types.Material.my_custom_props = bpy.props.PointerProperty(type=MyMaterialGroupProps)def unregister():    del bpy.types.Material.my_custom_props    bpy.utils.unregister_class(MyMaterialGroupProps)    bpy.utils.unregister_class(MyMaterialSubProps)if __name__ == "__main__":    register()

        因为“一切皆对象”,Python脚本还可以创建动态类型。如下:

# add a new property to an existing typebpy.types.Object.my_float = bpy.props.FloatProperty()# removedel bpy.types.Object.my_float

        对类对象同样适用:

class MyPropGroup(bpy.types.PropertyGroup):    passMyPropGroup.my_float = bpy.props.FloatProperty()#等价于下面的语法:class MyPropGroup(bpy.types.PropertyGroup):    my_float = bpy.props.FloatProperty()

        动态定义的对象:

for i in range(10):    idname = "object.operator_%d" % i    def func(self, context):        print("Hello World", self.bl_idname)        return {'FINISHED'}    opclass = type("DynOp%d" % i,(bpy.types.Operator, ),                       {"bl_idname": idname, "bl_label": "Test", "execute": func},                   )    bpy.utils.register_class(opclass)

    有点头大,不多解释了。运行下看:

>>> bpy.ops.object.operator_1()Hello World OBJECT_OT_operator_1{'FINISHED'}>>> bpy.ops.object.operator_2()Hello World OBJECT_OT_operator_2{'FINISHED'}

    现在,我们创建一个操作几何对象的Addon:

import bpybl_info = {    "name": "Move X Axis",    "category": "Object",    }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.    # execute() is called by blender when running the operator.    def execute(self, context):     # 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()

    一个扩展了菜单和快捷键映射的例子:

bl_info = {    "name": "Cursor Array",    "category": "Object",}import bpyclass 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 registrationaddon_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()

复制到文本编辑框,点击“运行脚本”运行下看:

In the menu

运行这个菜单项,结果如下:

Operator Property

当选中以后,可以选择一次创建多少个Cube对象。

注意:直接运行这个脚本,将会导致菜单项多次加载。但是放到Addon就没有这个问题了。

转载于:https://my.oschina.net/u/2306127/blog/372505

你可能感兴趣的文章
两种方式设置iframe的高度区别
查看>>
Iterator 和 for...of 循环
查看>>
关于iOS 11.x微信连wifi流程中,在Portal页无法拉起微信问题的简单记录
查看>>
Python GUI库wxPython官网Hello World示例的逐行解释
查看>>
RE·WORK 巅峰对话:深度学习将彻底改变医疗健康领域
查看>>
Codeforces Round #442 (Div. 2) A B
查看>>
极值问题(acms)
查看>>
swift UI专项训练8 展示数据
查看>>
一起学shell(十一)之安全的shell脚本:起点
查看>>
Microsoft® Deployment Toolkit 2010之快速部署Windows 7
查看>>
LNMP的技术讲解
查看>>
SVN Hooks的介绍及使用
查看>>
Oracle 字符集的查看和修改【上】
查看>>
tomcat注册windows服务
查看>>
使用qq邮箱的smpt服务发送邮件一定要记得用ssl
查看>>
20个非常有用的Java代码片段
查看>>
网站优化和竞价有什么区别
查看>>
MySQL开源热备工具XtraBackup的原理与程序说明
查看>>
mongoDB(1):windows下安装mongoDB(解压缩版)
查看>>
CentOS修改主机名
查看>>