Blender修改器开发入门
在Blender中,修改器(Modifier)是动态应用于网格的程序几何效果,可实现灵活的非破坏性工作流程。这是为 Blender 2.80 添加新修改器的编程指南。
自定义修改器不能用 Python 编写,因此本指南将展示 Blender 的 C 代码的哪些部分必须修改。
1、Blender源码构建
由于我们要修改 Blender 的核心,首先需要从源代码构建 Blender。这个过程在 Blender 的 Wiki: Building Blender中有详细记录。我将假设你遵循了有关目录名称的这些说明。
在实际开始修改代码之前,建议创建一个分支以将我们的更改与上游开发隔离。例如让我们称之为pizza-modifier
:
/../blender-git/blender $ git checkout -b pizza-modifier
在这篇文章中,我们将添加一个“Pizza”修改器。我不知道它可以做什么,但至少我们肯定不会被源库中其他出现的“pizza”这个词弄糊涂。
2、Pizza修改器概述
那么,我们需要改变什么?为什么我们需要更改这么多文件?显然,我们至少必须对修改器本身的行为进行编码。但我们还必须确保它在 UI 中列出,可以通过 Python API 访问,并且它的参数保存在Blender文件中。最后一点是使用 Blender 架构核心的 DNA/RNA 机制实现的。
我们的大部分更改位于/../blender-git/blender/source/blender/modifiers/
目录。
3、Blender核心修改器
为Blender创建修改器意味着定义一个ModifierTypeInfo
类型的全局变量。然后我们将它注册到全局修改器列表中。为了匹配编码风格并与现有宏很好地配合,此变量必须被命名为modifierType_Pizza,
其中“Pizza”是你的实际修改器名称的首字母大写形式。
3.1 修改器类型信息
修改器类型信息变量通常在/../blender-git/blender/source/blender/modifiers/intern
文件夹中MOD_pizza.c
文件中定义, 因此,创建此文件并将其添加到要在父目录CMakeLists.txt
中的构建列表中,连同以 intern/MOD_
开头的所有其他行。
至少,你的MOD_pizza.c
文件应当包含:
#include "BKE_modifier.h"
ModifierTypeInfo modifierType_Pizza = {
/* name */ "Pizza",
/* structName */ "PizzaModifierData",
/* structSize */ sizeof(PizzaModifierData),
/* type */ eModifierTypeType_None,
/* flags */ 0,
/* copyData */ NULL,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
/* initData */ NULL,
/* requiredDataMask */ NULL,
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
/* freeRuntimeData */ NULL,
};
结构ModifierTypeInfo
定义在source/blender/blenkernel/BKE_modifier.h
文件中,在我写这篇文章时的第 139 行,即使用 Blender 2.80 RC时。不同字段的含义在这个头文件中有很好的解释,所以你一定要看看。
我将专注于一些基本字段,而将其他领域留给你探索,因为根据你的修改器要实现的任务,并不一定需要所有这些字段。
3.2 类型和标志
要设置的第一个字段(在名称之后)是修改器的类型,type
字段。 这是在BKE_modifier.h
的开头定义的枚举类型,因此再次查看选项以找到最适合你的修改器的匹配项。如果不确定,可以尝试查看MOD_something.c
文件中具有类似行为的现有修改器。
另一个重要字段是flags
。 同样是一个在BKE_modifier.h
中定义的枚举。很可能你会用eModifierTypeFlag_AcceptsMesh
来告诉 Blender 你的修改器可以处理网格数据。可以使用逻辑或运算符( |
) 设置多个标志。
3.3 应用修改器
修改器的核心是applyModifier
函数中实现的功能。在定义修改器类型信息变量之前,定义一个函数,如:
#include "DNA_mesh_types.h"
static Mesh *pizza_applyModifier(struct ModifierData *md,
const struct ModifierEvalContext *ctx,
struct Mesh *mesh)
{
return mesh;
}
并将applyModifier
字段设置为pizza_applyModifier
,或者你为上述函数提供的任何名称。此功能将是修改器进行所有处理的地方。这完全取决于你自己,返回的网格可以是使用source/blender/blenkernel/BKE_mesh.h
中的函数创建的新网格,请参见附录中的示例。
3.4 其他字段
对于某些字段,可以使用定义在BKE_modifier.h
中的工具方法。例如,可以设置copyData
为modifier_copyData_generic
。
4、DNA和RNA
ModifierTypeInfo
中有两个非常重要的字段我还没有提到:structName
和structSize
。它们指向的PizzaModifierData
结构将成为我们修改器的DNA。
DNA 是.blend
文件保存在磁盘上的内容。它必须包含所有保存的参数。按照生物学的比喻,每个 DNA 都与一个 RNA 结构相关联。这个仅在运行时使用,用于编辑、传输、撤消、重做等与修改器相关的数据。
4.1 DNA
Blender 中使用的所有 DNA 结构都在source/blender/makesdna/
目录中定义。修改器定义在DNA_modifier_types.h
文件中。
首先要修改的是:添加eModifierType_Pizza
到ModifierType
文件开头的枚举中,就放在NUM_MODIFIER_TYPES
前面。 这个枚举不能重新排序,因为枚举值是保存在混合文件中的,所以它会破坏向后兼容性。这也是明确说明枚举值的原因。
在文件末尾,我们为修改器添加 DNA 结构。它的第一个字段必须是 type ModifierData
。它是一种继承机制,可以将指向结构的指针用作更通用的ModifierData*
。
typedef struct PizzaModifierData {
ModifierData modifier;
int num_olives;
int _pad0;
} PizzaModifierData;
在这个例子中,我们的修改器有一个整型参数num_olives
。
另一个要求是填充结构以使其整体大小为 8 字节的倍数。如果不是自然情况,请添加额外的_pad
前缀的字段以达到 8 的倍数。
请注意,整个文件是在构建 Blender 之前通过执行特殊程序makesdna
处理的,因此这里不能使用花哨的东西或预处理器宏。
注意:由于我们在修改器类型信息中指向的是 DNA 结构,因此必须将DNA_modifier_types.h
其包含在MOD_pizza.c
文件中。
4.2 RNA
RNA 机制位于source/blender/makesrna/
目录中。与 DNA 类似,intern
中的文件在Blender构建之前由一个名为makesrna
的定制程序处理, 这使我们免于执行一些关于 DNA/RNA 转换的非常重复的任务。
修改器的 RNA 定义在 makesrna/intern/rna_modifier.c
文件中。除非你用 DNA 制作高级的东西,否则你将主要需要编写一个类似于所有其他已经存在的简单函数 rna_def_modifier_pizza
,把这个函数添到 void RNA_def_modifier(BlenderRNA *brna)
之前:
static void rna_def_modifier_pizza(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
// Define the RNA and bind it to the PizzaModifierData DNA struct
srna = RNA_def_struct(brna, "PizzaModifier", "Modifier");
RNA_def_struct_ui_text(srna, "Pizza Modifier", "");
RNA_def_struct_sdna(srna, "PizzaModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_ARRAY);
// There will be such a block for each data field of PizzaModifierData
prop = RNA_def_property(srna, "num_olives", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 0, 100);
RNA_def_property_ui_range(prop, 0, 100, 1, -1);
RNA_def_property_ui_text(prop,
"Olives",
"The number of olives on the pizza");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
注意:您可以为您的 RNA 选择自定义图标,而不是ICON_MOD_ARRAY
我在此处选择的图标。
在 RNA_def_modifier()
的最后,添加对我们刚刚定义的rna_def_modifier_pizza(brna)
函数的调用。
4.3 修改器类型枚举
由于修改了ModifierType
枚举的 DNA,我们还需要编辑它的 RNA。为此,请在相应rna_modifier.c
部分的开头为rna_enum_object_modifier_type_items
添加一个条目。节标题是{0, "", 0, N_("Modify"), ""}
类型的行。它们与添加新修改器时显示在 UI 中的下拉菜单直接相关。第二个参数是用于绘制 UI 的 Python 函数的名称,见下文。
我们还必须编辑要在/* Default */
之前添加的rna_Modifier_refine
函数:
case eModifierType_Pizza:
return &RNA_PizzaModifier;
注意:变量RNA_PizzaModifier
不需要我们自己定义,它会由makesrna生成。
因此,我们完成了与 DNA/RNA 相关的更改。你可能对修改器参数有一些更高级的需求。如果是这样,请随意查看其他修改器如何处理特殊情况,它们都定义在同一个文件中。
注意:有关 RNA 的更多详细信息,可以查看此存档。
5、用户界面
修改器的用户界面在 Python 脚本中定义:release/scripts/startup/bl_ui/properties_data_modifier.py
.
向DATA_PT_modifiers
类添加绘图方法def PIZZA(self, layout, ob, md):
,类似于其他修改器已经存在的功能。函数的名称必须与上面rna_enum_object_modifier_type_items
( rna_modifier.c
)中定义的条目匹配。例如:
# in class DATA_PT_modifiers
def PIZZA(self, layout, ob, md):
layout.prop(md, "num_olives")
注意:构建时,请确保将此 python 文件复制到2.80/scripts/startup/bl_ui
目录中。可能需要手动复制它。
6、最后的步骤
我们的修改器有一个核心,通过 DNA 存储在Blender文件中并通过 RNA 传输,但我们仍然需要在其他地方注册它。
6.1 修改器表
修改器的类型信息需要在全局修改器表中注册。这是通过在modifier_type_init
原型之前的source/blender/modifiers/MOD_modifiertypes.h
末尾添加以下行来完成的:
extern ModifierTypeInfo modifierType_Pizza;
在source/blender/modifiers/intern/MOD_util.c
中,#undef INIT_TYPE
之前:
INIT_TYPE(Pizza);
6.2 大纲
大纲是 UI 空间,可以列出有关当前打开的Blender文件的所有技术细节。因此它必须知道所有的修改器,包括我们新的 Pizza 修饰符。在 source/blender/editors/space_outliner/outliner_draw.c
中编辑tree_element_get_icon
函数以添加适当的case eModifierType_Pizza
。 不过,我不知道为什么它不能从 RNA 中获取这条信息。
7、结论
现在,你的修改器有了第一个骨架。从现在开始,你将能够通过阅读BKE_modifier.h
的注释或其他修饰符的实现来学到很多东西。
原文链接:Writing a custom modifier for Blender
BimAnt翻译整理,转载请标明出处