从零开始 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 bpydef 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中@classmethoddef poll(cls, context):# 确保只有在有活跃对象时才允许执行该操作return context.active_object is not Nonedef 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 bpyscene = 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.0return {'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 contextscene = 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"  # 操作符的 IDbl_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 bpyclass ObjectCursorArray(bpy.types.Operator):"""Object Cursor Array"""  # 操作符的描述bl_idname = "object.cursor_array"  # 操作符的 IDbl_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()

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

资料

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaScript 观察者设计模式

观察者模式:观察者模式(Observer mode)指的是函数自动观察数据对象,一旦对象有变化,函数就会自动执行。而js中最常见的观察者模式就是事件触发机制。 ES5/ES6实现观察者模式(自定义事件) - 简书 先搭架子 要有一个对象&#xff…

el-table 行列文字悬浮超出屏幕宽度不换行的问题

修改前的效果 修改后的效果 ui框架 element-plus 在网上找了很多例子都没找到合适的 然后这个东西鼠标挪走就不显示 控制台也不好调试 看了一下El-table的源码 他这个悬浮文字用的el-prpper 包着的 所以直接改 .el-table .el-propper 设置为max-width:1000px 就可以了 吐槽一…

IO技术详解

IO监控项在监控中一直是很重要的存在,服务有IO,磁盘有IO,操作系统也有IO,IO到底是什么呢 IO IO,即“输入/输出”(Input/Output),是指计算机系统或设备之间交换数据的过程。这个概念…

Tcp中的流量控制,拥塞控制,超时重传时间的选择,都附带相应例子说明

端口号的了解 通常进行通信时,发送方使用任意端口,指定接收方为指定端口,因为接收方在接收到后的需要根据发送方指定的接收方端口号,来选择使用哪一个服务进程进行处理。 端口号还可以分类为两个大类: TCP和UDP报文的…

Nextflow最佳实践:如何在云上高效处理大规模数据集

1. Nextflow 软件架构介绍 Nextflow 是一个用于简化数据驱动计算流程的工具,可以在各种计算环境中轻松部署。它采用了分布式计算和容器技术,实现了高度模块化、可重复性和可扩展性。NextFlow 的软件架构主要包括以下几个部分: 用户界面&…

LeetCode【0032】最长有效括号

本文目录 1 中文题目2 求解方法:动态规划2.1 方法思路2.2 Python代码2.3 复杂度分析 3 题目总结 1 中文题目 给定一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长有效(格式正确且连续)括号 子串 的长度。 示例: 输入&…

一文看懂ERP、SCM、SRM、WMS、TMS、进销存管理系统

经常有人来私信问我ERP、SCM、SRM、WMS、TMS、进销存管理系统等等,它们听起来都很专业,但到底各自是什么?承担着怎样的角色呢?它们具体都有哪些功能?相互之间又存在怎样的关联,对企业而言又意味着什么呢&am…

c++写一个死锁并且自己解锁

刷算法题: 第一遍:1.看5分钟,没思路看题解 2.通过题解改进自己的解法,并且要写每行的注释以及自己的思路。 3.思考自己做到了题解的哪一步,下次怎么才能做对(总结方法) 4.整理到自己的自媒体平台。 5.再刷重复的类…

机器学习系列----KNN分类

目录 前言 一.KNN算法的基本原理 二.KNN分类的实现 三.总结 前言 在机器学习领域,K近邻算法(K-Nearest Neighbors, KNN)是一种非常直观且常用的分类算法。它是一种基于实例的学习方法,也被称为懒学习(Lazy Learnin…

深度学习——优化算法、激活函数、归一化、正则化

文章目录 🌺深度学习面试八股汇总🌺优化算法方法梯度下降 (Gradient Descent, GD)动量法 (Momentum)AdaGrad (Adaptive Gradient Algorithm)RMSProp (Root Mean Square Propagation)Adam (Adaptive Moment Estimation)AdamW 优化算法总结 经验和实践建议…

vue登陆验证

导航守卫:直白的说,导航守卫就是路由跳转过程中的一些钩子函数,这些函数能让你在跳转过程中操作一些其他 的事的时机,这就是导航守卫。 比如最常见的登录权限验证,当用户满足条件时,才让其进入导航&…

YOLOv11实战宠物狗分类

本文采用YOLOv11作为核心算法框架,结合PyQt5构建用户界面,使用Python3进行开发。YOLOv11以其高效的特征提取能力,在多个图像分类任务中展现出卓越性能。本研究针对5种宠物狗数据集进行训练和优化,该数据集包含丰富的宠物狗图像样本…

星期-时间范围选择器 滑动选择时间 最小粒度 vue3

星期-时间范围选择器 功能介绍属性说明事件说明实现代码使用范例 根据业务需要,实现了一个可选择时间范围的周视图。用户可以通过鼠标拖动来选择时间段,并且可以通过快速选择组件来快速选择特定的时间范围。 如图: 功能介绍 时间范围选择&…

上海ABC行测试面试题回忆版本

11.14号去ABC面试,流程上先做个半个小时的笔试,然后是排队面试。这次做笔试的人很多,有JAVA,大数据,前端,测试,我是最后一批测试。现场没有敢拍照。面试的时候,一共8个面试官&#x…

云岚到家 秒杀抢购

目录 秒杀抢购业务特点 常用技术方案 抢券 抢券界面 进行抢券 我的优惠券列表 活动查询 系统设计 活动查询分析 活动查询界面显示了哪些数据? 面向高并发如何提高活动查询性能? 如何保证缓存一致性? 数据流 Redis数据结构设计 如…

【大数据测试HBase数据库 — 详细教程(含实例与监控调优)】

大数据测试HBase数据库 1. 环境准备与安装1.1 安装 HBase 环境1.1.1 下载与安装 HBase1.1.2 配置 HBase 2. 功能测试2.1 创建表和插入数据2.2 查询数据2.3 更新数据2.4 删除数据2.5 查看表格结构 3. 性能测试3.1 使用 HBase 自带的性能测试工具3.2 使用 YCSB 进行性能测试 4. 容…

JavaWeb常见注解

1.Controller 在 JavaWeb 开发中,Controller是 Spring 框架中的一个注解,主要用于定义控制器类(Controller),是 Spring MVC 模式的核心组件之一。它表示该类是一个 Spring MVC 控制器,用来处理 HTTP 请求并…

vue3+elementplus+虚拟树el-tree-v2+多条件筛选过滤filter-method

筛选条件 <el-inputv-model"searchForm.searchTreeValue"input"searchTreeData"style"flex: 1; margin-right: 0.0694rem"placeholder"请输入要搜索的设备"clearable/><imgclass"refresh-img"src"com_refres…

光伏储能微电网协调控制器

安科瑞 Acrel-Tu1990 1. 产品介绍 ACCU-100微电网协调控制器是一款专为微电网、分布式发电和储能系统设计的智能协调控制设备。该装置能够兼容包括光伏系统、风力发电、储能系统以及充电桩等多种设备的接入。它通过全天候的数据采集与分析&#xff0c;实时监控光伏、风能、储…

【C++课程学习】:继承:默认成员函数

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;C课程学习 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 构造函数 &#x1f369;默认构造函数&#xff08;这里指的是编译器生成的构造函数&#xff09;&#…