您好，欢迎使用艺术家脚本。我叫Sybren。
在这一集中，我将向您展示如何创建自己的运算符。
到当前为止，我们仅创建了代码片段，您可以使用它们，但是它们不是最用户友好的。
许多人问过创建菜单和按钮以及自描绘面板和内容的方法。
在本集中，我们将不再关注。
但是，我们将考虑一个必要的第一步，即创建您的第一个运算符。
我们将看看运算符的确切含义，
然后，我们将了解如何创建自己的运算符以及如何使它成为现实。
通过向其传递参数来提高灵活性。
然后，我们通过将运算符限制为特定的上下文来得出结论。
运算符(operator)应在菜单，按钮和热键以及应由其运行的代码之间粘合。
在第一集中
我们已经通过将运算符从菜单和按钮复制粘贴到我们自己的脚本中来与他们进行合作。
运营商可以实施
在Blender中使用C编程语言编写。
或者，它们当然可以用Python编写。
无论如何制造，它们都具有相同的成分。
首先是一个标识符。因此，
这就是您要放在“bpy.ops”之后的内容，例如，在此运算符中，它远非完整，
但是我们正在创建它。所以在这个例子中
“bpy.ops.sfa.example”。
这些总是形式“某些类别 句号 一个名称”。
最好选择一个已经存在的类别，例如对象或网格或雕刻
或任何适合您的运算符的东西。
但是正如您所看到的，您也可以创建自己的。然后，我们有一个标签。
这就是菜单项和按钮上显示的内容，并以工具提示显示说明。
然后，一切都合并了
类别(Class)这是我们待会儿要讨论的问题。
现在，仅将其视为收集运算符所有成分的锅具。
你可以看到
该类以运算符命名。
因此，我们用大写字母表示类别，然后将OT作为运算符类型，
然后其余的标识符。
到当前为止，我们已经看到了描述，但是还没有看到实际的代码。
可以用不同的方式添加用于不同的目的。
因此，这里有从简单到复杂的可能性。
您具有“运行”，这是您放置的位置代码的主要功能。
如果要创建600只猴子，则可以在这里进行。
运行功能也是直接从Python调用什麽。
因此，如果您呼出运算符，例如“bpy.something.something”
那就是被调用的函数。
然后我们有“Invoke”，当调用菜单的运算符时调用此函数
或一个按钮。
如果您想做一些额外的事情，在这种情况下，您想要有一些稍微不同的行为，
那麽您可以在Invoke中运行此操作，然后从那里调用Execute函数。
现在，我们进入最复杂的模态模型。
模态功能适用于需要较长时间运行的特殊运算符。
这会收到各种事件在Blender中， 当您移动鼠标时，单击按钮，然后使用键盘，就可以了。
诸如Blender Cloud，纹理浏览器或CG美洲狮之类的东西，
Retopo，Float，已实施，就象这样。
如果所有这些之后，如果您不确定要使用哪个功能，请保持简单，
只需使用运行功能。
如果结果证明您无法做自己想做的事，那麽您就有具体的理由
看一些更复杂的东西。但在此之前，只需保持简单即可。
现在，让我们将其转换为可以使用的实际运算符。
让我们再制造一些猴子。
让我们从删除不需要的内容开始。
让我们保持简单，只是一个Execute函数。如果您看一下网格运算符，
您会看到，它们以“bpy.ops网格原始猴子添加”或
“bpy.ops网格原始ico球形添加”开头
因此，所有创建新网格对象的运算符都以“网格”开头。
因此，让我们继续这样做。
因此，ID名称变为“mesh”，我们将创建一个猴子网格。
猴子网格，标签为“猴子网格”，工具提示将为
“让我们散播一些喜悦”
然后我们必须更改类名称，即成为类别
“mesh_ot_monkey_grid”。
Execute函数必须运行某些操作，但还必须告诉Blender一切是否成功。
这样一切都很好，您返回“完成”
这告诉Blender代码实际上运行得很好，
但是也许您的运算符无法工作，也许是为了拉伸网格
且网格没有任何顶点。
因此，在这种情况下，您将返回“已取消”。
还有其他一些选项，它们都在菜单中进行了描述。
去那里您可以转到“帮助”，然后转到“Python API参考”，
然后转到有关“bpy.ops”的部分。
所以我们假设 一切都会正常进行，
我们将返回“完成”。
现在，我们要做的就是将代码放入此处以创建我们的猴子网格。
因此，让我们复制“脚本艺术家”第3章中的代码，并将其放在此处。
因此，这会在25行中创建600只猴子，
它们之间有一个Blender单元。
运算符几乎已经完成了。所以我们这里有所有的成分。
现在我们唯一需要做的就是告诉Blender这个操作项存在，这叫做注册。
幸运的是，这很简单，我们只称
“bpy.utils.register_class”，然后是类的名称， 在本例中为“网眼OT猴子网格”。
为了对称，
还应该有取消注册功能。这样看起来象这样。
代替调用“注册类”，它被称为“取消注册类”。
基本上，它撤消了寄存器功能的作用，然后，我们快要完成了。
如您所知，当您拥有
这样的函数，运行脚本时不会自动调用它。
有一个小窍门。
如果您在此处添加这样的魔术，它看起来会有些奇怪。
但是从根本上讲，这意味着，如果运行此脚本，则应调用register函数。
Blender可以通过多种方式访问​​脚本，运行脚本，也可以从其他方式导入脚本，
就象我们导入BPY一样，其他代码也可以导入此文档。
因此，从其他位置导入与运行之间是有区别的。而且只有在运行时，
它应该调用Register函数吗，这就是这段代码的作用。
现在，我们可以做的就是将其命名为“monkey_grid.py”
很好
然后点击播放。
而且什麽也没发生，这是一件好事。
我们没有看到任何错误消息，我们的代码也没有显示任何消息。
因此，这里的沉默是件好事。
那麽，让我们看看现在会发生什麽，
“bpy.ops.mesh.monkey_grid”
好了 我们可以创建一个猴子抓地力。
运算符在那里。让我们散布一些喜悦。我们不要在这里称呼它。
让我们看看是否可以在F3菜单中找到我们的新运算符
和猴子在一起，还有你的猴子网格。所以这真的很酷。
按“输入”运行它。如您所见，
Blender现在冻结一只正在制造600只猴子。
这就是当您运行需要花一些时间在Execute函数中 并且没关系的事情时发生的情况。
该代码是
此Blend文档。因此，让我们看看创建新的Blend文档时会发生什麽。
如您所见，运算符仍在那儿。
已加载到Blender的内存中。
它已注册，并且一直在发送。
现在，让我们看看会发生什麽如果重新启动Blender。
现在，猴子网格运算符不再存在。
这是因为，Blender不仅运行了可以在Blend文档中找到的所有脚本， 还必须告诉它首先运行该脚本。
您必须确保文本文档的名称以“.py”结尾，
然后在文本菜单中，
您可以选中已注册复选框。
现在，保存，重新启动Blender，
现在就在那里。因此，让我们玩得开心，并添加一些参数。
添加立方体时，在此处左侧看到的内容称为“重做”面板。
打开它时，您会看到不同的参数
您可以设置。所以发生的是
当您更改参数值时，
Blenderoa会自动地按下“撤消”按钮和重新运行运算符。
这就是为什麽将其称为“重做”面板的原因，因为它一直在重做。
因此，让我们向运算符添加对“重做”面板的支持。
我们首先声明我们想要的属性。
这将是X方向上的猴子数，Y方向上的猴子数以及猴子的大小。
就象运算符位于“bpy.ops”中一样，属性也位于“bpy.props”中。
再说一遍，如果你想要获取更多信息，
只需转到“帮助”，“Python”，“API参考”，然后单击“bpy.props”部分。
我给你看看起来象什麽。
我们称其为“count x：bpy.props.IntProperty”。
IN代表整数，表示整数，因为我们不能有半只猴子。
所以计数X必须是一或二或三，
但永远不能象2.5一样。
因此，它仅是整数，它声明我们要拥有该属性。
这里的“：”和此处的“=”符号之间有很大的区别。
这将一个名称设置为一个值，
这是为了只需设置。我们必须设置“BL ID名称”以匹配
“猴子网格”使其工作。但是在这里我们并没有真正设置任何东西。
我们只是向Blender声明，这是一个IN属性，请相应运行操作。
您可以在此处添加一些参数以更改行为。
首先，我们应该设置一个名称。
我们可以称它为X。这可能有点神秘。
但就当前而言，会做到的。
我们可以添加一个描述，
“X方向上的猴子数”。
因此，我们将其复制到Y。
将此Y命名为“Y方向上的猴子数”，并命名为任意大小，
这就是另一个“bpy.props.FloatProperty”
float代表浮点数，是仅十进制数字的技术术语。
“名称=大小”和“描述=每只猴子的大小”，这为我们提供了属性，但尚未使用。
让我们来看看
在我们应该使用它们的Execute函数中。
这个注释必须走，因为我们不再在25行中创建600只猴子，但是它非常灵活。
因此，让我们暂时将其删除。
现在我们必须访问属性。
因此，我们已经声明了它们，并且此“自我”使我们可以访问实际值。
“自我”是很重要的事情，在这里我不会详细介绍它所代表的含义。
只要知道，如果您声明
此处的属性为count X， 那麽您可以在此处以“self.count X”访问它。
所以猴子总数
是X和Y方向上的猴子数，
这里的25是X方向上的猴子数。
然后，剩下的就是设置一个大小，
就是这样。
试一试吧。
让我们看看控制台中发生了什麽。
在这里，您可以看到我们的属性，X，Y，大小，
它们都等于0，因为我们尚未设置任何默认值。
那里，我们有我们的三只猴子。
在我们从视口实际调用它之前，让我们设置一些明智的默认值。
默认值为3。
对于Y，默认值为2，我故意在其中选择不同的值。
这是默认值。
因此，当有人单击猴子网格按钮或从F3列表中选择它时，
这将是他们所追求的。
因为他们看到3x2的网格，所以他们立即知道需要进行哪些更改。
如果他们想将3更改为4，只需将3更改为4，而不必考虑是X方向还是Y方向。
因此，如果我们给他们相同的默认值，那麽他们将看不到它。
然后，他们将拥有
例如哪个方向是X，哪个方向是Y，我想更改哪个值。
这就是为什麽我给他们独特的价值观。
最后，默认大小，再次运行，
删除所有内容。
在这里，您可以看到默认值。
当我们运行时没有任何值时，它将仅使用默认值。
与F3菜单相同。
还剩下一个步骤，那就是获得“重做”面板。我们有属性，
因此，Blender知道该去哪里。
只是还不知道我们是否支持该Redo面板。
因此，让我们告诉Blender我们这样做。
这是通过“bl选项”完成的。默认值为“注册”，
并且我们必须在其中添加“撤消”。这将为我们提供最终成分。
这就对了，
现在我们可以使它们变大和变小，甚至为它们提供无效的值。
因此，为了让人们使用起来愉快，我们应该对滑块进行真正的设置，
以便，您可以在此处选择所有明智的值。
幸运的是，这很简单。
我们可以设置最小值为1。
因为创建0个猴子没有意义。甚至更少地制造负数猴子。
因此，让我们尝试1。现在将最大数量设置为10。
我们可以对Y计数做同样的事情，
我们可以将大小0设置为最小值，将最大值设置为1。
现在，我们可以拖拉，并且一切仍然美好而理智。
您会看到，当这些数字增加时，它已经变得有点慢了。
而且我们仍然无法达到之前的600
即使我在此处键入100，它也会被最大程度地切断。
因此，这就是Blender具有软限制的原因。
硬限制是我们现在设置的，即属性值的绝对限制。而软限制是
拖动时滑块将运行的操作。
因此，如果您想允许最大值大于10或大小大于1，但仍然需要这些限制
作为滑块的极限，您可以将最大值更改为柔和的最大值。
我们现在拥有的最小值实际上是最小值，因为创建0个猴子没有意义，
负数的猴子是不可能的。同样，创建一个负大小的猴子也是不可能的。
因此，让我们将最大值更改为soft。
现在，拖动仍然是相同的，
但是我们可以将其设置为创建比拖动更多的猴子。
现在，让我们回到该类声明。
我将进一步解释有关类如何以初始方式工作的信息，
我希望不要过多地讨论技术细节。
类使用称为继承的系统，
就象与人一样，它就象一个父子结构。
因此，在这种情况下，“bpy.types.operator”是父级，
并且“网格OT猴子网格”是访问到子级。
如果您问孩子一个您知道答案的问题，例如您想吃饼干，
当然，孩子会立即不答应父母。
但是，如果您询问税收，那麽“妈妈，请帮助我，因为我什麽都不知道！”
然后孩子顺从这个问题交给父母。
大致上，类与Python中的工作方式相同。
我们可以不用“bl”选项。
我们的孩子对此一无所知。于是Python问父母。
当我们想拥有不同的东西时，我们可以为孩子和班级添加“bl”选项。
然后，首先要问因此优先于父母的意愿。
因此，我们总是有幸运的孩子们得到他们想要的所有cookie。
在结束本视频之前，我还有两件事我想告诉你。
再次，我们看一下Execute函数。
您会看到它获得了一个上下文参数，这非常类似于我们之前所见的上下文。
它给我们“上下文对象”，“context.scene”，“context.selected对象”，
您之前在“ bpy.context”中看到的所有这些内容也都到达了这里，
但是随后专门针对此运算符进行了本地化。
因此，作为一般经验法则，如果您有一个获取上下文的函数，请使用该上下文。
请勿使用“ bpy.context。
因此，如果您想在此Execute函数中对所有选定的姿势骨骼进行操作，
您将使用“context.selected姿势骨骼”。
另一个功能是我想向您展示的第二件事，另一个获得上下文的功能是Poll功能，
而且它的编写方式有点怪异，但只要从我这里获取，它就可以那样工作。
同样，您在此函数中获得一个上下文。
但是，除了做类似的事情，而不是运行动作，
此功能旨在检查是否可以运行此操作。
因此，每次应该在菜单中显示此运算符时，Blender都会调用此轮询功能，
或作为面板上的按钮。我可以告诉你这是如何工作的。
现在，返回“true”，这意味着它始终象以前一样被允许。 和以前一样，
它显示在F3菜单中。
当我碰到“假(False)”的时候，
它永远不会出现在任何地方，这是没有用的。
让我们对其进行调整，使其更加有用。
您可以在控制台中看到这里
我们有自动完成功能，这在Python控制台中很有意义。
但是那个运算符不起作用
在3D视口中，因为上下文错误。这也是我们可以做的事情。
现在，当我再次将其更改为“真(true)”时，
Monkey网格运算符也会在Python出现的上下文中显示。
它会显示在Blender中的任何位置，这并不是正确的方法。
让我们再看一看在该上下文中的变量处。
“Context.area”为您提供了Blender用户界面中 当前处于活动状态的区域。
因此，在这种情况下，它将是控制台。
但是如果鼠标在这里，我们拉出3个菜单，
然后突然之间，它的3D视口处于活动状态，这里就是“大纲视图”。
所以Blender中的每个区域都有自己的区域类型
我们可以在“投票”功能中使用该功能，以确保它仅在该地区有效
我不喜欢的一件事是猜测。
因此，我们现在知道控制台的“区域类型”是“控制台”，但是在3D视口中是吗？
是“3D视图”吗？“3D_view”，是“3D视口”吗？
我不知道。因此，让我们让脚本告诉我们。
我可以说“打印我的区域是context.area.type”
让我们看看将所有这些打印稿发送到的终端上发生了什麽。
在这里，您看到了控制台，然后立即看到它被称为
“我的区域是3D视图”。当我在大纲视图中运行此操作时， “我的区域就是大纲视图”。
如果我在“属性”面板中运行此操作，
我的区域是属性。
这样，您就可以使用这些打印语句来知道必须放置在什麽位置。
现在，我们知道了要为3D视口使用哪个值。
因此，让我们开始吧。
如果“context.area.type = view 3D”，则返回“true”。
否则，我们可以返回“false”。
让我们看看它是如何工作的。
在这里，它仍然显示。
但是这里不再存在，当然，这里和那里现在只显示在我们希望它显示的位置。
最后一件事，
这种结构，我也从经验丰富的进程员那里看到很多。
它比必要的更为复杂。
因为这个家伙已经是对或错的表达。
因此，基本上，代码在说什麽，如果这个东西的价值，这个选定的表达式，
如果该事物的值为true，则返回true；
如果该事物的值为false，则返回false。
所以这基本上意味着
返回该事物的值，您当然可以这样写。
这就是“艺术家脚本”这一集的内容。
如果您有任何疑问或意见，请在下面发表评论，我们很快会再见。