从零开始 blender插件开发

blender 插件开发

文章目录

  • blender 插件开发
    • 环境配置
      • 1. 偏好设置中开启相关功能
      • 2. 命令行打开
      • 运行脚本
    • API学习
      • 专有名词
      • 1. bpy.data 从当前打开的blend file中,加载数据。
      • 2. bpy.context 可用于获取活动对象、场景、工具设置以及许多其他属性。
      • 3. bpy.ops 用户通常通过按钮、菜单项或快捷键访问的工具。
    • 将脚本融入blender, 成为blender的一部分
      • 1. 通过添加ui
      • 2. 通过添加功能(operator)
    • 从脚本到add-on
      • 1. 组成部分
      • 2.示例
    • 资料

环境配置

1. 偏好设置中开启相关功能

打开blender, 快捷键ctrl+,, 打开偏好设置面板。进行下列相关设置(下图为设置好的状态)

设置好后, 鼠标浮动在会出现工具提示,右键可以展示相关的菜单。
在这里插入图片描述
在这里插入图片描述

2. 命令行打开

第一种方法:

  • 将blender.exe所在路径添加到环境变量中
  • 打开命令行,输入blender, 即可打开blender,命令行中会出现软件运行相关的信息, 包括python的print输出. 注意要先关掉软件,再关掉命令行。
    ps: 目前来看,命令行主要是用来展示信息,而不是输入命令。

第二种方法:

  • 打开blender之后,点击如下图所示。
    在这里插入图片描述

运行脚本

点击如下按钮。
在这里插入图片描述
之后,界面变为下图。
在这里插入图片描述

API学习

专有名词

  • context
    在这里插入图片描述

1. bpy.data 从当前打开的blend file中,加载数据。

2. bpy.context 可用于获取活动对象、场景、工具设置以及许多其他属性。

请注意,上下文是只读的,这意味着不能直接修改这些值。但是,可以通过运行 API 函数或使用数据 API 来更改它们。

3. bpy.ops 用户通常通过按钮、菜单项或快捷键访问的工具。

从用户的角度来看,它们是一个工具,但 Python 可以通过 bpy.ops 模块使用自己的设置运行这些。
许多工具(运算符)都有一个 “poll” 功能,用于检查光标是否在有效区域中,或者对象是否处于正确的模式(Edit Mode、Weight Paint Mode 等)。当运算符的 poll 函数在 Python 中失败时,会引发异常。

if bpy.ops.view3d.render_border.poll():
    bpy.ops.view3d.render_border()

将脚本融入blender, 成为blender的一部分

1. 通过添加ui

  • By defining menus, headers and panels.
    通过定义菜单、标题和面板。

  • By inserting new buttons into existing menus, headers and panels.
    通过将新按钮插入到现有菜单、标题和面板中。

import bpy  # 导入Blender的Python API模块


# 定义一个自定义面板类 HelloWorldPanel,继承自 bpy.types.Panel
class HelloWorldPanel(bpy.types.Panel):
    """创建一个面板,在 '对象属性' 窗口中显示"""
    
    # 面板的标签,会显示在Blender UI中
    bl_label = "Hello World Panel"
    
    # 面板的唯一ID,用于Blender内部识别
    bl_idname = "OBJECT_PT_hello"
    
    # 面板显示的空间类型,这里是 'PROPERTIES',即对象属性窗口
    bl_space_type = 'PROPERTIES'
    
    # 面板显示的区域类型,这里是 'WINDOW',表示在窗口区域显示
    bl_region_type = 'WINDOW'
    
    # 面板显示的上下文,这里是 'object',即与对象相关的上下文
    bl_context = "object"

    # 面板的绘制方法,这个方法会在面板中绘制UI元素
    def draw(self, context):
        layout = self.layout  # 获取面板的布局对象,用于在面板中添加控件

        obj = context.object  # 获取当前选中的活动对象

        # 创建一行(row),并在其中添加一个标签,显示 "Hello world!" 并使用 'WORLD_DATA' 图标
        row = layout.row()
        row.label(text="Hello world!", icon='WORLD_DATA')

        # 创建新的一行,显示当前活动对象的名称
        row = layout.row()
        row.label(text="Active object is: " + obj.name)

        # 创建新的一行,添加一个控件,让用户可以编辑活动对象的名称
        row = layout.row()
        row.prop(obj, "name")  # 添加一个属性控件,允许修改对象的 'name' 属性

        # 创建新的一行,添加一个操作按钮,点击时会添加一个立方体到场景中
        row = layout.row()
        row.operator("mesh.primitive_cube_add")  # 这个操作会添加一个立方体到当前场景


# 注册类和面板的函数
def register():
    bpy.utils.register_class(HelloWorldPanel)  # 注册 HelloWorldPanel 面板类


# 注销类和面板的函数
def unregister():
    bpy.utils.unregister_class(HelloWorldPanel)  # 注销 HelloWorldPanel 面板类


# 这部分代码确保如果脚本直接执行时,面板会被注册
if __name__ == "__main__":
    register()  # 注册面板
 

在这里插入图片描述

2. 通过添加功能(operator)

import bpy


def main(context):
    # 遍历当前场景中的所有对象
    for ob in context.scene.objects:
        print(ob)  # 打印每个对象的信息


class SimpleOperator(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "object.simple_operator"  # 操作的唯一标识符
    bl_label = "Simple Object Operator"  # 操作的名称,显示在UI中

    @classmethod
    def poll(cls, context):
        # 确保只有在有活跃对象时才允许执行该操作
        return context.active_object is not None

    def execute(self, context):
        # 当操作被触发时,调用 main 函数打印所有对象信息
        main(context)
        return {'FINISHED'}  # 操作完成


def menu_func(self, context):
    # 将操作添加到 Blender 对象菜单中
    self.layout.operator(SimpleOperator.bl_idname, text=SimpleOperator.bl_label)


# 注册操作和菜单项
def register():
    bpy.utils.register_class(SimpleOperator)  # 注册 SimpleOperator 操作类
    bpy.types.VIEW3D_MT_object.append(menu_func)  # 将操作添加到对象菜单


# 注销操作和菜单项
def unregister():
    bpy.utils.unregister_class(SimpleOperator)  # 注销 SimpleOperator 操作类
    bpy.types.VIEW3D_MT_object.remove(menu_func)  # 从对象菜单中移除操作


if __name__ == "__main__":
    # 如果脚本直接执行,注册操作和菜单项
    register()

    # 测试调用 SimpleOperator 操作,打印场景中所有对象
    bpy.ops.object.simple_operator()

在这里插入图片描述

从脚本到add-on


附加组件,也就是我们说的插件 add-on。本质上就是对脚本的一种包装。

1. 组成部分

从一个最简单的示例看起

bl_info = {
    "name": "My Test Add-on",
    "blender": (2, 80, 0),
    "category": "Object",
}
def register():
    print("Hello World")
def unregister():
    print("Goodbye World")

bl_info 添加插件的时候,显示的相关信息。包括插件名字,版本号等等。
registerenable插件的时候运行。
unregister disable插件的时候使用。

2.示例

接下来的示例将展示,一个python脚本如何包装为插件

python脚本如下

import bpy

scene = bpy.context.scene
for obj in scene.objects:
    obj.location.x += 1.0
首先将脚本包装为一个函数, 将函数作为一个类的excute方法, 并添加相关属性:用作菜单项和按钮的提示信息。
class ObjectMoveX(bpy.types.Operator):
    """My Object Moving Script"""      # 用作菜单项和按钮的提示信息。
    bl_idname = "object.move_x"        # 唯一标识符,用于按钮和菜单项引用。
    bl_label = "Move X by One"         # 显示在界面上的名称。
    bl_options = {'REGISTER', 'UNDO'}  # 启用撤销和注册功能。

    def execute(self, context):        # 执行操作时调用此方法。

        # 原始脚本
        scene = context.scene            # 获取当前场景
        for obj in scene.objects:        # 遍历场景中的所有对象
            obj.location.x += 1.0        # 将对象的X轴坐标加1.0

        return {'FINISHED'}              # 告诉Blender操作已成功完成。
    

接下来将这个功能添加到菜单中。先写一个添加到菜单的函数。

def menu_func(self, context):
    self.layout.operator(ObjectMoveX.bl_idname)  # 将操作按钮添加到菜单中。

接下来,根据插件的三大组成:信息+注册+注销
信息

bl_info = {
    "name": "Move X Axis",               # 插件名称
    "blender": (2, 80, 0),                # 兼容的Blender版本
    "category": "Object",                 # 插件所属分类
}

注册函数,注册分为两部分,一是功能注册,而是ui注册

def register():
    bpy.utils.register_class(ObjectMoveX)         # 注册操作类
    bpy.types.VIEW3D_MT_object.append(menu_func)  # 将新的操作添加到现有菜单中。

注销,注销只需要注销功能。

	def unregister():
    bpy.utils.unregister_class(ObjectMoveX)       # 注销操作类

很好,再看一示例。

先看python脚本

import bpy
from bpy import context

# 获取当前场景
scene = context.scene

# 获取 3D 游标的位置
cursor = scene.cursor.location

# 获取当前激活的对象(假设我们有一个激活的对象)
obj = context.active_object

# 现在复制这个对象
obj_new = obj.copy()

# 新对象必须被添加到场景中的一个集合里
scene.collection.objects.link(obj_new)

# 现在可以将新对象放置在 3D 游标的位置
obj_new.location = cursor

这段代码的功能是,将选中激活的物体,复制到cusor位置,代码执行前
在这里插入图片描述
代码执行后
在这里插入图片描述

接下来省级一下这个python脚本,实现从选中物体到光标之间复制多个物体.

import bpy
from bpy import context

scene = context.scene
cursor = scene.cursor.location
obj = context.active_object

# 目前使用固定值,将来可以让用户调整这个值
total = 10

# 在场景中添加 'total' 个对象
for i in range(total):
    obj_new = obj.copy()  # 复制对象
    scene.collection.objects.link(obj_new)  # 将新对象添加到场景的集合中

    # 根据 'i' 将新对象放置在游标和活动对象之间
    factor = i / total  # 计算当前对象的位置比例
    # 将新对象的位置设置为介于活动对象和游标之间
    obj_new.location = (obj.location * factor) + (cursor * (1.0 - factor))

代码执行前同上,代码执行后

在这里插入图片描述
接下来,我们将其变为一个插件.
第一步,依然是包装这个脚本为一个函数,包装这个函数为一个类中的excute方法. 并为这个类添加相关属性

class ObjectCursorArray(bpy.types.Operator):
    """Object Cursor Array"""  # 操作符的描述
    bl_idname = "object.cursor_array"  # 操作符的 ID
    bl_label = "Cursor Array"  # 操作符的显示名称
    bl_options = {'REGISTER', 'UNDO'}  # 操作符的选项,包括注册和撤销支持

    def execute(self, context):
        # 获取当前场景
        scene = context.scene
        # 获取 3D 游标的位置
        cursor = scene.cursor.location
        # 获取当前激活的对象
        obj = context.active_object

        # 设置要创建的对象数量
        total = 10

        # 创建并定位对象
        for i in range(total):
            # 复制当前激活的对象
            obj_new = obj.copy()
            # 将新对象添加到场景的集合中
            scene.collection.objects.link(obj_new)

            # 计算新对象的位置,使其位于活动对象和游标之间
            factor = i / total
            # 将新对象的位置设置为活动对象和游标之间的插值位置
            obj_new.location = (obj.location * factor) + (cursor * (1.0 - factor))

        # 返回操作完成
        return {'FINISHED'}

第二步,将这个功能添加到菜单或者ui中.

def menu_func(self, context):
    self.layout.operator(ObjectCursorArray.bl_idname)

第三步,添加插件三部 信息+注册+注销

bl_info = {
    "name": "Cursor Array",  # 插件的名称
    "blender": (2, 80, 0),  # 支持的 Blender 版本
    "category": "Object",  # 插件类别
}
def register():
    bpy.utils.register_class(ObjectCursorArray)
    bpy.types.VIEW3D_MT_object.append(menu_func)

def unregister():
    bpy.utils.unregister_class(ObjectCursorArray)

合并之后,整体代码

bl_info = {
    "name": "Cursor Array",  # 插件的名称
    "blender": (2, 80, 0),  # 支持的 Blender 版本
    "category": "Object",  # 插件类别
}

import bpy


class ObjectCursorArray(bpy.types.Operator):
    """Object Cursor Array"""  # 操作符的描述
    bl_idname = "object.cursor_array"  # 操作符的 ID
    bl_label = "Cursor Array"  # 操作符的显示名称
    bl_options = {'REGISTER', 'UNDO'}  # 操作符的选项,包括注册和撤销支持

    def execute(self, context):
        # 获取当前场景
        scene = context.scene
        # 获取 3D 游标的位置
        cursor = scene.cursor.location
        # 获取当前激活的对象
        obj = context.active_object

        # 设置要创建的对象数量
        total = 10

        # 创建并定位对象
        for i in range(total):
            # 复制当前激活的对象
            obj_new = obj.copy()
            # 将新对象添加到场景的集合中
            scene.collection.objects.link(obj_new)

            # 计算新对象的位置,使其位于活动对象和游标之间
            factor = i / total
            # 将新对象的位置设置为活动对象和游标之间的插值位置
            obj_new.location = (obj.location * factor) + (cursor * (1.0 - factor))

        # 返回操作完成
        return {'FINISHED'}

def menu_func(self, context):
    self.layout.operator(ObjectCursorArray.bl_idname)
    
# 注册操作符
def register():
    bpy.utils.register_class(ObjectCursorArray)
    bpy.types.VIEW3D_MT_object.append(menu_func)


# 注销操作符
def unregister():
    bpy.utils.unregister_class(ObjectCursorArray)


# 如果是直接执行脚本,注册操作符
if __name__ == "__main__":
    register()

此外,官方还给出了一些示例,可以从这里打开
在这里插入图片描述
在这里插入图片描述

资料

官方给出了多个链接用于学习

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/913037.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【若依框架】代码生成详细教程,15分钟搭建Springboot+Vue3前后端分离项目,基于Mysql8数据库和Redis5,管理后台前端基于Vue3和Element Plus,开发小程序数据后台

今天我们来借助若依来快速的搭建一个基于springboot的Java管理后台,后台网页使用vue3和 Element Plus来快速搭建。这里我们可以借助若依自动生成Java和vue3代码,这就是若依的强大之处,即便你不会Java和vue开发,只要跟着石头哥也可…

Java基于SpringBoot+Vue的宠物共享平台的设计与实现(附源码,文档)

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…

前端入门一之DOM、获取元素、DOM核心、事件高级、操作元素、事件基础、节点操作

前言 JS是前端三件套之一,也是核心,本人将会更新JS基础、JS对象、DOM、BOM、ES6等知识点,这篇是DOM;这篇文章是本人大一学习前端的笔记;欢迎点赞 收藏 关注,本人将会持续更新。 文章目录 DOMDOM简介1.1、什么是DOM1…

Python小游戏22——吃豆豆小游戏

运行效果图 【python】代码展示 import pygame import random # 初始化Pygame pygame.init() # 屏幕尺寸 WIDTH, HEIGHT 800, 600 WIN pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("吃豆豆小游戏") # 颜色定义 WHITE (255, 255, 255) B…

「Mac畅玩鸿蒙与硬件32」UI互动应用篇9 - 番茄钟倒计时应用

本篇将带你实现一个番茄钟倒计时应用,用户可以设置专注时间和休息时间的时长,点击“开始专注”或“开始休息”按钮启动计时,应用会在倒计时结束时进行提醒。番茄钟应用对于管理时间、提升工作效率非常有帮助,并且还会加入猫咪图片…

2024 网鼎杯 - 青龙组 Web WP

2024 网鼎杯 - 青龙组 WEB - 02 打开容器一个登录界面,随便输入账号密码可以进到漏洞界面 这里有一个发送给boss的功能,一眼xss 有三个接口:/flag 、/update 、/submit /flag :要求boss才能访问,/update &#xf…

【笔记】自动驾驶预测与决策规划_Part6_不确定性感知的决策过程

文章目录 0. 前言1. 部分观测的马尔可夫决策过程1.1 POMDP的思想以及与MDP的联系1.1.1 MDP的过程回顾1.1.2 POMDP定义1.1.3 与MDP的联系及区别POMDP 视角MDP 视角决策次数对最优解的影响 1.2 POMDP的3种常规解法1.2.1 连续状态的“Belief MDP”方法1. 信念状态的定义2. Belief …

ffmpeg 视频滤镜:屏蔽边框杂色- fillborders

滤镜描述 fillborders 官网链接 > FFmpeg Filters Documentation fillborders滤镜有几种方式帮你屏蔽边框的杂色、不好的图案。 滤镜使用 参数 left <int> ..FV.....T. set the left fill border (from 0 to INT_MAX) (default 0)right …

Java基础——类和对象的定义链表的创建,输出

目录 什么是类&#xff1f; 什么是对象? 如何创建链表&#xff1f; 尾插法&#xff1a; 头插法&#xff1a; 输出链表的长度 输出链表的值 什么是类&#xff1f; 创建Java程序必须创建一个类class. .java程序需要经过javac指令将文件翻译为.class字节码文件&#xff0c…

简单的 docker 部署ELK

简单的 docker 部署ELK 这是我的运维同事部署ELK的文档&#xff0c;我这里记录转载一下 服务规划 架构: Filebeat->kafka->logstash->ES kafka集群部署参照: kafka集群部署 部署服务程序路径/数据目录端口配置文件elasticsearch/data/elasticsearch9200/data/elas…

【初阶数据结构篇】二叉树OJ题

文章目录 须知 &#x1f4ac; 欢迎讨论&#xff1a;如果你在学习过程中有任何问题或想法&#xff0c;欢迎在评论区留言&#xff0c;我们一起交流学习。你的支持是我继续创作的动力&#xff01; &#x1f44d; 点赞、收藏与分享&#xff1a;觉得这篇文章对你有帮助吗&#xff1…

5分钟科普:AI网关是什么?应用场景是什么?有没有开源的选择?

AI网关的功能及其定义 AI网关位于企业应用与内外部大模型调用的交汇点&#xff0c;能够灵活地将请求转发给内部自建模型或外部大模型服务提供商&#xff0c;甚至海外的服务商。它管理着企业所有的AI出口流量&#xff0c;为企业内的不同团队提供了多方面的优势。 对于开发团队…

Ansys Zemax | 手机镜头设计 - 第 4 部分:用LS-DYNA进行冲击性能分析

该系列文章将讨论智能手机镜头模组设计的挑战&#xff0c;从概念和设计到制造和结构变形分析。本文是四部分系列中的第四部分&#xff0c;它涵盖了相机镜头的显式动态模拟&#xff0c;以及对光学性能的影响。使用Ansys Mechanical和LS-DYNA对相机在地板上的一系列冲击和弹跳过程…

凸优化理论,凸二次规划问题,对偶问题及KKT条件

凸优化理论 ​ 研究凸优化之前我们不妨提出几个小问题&#xff1a; 什么是优化问题&#xff1f;优化问题的解是什么&#xff1f;什么是凸优化问题&#xff1f;凸优化问题的解决方案是什么&#xff1f; 1.1 优化问题 ​ 理解优化问题其实很简单&#xff0c;我们其实从高中事…

实战攻略 | ClickHouse优化之FINAL查询加速

【本文作者&#xff1a;擎创科技资深研发 禹鼎侯】 查询时为什么要加FINAL 我们在使用ClickHouse存储数据时&#xff0c;通常会有一些去重的需求&#xff0c;这时候我们可以使用ReplacingMergeTree引擎。这个引擎允许你存储重复数据&#xff0c;但是在merge的时候会根据order …

3DGS与NeRF的区别

0 论文链接 nerf&#xff1a;https://arxiv.org/abs/2003.08934 3dgs&#xff1a;https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/3d_gaussian_splatting_low.pdf 1 简要 1.1 nerf neural radiance fields神经辐射场 作者提出了一种优化来自一组输入图像的场景…

关于python的复习

Python的基础 自动声明: 在 Python 中&#xff0c;不需要显式声明变量类型&#xff0c;变量的类型是在赋值时根据值自动推断的。 动态类型: Python 是动态类型语言&#xff0c;变量的类型可以在运行时改变。 x 10 # 整数 x "hello" # 现在是字符串 变量…

HBuilderX运行微信小程序,编译的文件在哪,怎么运行

1. 点击HBuilderX顶部的运行-运行到小程序模拟器-微信开发者工具&#xff0c;就会开始编译 2. 编译完成后的文件在根目录找到 unpackage -- dist -- dev -- mp-weixin, 这里面就是编译后的文件&#xff0c;如果未跳转到开发者工具&#xff0c;那可能是没设置启动路径&#xff0…

自然语言处理在客户服务中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 自然语言处理在客户服务中的应用 自然语言处理在客户服务中的应用 自然语言处理在客户服务中的应用 引言 自然语言处理概述 定义…

【学习笔记】Kylin-Desktop-V10-SP1 麒麟系统知识4——设备设置

提示&#xff1a;学习麒麟Kylin-Desktop-V10-SP1系统设备设置相关知识&#xff0c;包含设备设置进入方法、配置打印机、设置鼠标、键盘相关参数&#xff08;包含输入法的配置&#xff09;、以及管理快捷键组合、和多屏协同相关配置 一、前期准备 成功安装麒麟系统&#xff08…