从零开始 blender插件开发

news2024/11/23 20:50:30

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

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

资料

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

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

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

相关文章

深入理解JVM

文章目录 1. JVM内存区域划分2. JVM中类加载过程类加载(1)类加载的基本流程(2)双亲委派模型 《深入理解java虚拟机》 在这本书前,面试官对于JVM也不是很了解。 这本书主要还是写个一下开发 JVM 的人。 1. JVM内存区域…

c# 开发web服务 webserver

024-11-10<<<<<<<<<<<<<<<<<<<<<<<<<< 开始插件前Cyber_CallWeb acajax_dac_database_viewer 2024-11-10<<<<<<<<<<<<<<<<<<<<…

WPS 默认模板修改

重装系统把word自定义样式搞没了&#xff0c;安装office时间太长&#xff0c;转战wps 解决方案 打开wps 点击【新建】word空白文档 设置修改你自己的样式 点击文件–另存为–Microsoft Word 带宏的模板文件&#xff08;*.dotm&#xff09; 另存路径为如下&#xff1a; 查…

使用vite构建一个react网站,并部署到Netlify上

这篇教程中&#xff0c;我会教你如何用vite快速构建一个react网站&#xff0c;并把网站免费部署到Netlify上&#xff0c;让别人可以经由网址访问你的react网站。 1. 使用vite构建基础框架 npm create vitelatestcd vite-project npm install npm run dev2. 网站内容设计 3. 构…

GPT-5 一年后发布?对此你有何期待?

GPT-5 一年后发布?对此你有何期待? 在最新技术的洪流中,GPT-5即将登场。你是否在思考,它将为我们的生活和工作带来哪些变革?接下来的探索,或许可以启发你对未来的想象。让我们一起深入这场关于未来AI语言模型的讨论。 一、技术上的提升 1.1 更强的语言理解能力 想象一…

MPC5744P——UART通信

简介 快速通过官方的example工程跑通MPC5744P的UART通信。 一、软件工程 点击File->New->S32DS Project from Example&#xff0c;打开示例程序窗口。 选择MPC5744P->LINFlexD_UART_MPC5744P&#xff0c;点击Finish&#xff0c;创建UART的示例工程。 工程创建成功&…

安当ASP系统:适合中小企业的轻量级Radius认证服务器

安当ASP&#xff08;Authentication Service Platform&#xff09;身份认证系统是一款功能强大的身份认证服务平台&#xff0c;特别适用于中小企业。其中&#xff0c;简约型Radius认证服务器是安当ASP系统中的一个重要组成部分。以下是对该系统的详细介绍&#xff1a; 一、主要…

「Mac畅玩鸿蒙与硬件30」UI互动应用篇7 - 简易计步器

本篇将带你实现一个简易计步器应用&#xff0c;用户通过点击按钮增加步数并实时查看步数进度&#xff0c;目标步数为 10000 步。该项目示例展示了如何使用 Progress 组件和 Button 组件&#xff0c;并结合状态管理&#xff0c;实现交互式应用。 关键词 UI互动应用计步器Button…

(64)使用RLS自适应滤波器进行预测的MATLAB仿真

文章目录 前言一、仿真说明四、MATLAB仿真代码五、仿真结果总结与后续 前言 RLS&#xff08;递归最小二乘&#xff09;自适应滤波器是一种用于信号处理的算法&#xff0c;其原理基于最小二乘法。在时间序列分析中&#xff0c;RLS滤波器可以用于预测信号的下一个值。本文以股票…

Python小白学习教程从入门到入坑------第二十九课 访问模式文件定位操作(语法进阶)

一、访问模式 模式可做操作若文件不存在是否覆盖r只能读报错-r可读可写报错是w只能写创建是w可读可写创建是a只能写创建否&#xff0c;追加写a可读可写创建否&#xff0c;追加写 1.1 r r&#xff1a;只读模式(默认模式)&#xff0c;文件必须存在&#xff0c;不存在就会报错…

学习记录:js算法(八十九):电话号码的字母组合

文章目录 电话号码的字母组合思路一 电话号码的字母组合 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 如图 示例 1&…

【机器学习】均方误差(MSE:Mean Squared Error)

均方误差&#xff08;Mean Squared Error, MSE&#xff09;是衡量预测值与真实值之间差异的一种方法。在统计学和机器学习中&#xff0c;MSE 是一种常见的损失函数&#xff0c;用于评估模型的预测准确性。 均方误差的定义 假设有一组真实值 ​ 和模型预测的对应值 ​。均方误…

Uniapp安装Pinia并持久化(Vue3)

安装pinia 在uni-app的Vue3版本中&#xff0c;Pinia已被内置&#xff0c;无需额外安装即可直接使用&#xff08;Vue2版本则内置了Vuex&#xff09;。 HBuilder X项目&#xff1a;直接使用&#xff0c;无需安装。CLI项目&#xff1a;需手动安装&#xff0c;执行yarn add pinia…

Typora导出pdf手动分页和设置字体样式

手动分页 <div style"page-break-after: always;"></div>鼠标点击代码才会显示&#xff0c;不点击会隐藏。导出pdf时&#xff0c;该位置会分页 设置字体大小、加粗、居中、空格 <p style"font-size:30px; font-weight: bold; text-align: cen…

Linux相关概念和易错知识点(19)(HDD、Block group)

目录 1.HDD &#xff08;1&#xff09;HDD存储描述 &#xff08;2&#xff09;HDD结构图 &#xff08;3&#xff09;磁盘管理的分治思想 &#xff08;4&#xff09;硬盘中文件系统的整体划分图 2.Block group &#xff08;1&#xff09;文件管理 ①文件属性的存储 ②in…

【跟着官网学技术系列之Java】第1天之Java开胃菜

前言 在当今信息爆炸的时代&#xff0c;拥有信息检索的能力很重要。 作为一名软件工程师&#xff0c;遇到问题&#xff0c;你会怎么办&#xff1f;带着问题去搜索引擎寻找答案&#xff1f;亦或是去技术官网&#xff0c;技术社区去寻找&#xff1f; 根据个人经验&#xff0c;一…

网络自动化03:简单解释send_config_set方法并举例

目录 拓扑图设备信息 netmiko涉及方法send_config_set()方法的简单示例代码输出结果代码解释导入模块配置信息config_device_interface_description 函数主程序块总结 send_config_set方法参数&#xff1a;1. enter_config_mode2. config_commands3. enter_config_mode4. error…

vue2,vue3,uniapp,小程序实现前端url生成二维码

最近遇到一个项目&#xff0c;api返回url地址&#xff0c;前端通过地址生成二维码。 话不多说直接上代码&#xff0c;亲测有效&#xff0c;希望能帮助大家&#xff0c;同时如果有更好的方法希望大家能够分享 1、第一步&#xff0c;在项目的utils文件夹下面创建一个weapp-qrco…

openlayers实现图层裁剪,只展示关心区域,抹掉无关区域,“抠”地图

先给大家看一下效果: 很久没有用ol了,今天突发奇想,想完成一下在ol中如何实现图层裁剪,抹掉消除非关心区域的地图的操作。过去写了有关于遮罩和掩膜的教程,现在看来好像有点低级,不足以满足需求,于是我们重新来做一下。 首先要知道ol官方是支持canvas参数传递的,就是说…

SpringBoot框架:共享汽车管理的创新工具

5系统详细实现 5.1 管理员模块的实现 5.1.1 用户信息管理 共享汽车管理系统的系统管理员可以管理用户&#xff0c;可以对用户信息修改删除以及查询操作。具体界面的展示如图5.1所示。 图5.1 用户信息管理界面 5.1.2 投放地区管理 系统管理员可以对投放地区信息进行添加&#…