在这篇文章中,我将向你展示如何在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的文档中找到更多信息。
如何在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度。我们每旋转一次相机就拍一张照片。这样,我们就围绕着一个三维物体拍摄了多张二维图片,在本例中是立方体,但也可以是任何物体。
现在就到此为止吧!我觉得这篇文章很有用。
如果你想做一个动画,也许你想阅读下一篇文章,在那里我创建了一个旋转的甜甜圈的小动画。
在那之前,祝你编码愉快!
资源
Blender Python API播放列表
Github源代码: render_360_cube_with_material.py