文档章节

Blender的插件开发-Operator操作器(算子)

openthings
 openthings
发布于 2015/01/28 09:14
字数 1216
阅读 827
收藏 1

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

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

import bpy

class 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 bpy

class 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 bpy

class 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 bpy

class 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_float
import bpy

class 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 type
bpy.types.Object.my_float = bpy.props.FloatProperty()

# remove
del bpy.types.Object.my_float

        对类对象同样适用:

class MyPropGroup(bpy.types.PropertyGroup):
    pass
MyPropGroup.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 bpy

bl_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 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()

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

In the menu

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

Operator Property

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

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


© 著作权归作者所有

openthings
粉丝 323
博文 1140
码字总数 689435
作品 1
东城
架构师
私信 提问
Blender的插件开发-对象体系探索

按照python的说法一切皆对象,Blender中亦然。 Blender的根对象是bpy,因此任何模块都需要: import bpy 注意: Blender的脚本print("hello")函数是输出信息到启动的控制台的,直接运行的时候...

openthings
2015/01/27
1K
3
Rook:基于Ceph的Kubernetes存储解决方案

Rook是一款运行在Kubernetes集群中的存储服务编排工具,在0.8版本中,Rook已经变成Beta发行版,如果还没有尝试过Rook,可以现在尝鲜。 Rook是什么,为什么很重要?Ceph运行在Kubernetes集群中...

店家小二
2018/12/18
0
0
Blender的插件开发-快速入门

使用Blender创建精彩非凡的作品,你可以是三维图形、创意设计的专家,但不必要成为软件开发的专家。 Blender具有强大的插件扩展功能,不仅可以加载大量的各种功能、效率增强插件,而且稍微懂...

openthings
2015/01/27
3.9K
5
Airflow在Kubernetes上的操作器

Airflow在Kubernetes (第一部分): 一种不同类型的Operator 作者: Daniel Imberman (Bloomberg LP) 译者:openthings,2019.02.26. 原文:https://kubernetes.io/blog/2018/06/28/airflow-on-......

openthings
2018/07/07
831
0
Blender 源码学习--Operator

Blender 的 c 语言 api 与 python api 颇为相似。[感觉像Python的超级扩展] Mesh Subdivide 下面是对 blender 中的 mesh subdivide operator 代码的分析 Registration 首先我们需要在 wind...

openthings
2015/01/28
2.4K
2

没有更多内容

加载失败,请刷新页面

加载更多

golang-字符串-地址分析

demo package mainimport "fmt"func main() {str := "map.baidu.com"fmt.Println(&str, str)str = str[0:5]fmt.Println(&str, str)str = "abc"fmt.Println(&s......

李琼涛
今天
4
0
Spring Boot WebFlux 增删改查完整实战 demo

03:WebFlux Web CRUD 实践 前言 上一篇基于功能性端点去创建一个简单服务,实现了 Hello 。这一篇用 Spring Boot WebFlux 的注解控制层技术创建一个 CRUD WebFlux 应用,让开发更方便。这里...

泥瓦匠BYSocket
今天
6
0
从0开始学FreeRTOS-(列表与列表项)-3

FreeRTOS列表&列表项的源码解读 第一次看列表与列表项的时候,感觉很像是链表,虽然我自己的链表也不太会,但是就是感觉很像。 在FreeRTOS中,列表与列表项使用得非常多,是FreeRTOS的一个数...

杰杰1号
今天
4
0
Java反射

Java 反射 反射是框架设计的灵魂(使用的前提条件:必须先得到代表的字节码的 Class,Class 类 用于表示.class 文件(字节码)) 一、反射的概述 定义:JAVA 反射机制是在运行状态中,对于任...

zzz1122334
今天
5
0
聊聊nacos的LocalConfigInfoProcessor

序 本文主要研究一下nacos的LocalConfigInfoProcessor LocalConfigInfoProcessor nacos-1.1.3/client/src/main/java/com/alibaba/nacos/client/config/impl/LocalConfigInfoProcessor.java p......

go4it
昨天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部