Blender 3D - 如何使用Python API在Blender中创建和渲染一个场景

2,028 阅读9分钟

在这篇文章中,我将向你展示如何在Blender中使用Python 2.9 Blender API创建一个场景。我们将用一个平面、一个立方体、纹理、一个光源和一个摄像机创建一个简单的场景。然后,我将向你展示如何围绕立方体旋转一个虚拟摄像机,并使用Blender API从不同的视角将其从3D渲染到2D。

用Blender创建一个Python脚本

首先要做的是打开Blender,点击脚本标签。然后点击新建

导入bpy Python包

为了能够使用Blender的Python API,你总是需要导入bpypython库。

import bpy

以艰难的方式创建一个立方体

我知道Blender已经带有一个默认的立方体,但既然我们想学习Blender,最好把它删除,然后创建我们自己的立方体,对吗?

要创建一个立方体,有不止一种方法。你可以通过使用from_pydata函数来指定立方体的顶点和面,这样做总是很困难的。对于你自己设计的更复杂的网格,学习如何使用这个函数肯定是有价值的。下面是代码的样子。

import bpy
vertices=[(1,1,-1),(1,-1,-1),(-1,-1,-1),(-1,1,-1),(1,1,1),(1,-1,1),(-1,-1,1),(-1,1,1)]
new_mesh=bpy.data.meshes.new("new_mesh")
#make object from the mesh
view_layer=bpy.context.view_layer

如果你对我是如何写这段代码感到好奇,我建议你观看下面的视频。

底线是,你只想用这种方式创建一次立方体。当你匆忙时......你想用简单的方法。

如何以简单的方式创建一个立方体

为了节省时间,我们可以使用bpy.ops.mesh.primite_cube_add函数来向我们的场景添加一个立方体。

bpy.ops.mesh.primitive_cube_add()

在没有任何参数的情况下,这个立方体将以1的大小被创建,并且在原点(0,0,0)。

为了增加立方体的大小和移动它,我们可以使用。

bpy.ops.mesh.primitive_cube_add(size=3, location=(0,0,1.5))

让我们也添加一个平面来支持我们的立方体。

bpy.ops.mesh.primitive_cube_add(size=10)

如果我们想移动立方体,我们也可以用:

cube.location[0]+=10

这条指令在X轴上移动立方体10个单位。

如何在Blender中用Python创建光源

为了渲染一个场景,我们需要一个光源。没有光源,在Blender中进行渲染时,一切都会变得很暗。

要创建一个光源。

light_data = bpy.data.lights.new('light', type='POINT')

上面的代码创建了一个光源,但它在哪里呢?

默认情况下,光源是在原点,所以它是在立方体的内部!让我们改变它的位置。
让我们改变它的位置。

light.location = (3, 4, -5)

现在我们可以看到光源了!

为了看看这个光源在Blender中的作用有多大,我们可以对它进行渲染。

正如你所看到的,我们的光源并不是那么强大。

这个光源是点状的,类似于人造光。为了控制光源的功率,我们以瓦特为单位设置强度。

light.data.energy=200.0

还有更多类型的灯。如果你想要一个更强大的光,类似于太阳,我们不创建一个POINT类型的光,而是创建一个SUN类型的光。

light_data = bpy.data.lights.new('light', type='SUN')

在这种情况下,光源的强度不是以瓦特为单位,而是以每米平方的瓦特为单位,但属性名称仍称为能量。

light.data.energy=200

尽管我们使用的能量值与POINT光源相同,但SUN光源的能量更强。

还有更多类型的光源,比如说点光源和区域光源。

你可以在Blender的文档中找到更多信息。

docs.blender.org/manual/en/l…

如何在Blender中用Python创建一个摄像机

没有摄像机,就不可能将一个场景从3D渲染到2D。所以我们来创建一个摄像机。

# we first create the camera object

再说一次,默认情况下,摄像机是以原点为中心的。

设置它的位置和以前一样简单。

cam.location=(25, -3, 20)

我们只是有一个问题。摄像机是朝下的,立方体的视野不是很好。我们将在以后解决这个问题。

现在,我们已经很高兴了,因为我们已经创建了一个有摄像机、光源和照相机的场景

如何在Blender中使用Python创建和分配材质

下一步是为立方体创建并分配一个材质。

要创建一个新的材质。

# create material

要分配一个材料。

cube.data.materials.append(mat)

我们指定use_nodes=True来启用Blender中节点的功能。

mat.use_nodes=True

通过Blender中的节点,你可以创建非常复杂的材料,通过树状的多个节点组成,使用各种输入对材料进行一些操作,这些输入可以从一个节点路由到另一个节点。

它非常强大,但也可能变得非常复杂。默认情况下,在Blender中创建的新材质有一个原则性的BSDF着色器节点和一个材质输出节点。

原理BSDF着色器节点允许创建许多不同类型的材料,都在一个着色器节点中:玻璃、金属、塑料、果冻,以及更多。

如果你想进一步了解这个神奇的着色器节点,我推荐你观看Blender大师的这个深入的视频:spltech.co.uk/media/c7983…

当你看完后,请回到这里,我们可以继续。

如何使用Python配置原则性的BSDF节点

我们将使用Principled BSDF节点来使我们的立方体看起来像一面金属镜。

# let's create a variable to store our list of nodes
# let's set the metallic to 1.0

粗糙度属性控制发生多少反射。我把它设置为0,这意味着所有的光线都被反射。

我们可以改变底色,使其反射率降低。

mat_nodes['Principled BSDF'].inputs['Base Color'].default_value=(0.05, 0.0185, 0.8, 1.0)

如果你想知道我是如何得到颜色值的,我在编码之前使用了Blender的用户界面。

让我们也为这个平面添加一个材质。

# create material
mat_nodes['Principled BSDF'].inputs['Base Color'].default_value=(0.010, 0.0065, 0.8, 1.0)

现在我们有了一个蓝色的平面。看起来不是很好,但也不算太差。

好吧,这还不是值得在Blender Reddit频道上分享的东西。但是,我们必须从某个地方开始!

如何使用Blender Python API渲染和保存场景到图片中

现在我们已经成功地在Blender中使用Python创建了一个场景,现在是时候渲染它并把它保存到图片上了。

你为什么要这样做呢?有很多用例。我能想到的一个用例是为用于深度学习的合成数据集生成图像。Blender在机器视觉领域的许多出版物中被提及,因为它非常强大,可以生成照片般逼真的图像。

让我们生成一个图像,看看它是什么样子的。

scene = bpy.context.scene

我们得到的结果相当奇怪。

之所以会出现这种奇怪的图像,是因为我们添加到场景中的摄像头与Z轴完全对齐,向下看。而你看到的黑色的东西,不是立方体,而是Blender的悬崖。立方体在左手边的某个地方,但不在摄像机的视野内。

我们想要的是摄像机向下看,以一个角度,指向立方体。我们可以很容易地旋转摄像机,直到它指向立方体。

cam.rotation_euler(0.9, 0.0, 1.1)

其中0.9、0.0和1.1是x、y和z轴上的一个角度,单位是弧度。现在我们可以看到,摄像机已经指向了立方体。

当我们现在再次进行渲染时,我们得到的是。

好多了,但仍然不是很好。我们可以进一步对准摄像机,但有一个更好的方法

用Python在Blender中用摄像机跟踪物体

要添加一个约束条件来使用摄像机跟踪一个物体,就像这样简单。

constraint = cam.constraints.new(type='TRACK_TO')

就这样,摄像机现在会看向立方体,不管它位于哪里。
对立方体进行新的渲染,就会生成立方体的如下图像。

如何使用Python在Blender中围绕立方体旋转摄像机

我们接下来要做的是通过将摄像机围绕立方体旋转360度来生成多个图像。这并不像看起来那么简单,因为Blender的API已经发生了变化,围绕另一个物体旋转相机并不那么简单。但是仍然有一个简单的方法

要围绕一个物体旋转摄像机,我们只需要平移它的位置属性。因为我们在摄像机中已经有了一个约束条件,即看向立方体,无论我们把摄像机放在哪里,它都会看向立方体。

感谢 堆叠溢出,我发现了一个很好的即用型函数,可以将一个点绕着轴线旋转到远离摄像机的地方。

import numpy as npimport math
def rotation_matrix(axis, theta):    """    Return the rotation matrix associated with counterclockwise rotation about    the given axis by theta radians.    """    axis = np.asarray(axis)    axis = axis / math.sqrt(np.dot(axis, axis))    a = math.cos(theta / 2.0)    b, c, d = -axis * math.sin(theta / 2.0)    aa, bb, cc, dd = a * a, b * b, c * c, d * d    bc, ad, ac, ab, bd, cd = b * c, a * d, a * c, a * b, b * d, c * d    return np.array([[aa + bb - cc - dd, 2 * (bc + ad), 2 * (bd - ac)],                     [2 * (bc - ad), aa + cc - bb - dd, 2 * (cd + ab)],                     [2 * (bd + ac), 2 * (cd - ab), aa + dd - bb - cc]])

使用这个函数,我们可以定义另一个函数来旋转一个点。

def rotate(point, angle_degrees, axis=(0,1,0)):
    rotated_point = np.dot(rotation_matrix(axis, theta_radians), point)
    return rotated_point

然后我们可以改变代码来渲染一个图像,如下所示。

for angle in range(0, 360, 10):

我们现在要做的是将摄像机沿原点(0,0,0)平行于Z轴的轴线旋转10度。我们每旋转一次相机就拍一张照片。这样,我们就围绕着一个三维物体拍摄了多张二维图片,在本例中是立方体,但也可以是任何物体。

现在就到此为止吧!我觉得这篇文章很有用。
如果你想做一个动画,也许你想阅读下一篇文章,在那里我创建了一个旋转的甜甜圈的小动画。

如何用Python、Blender和一些甜甜圈形状的数学来创建一个3D旋转的甜甜圈

在那之前,祝你编码愉快!

资源

Blender Python API播放列表

Github源代码: render_360_cube_with_material.py