在本教程中,咱们将学习一些 Blender 脚本技术,比方如何应用代码解决、操作、复制和动画网格图元。要联合所有这些技术,咱们将创立一个波浪形的锥形图案:一个看起来很酷的动画,你能够将其转换为循环 GIF。

我将应用bpy.data模块中的一系列属性和办法来回顾最重要的bpy库。我还将介绍如何从其余 Python 文件导入代码,以及如何应用其余代码编辑器来编写 Blender 代码。当然,应用 Blender 进行创意编码还有很多其余内容,但这就是我在这个简短的教程系列中所涵盖的全部内容。

在持续之前,启动 Blender(应用命令行)。如果曾经关上它,请应用File > New > General创立一个新的 Blender 文件。能够看到一个新场景,其中一个立方体位于 xyz 坐标 (0, 0, 0)。

一、导入 bpy

bpy 库是所有魔术产生的起因。它蕴含九个次要模块,使你可能应用 Python 管制 Blender;它们是bpy.app, bpy.context, bpy.data, bpy.msgbus, bpy.ops, bpy.path, bpy.props, bpy.types, 和bpy.utils. 在 Python 控制台中,bpy库会主动导入并立刻可用。然而,当你应用文本编辑器(或任何其余代码编辑器)编写 Python 脚本时,必须先增加必要的import行,而后能力应用bpy。

留神:除了bpy,Blender 还包含几个独立的模块,例如aud用于音频,以及mathutils用于操作矩阵、欧拉、四元数和向量。

切换到 【Scripting】 选项卡,而后在【 Text Editor 】中单击 【New】 以创立新的 Python 脚本。

接着,将以下代码增加到新脚本中以导入bpy并打印场景中的对象列表:

import bpyprint(bpy.data.objects)

运行脚本(应用 Alt-P快捷键 或者 ▶ 按钮),终端应显示:

<bpy_collection[3], BlendDataObjects>

其中,bpy_collection[3]局部示意存在三个对象:相机、立方体和灯光。如果你在场景中增加或删除任何内容,[3] 会变动以反映对象的总数。

不过,bpy.data.objects 还有更多的作用. 例如,你能够应用它来解决 Outliner 列表中的特定我的项目。

二、选择对象

通过下面内容,咱们应用 Python 控制台来影响在 3D 视口中抉择的对象。不过,更多时候,咱们会心愿通过 Python 脚本来解决对象,而不依赖于 GUI 中抉择的内容。能够应用bpy按名称、对象在对象序列中的地位或某些其余属性来选择对象。如果应用的是bpy.context,则必须在 3D 视口中抉择立方体(因而它是橙色的)以应用 Python 代码对其进行操作。应用bpy.data.objects,能够解决对象,而不论 Blender 界面中的流动是什么。

应用 Pythonlist()函数 解决bpy.data.objects 以打印场景中的对象列表:

print(list(bpy.data.objects))

运行脚本时,它应该在终端中显示以下输入:

[bpy.data.objects['Camera'], bpy.data.objects['Cube'],

能够应用其键(项目名称)或索引(序列中的程序)来寻址任何对象。索引值从零开始——所以 Camera 是 item 0, Cube 是 item 1,等等。能够应用bpy.data.objects['Cube']或bpy.data.objects[1]来寻址多维数据集。接下来,咱们将应用不同的属性和办法来操作多维数据集。
 

三、属性和办法

属性就像属于对象的变量。对象的数据类型决定了它的属性。例如,立方体(由顶点组成的三维网格)包含其尺寸、坐标等属性。立方体的数据类型是 bpy_types.Object ,能够通过在终端或控制台中运行  type(bpy.data.objects['Cube'])  来确认这一点。

location属性(泛滥bpy_types.Object属性之一)蕴含立方体的坐标,能够应用它来从新定位对象:

bpy.data.objects['Cube'].location = (3, 0, 0)

这会将立方体定位在 xyz 坐标 (3, 0, 0)。在这种状况下,只会影响 x 坐标,因而能够应用:

bpy.data.objects['Cube'].location[0] = 3

请留神,.location[0]是 (3, 0, 0)中第一个 (x) 值的索引。或者,能够尝试该.location.x属性,这能够说是最直观的可读版本:

bpy.data.objects['Cube'].location.x = 3

运行脚本,立方体应挪动到新地位,沿 x 轴间隔场景核心三个单位:

因为咱们已启用 python tooltips,因而如果将鼠标指针悬停在“对象属性”面板中的任何字段上,则会有一个工具提醒批示如何在 Python 中为该特定对象解决该特定属性。该面板通常位于 Blender 界面的右下方区域,位于布局和脚本工作区中。在下图 中,工具提醒显示了立方体 x 坐标的 Python 详细信息:


如果右键单击此字段,则会有一个名为Online Python Reference的菜单选项,它会在 Web 浏览器中关上该location属性的相干文档:

记下浏览器地址栏中的 URL:https://docs.blender.org/api/2.83/bpy.types.Object.html#bpy.t...。尤其是最初一个斜线之后的内容。加载/bpy.types.Object.html网页,而后是#bpy.types.Object.location跳转/滚动到location条目。还能够应用左栏中的搜寻性能和链接导航参考。有时应用你的网络浏览器搜寻性能(Ctrl+F或Cmd+F)在给定页面上疾速查找内容会很不便。如果想尝试其余属性,无妨试试scale。

办法就像属于对象的函数。它们执行操作——例如,bpy.ops.mesh模块包含几种用于创立新网格的办法。能够很容易地区分属性和办法,因为办法的开端有一对括号。在本节中,咱们将应用不同的办法在场景中增加和删除对象。

primitive_cone_add() 办法将结构一个圆锥网格,换句话说,能够应用此办法将圆锥体增加到场景中。将此新行增加到脚本的开端:

bpy.ops.mesh.primitive_cone_add()

当运行代码时,这应该会在场景中增加一个新的锥体。

primitive_cone_add()办法还能够承受参数来指定圆锥半径、深度、地位、旋转、比例等。在脚本中增加第二条锥形,其中蕴含一个管制其地位的参数:

bpy.ops.mesh.primitive_cone_add(location=(-3, 0, 0))

运行脚本时,会呈现一个新圆锥。然而,如果查看 Outliner 面板,你会留神到场景中当初有三个圆锥体。额定的锥体是舞台地方的锥体的正本(雷同大小,雷同地位)。每次运行脚本时,你都会增加更多反复项。

为避免产生这种反复,能够增加一个循环来查看并删除场景中任何已有的网格。不再须要立方体或其代码,因而无需替换它即可。最终脚本如下所示:

import bpy# clear meshes in the scenefor obj in bpy.data.objects:    if obj.type == 'MESH':        bpy.data.objects.remove(obj)# add two conesbpy.ops.mesh.primitive_cone_add()bpy.ops.mesh.primitive_cone_add(location=(-3, 0, 0))

remove()办法从场景中移除对象。当初,每次运行脚本时,它都会在再次增加之前革除已有的网格。

四、动画

Blender的动画编程是十分弱小的,能够创立联合了 Python API、弱小的渲染器和模仿性能的令人惊叹的动静图像。请记住,这不是“实时渲染”办法。咱们将事后定义关键帧并将它们齐全渲染进去以生成造成动画的帧序列。这不是交互式的,就像你可能在Processing或某些游戏引擎中创立的那样。上面是一个根本示例,可帮忙你开始应用基于现有脚本的多帧编程。
 

将以下代码增加到脚本的开端:

...# animation variablestotal_frames = 100keyframe_interval = 10# define a one hundred frame timelinebpy.context.scene.frame_end = total_framesbpy.context.scene.frame_start = 0# add keyframesfor frame in range(0, total_frames + 1, keyframe_interval):    bpy.context.scene.frame_set(frame)    cone = bpy.data.objects['Cone']    cone.location.x = frame / 25    cone.keyframe_insert(data_path='location')

有正文行(以#结尾)来帮忙解释每个步骤。该循环在从第 0 帧到第 100 帧 ( total_frames) 的工夫线上每 10 帧 (keyframe_interval ) 插入一个新的关键帧。圆锥在关键帧之间沿 x 轴后退 0.04 个单位;Blender 将插入/补间此静止以使其平滑。

为了帮忙可视化正在产生的事件,我为Dope Sheet切换了 Console 面板(在 3D 视口下方的区域中) 。能够看到每个关键帧都示意为一个黄点。按空格键开始和进行动画;蓝色播放头线的地位批示正在播放的帧:

能够决定关键帧距离的大小。默认状况下,关键帧之间的挪动是线性的——所以,实际上,这个动画只须要第 0 帧和第 100 帧上的关键帧。但我想演示如何应用循环增加更多关键帧。如果想调整动画曲线,能够应用Graph Editor进行调整。

五、波浪锥

上面脚本联合了本教程中的所有技术来生成由圆锥体制成的波浪形图案,代码如下:

import bpyfrom math import sin, tau# clear meshes in the scenefor obj in bpy.data.objects:    if obj.type == 'MESH':        bpy.data.objects.remove(obj)# animation variablestotal_frames = 150theta = 0.0# define a one hundred frame timelinebpy.context.scene.frame_end = total_framesbpy.context.scene.frame_start = 0for x in range(30):    # generate a grid of cones    for y in range(30):        cone = bpy.ops.mesh.primitive_cone_add()        cone = bpy.context.object        cone.name = 'Cone-{}-{}'.format(x, y)        cone.location[0] = x * 2        cone.location[1] = y * 2        # add keyframes to each cone        for frame in range(0, total_frames):            bpy.context.scene.frame_set(frame)            cone.location.z = sin(theta + x) * 2 - 1            cone.keyframe_insert(data_path='location')            scale = sin(theta + y)            cone.scale = (scale, scale, scale)            cone.keyframe_insert(data_path='scale')            theta += tau / total_frames

在这种状况下,我没有应用关键帧距离。正如Dope Sheet所示,150 帧中的每一帧都有一个独自的关键帧。我应用了一个sin()函数来生成正弦波静止;必须从math库中导入这个函数,以及tau(等于 2)。运行脚本可能须要一段时间,具体取决于计算机的能力。能够缩小每个range()函数中的30参数以加快速度。

六、对于导入的更多信息

对于导入非 Blender 模块,咱们应该理解一些问题,尤其是当你将脚本拆分为多个 Python 文件或在我的项目中应用第 3 方包(库和模块)时。咱们必须应用importlib.reload() 从新加载你导入的任何 Python 代码。例如,这是一个名为bar.py的文件,其中蕴含一个greeting变量:

#bar.pygreeting = 'Hello, World!'

咱们首先须要将bar导入到名为foo.py的主脚本中,而后就能够应用greeting值。这是foo.py代码:

#foo.pyimport bpy, os, sys, importlibdir = os.path.dirname(bpy.data.filepath)sys.path.append(dir)import barimportlib.reload(bar)print(bar.greeting)

能够看到, .blend)文件、foo.py和bar.py都保留在同一个文件夹中;dir变量指向该地位。dir门路附加到 sys.path以便我能够导入该文件夹中的任何 python 文件。如果我更改bar.py中 greeting的值,该行将打印更新后的值——仅仅是因为我蕴含了print()importlib.reload(bar) 这一行。

咱们能够应用 pip(Python 包安装程序)来治理第三方包,但应该应用 Blender 附带的版本。这是装置cowsay包的演示。

首先,关上终端并进入 Blender 装置目录,而后进入其中的目录(或任何实用的版本号)。当初顺次输出以下命令:

python/bin/python3.7m python/lib/python3.7/ensurepippython/bin/pip3 install cowsay --target python/lib/python3.7/

如果是Window零碎,那么须要应用如下的命令:

python\bin\python.exe python\lib\ensurepippython\bin\python.exe -m pip install cowsay --target python\lib

能够应用python/bin/pip3 list(Windows: python\bin\python.exe -m pip list )列出已装置的软件包。终端应显示如下内容:

Package    Version---------- -------cowsay     2.0.3pip        19.0.3setuptools 40.8.0

如果想晓得 cowsay 是做什么的,能够应用以下代码运行一个新的 Blender 脚本:

import cowsaycowsay.cow('Blender is rad!')

接着,控制台会输入如下的内容:

   _______________< Blender is rad! >  ===============                   \                    \                      ^__^                      (oo)_______                      (__)\       )/\                          ||----w |                          ||     ||

七、其余代码编辑器

除了Blender之外,咱们可能还会应用别的编辑器,比方应用Atom来开发py脚本。如下图所示,我曾经编辑了print()参数并保留了更改,这会提醒 Blender 脚本编辑器显示一个解决抵触 按钮。

如果单击该按钮,则会提醒从磁盘从新加载选项;这将更新 Blender 的脚本编辑器以反映咱们在内部编辑器(Atom?)中所做的更改。还有一个Make text internal选项,它将脚本的 Blender 版本保留在 .blend 文件中(连同模型、材质和场景数据)。

当然,也能够间接从命令行执行脚本,而无需齐全启动 Blender。然而,必须增加一些代码来出现输入/视觉后果:

# foo.pyimport bpybpy.ops.mesh.primitive_cone_add(location=(-3, 0, 0))output = '/home/nuc/Desktop/render.png'bpy.context.scene.render.filepath = outputbpy.ops.render.render(write_still=True)

该脚本将一个圆锥体增加到规范场景中,而后将其渲染到一个名为render.png(在我的桌面上)的文件中。请留神,我还将脚本保留到我的桌面。要运行它,进入到我的桌面目录并执行以下命令:

<blender_dir>/blender --background --python foo.py

当然,须要用你的blender装置门路替换<blender_dir>。我用图像查看器关上输入文件 ( render.png )。如果图像文件更新,大多数查看器都会刷新,因而每次执行blender命令时,我都会看到新的渲染。

当然,咱们也能够配置代码编辑器以应用键盘快捷键(而不是终端)运行此命令。如果想要一个蕴含一些能够操作的数据的场景,请将 .blend 文件增加到命令中:

<blender_dir>/blender bar.blend --background --python foo.py

更多的晋升和技巧请参考:https://docs.blender.org/api/current/info_tips_and_tricks.html

原文参考:A Quick Intro to Blender Creative Coding