使用python+blender绘制原子结构示意图--以黑磷为例

摘要

使用python+blender绘制原子结构示意图 --以黑磷为例

也可以代入其他原子结构

1.结果样式

黑磷原子结构示意图

2.blender和bpy

Blender是一款免费开源三维图形图像软件,支持python脚本创作。其中bpy库就是用来对其进行操作的。

3.绘图步骤

3.1 准备工作

3.1.1 安装blender

官网: https://www.blender.org/

3.1.2 计算参数

将需要绘制的atoms和bonds写成json文件

atom有4个元素:原子种类,颜色,半径,位置 bond有一个列表元素,列表中包含了bond的起始坐标和结束坐标。

其中前面的名字可以随意写。

输入文件

注:这里的数据不是黑磷的真实数据。

3.2 绘制图像

3.2.1 执行脚本

打开blender选择常规,可以看见下图画面。

blender初始界面

按a,再按del,删除所有元素。

在编辑-偏好设置里可以改成中文。

选择上面菜单栏中的Scripting进入脚本编辑工作区

在右边的区域新建文档将下面的代码复制粘贴进去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import bpy
import math
import json


def cylinder_between(x1, y1, z1, x2, y2, z2, r = 0.1):

dx = x2 - x1
dy = y2 - y1
dz = z2 - z1
dist = math.sqrt(dx**2 + dy**2 + dz**2)

bpy.ops.mesh.primitive_cylinder_add(
radius = r,
depth = dist,
location = (dx/2 + x1, dy/2 + y1, dz/2 + z1)
)

phi = math.atan2(dy, dx)
theta = math.acos(dz/dist)

bpy.context.object.rotation_euler[1] = theta
bpy.context.object.rotation_euler[2] = phi

try:
bpy.context.object.active_material = bpy.data.materials['bond']
except:
bpy.data.materials.new(name='bond')
bpy.data.materials['bond'].diffuse_color = [0.5,0.5,0.5,1]
bpy.data.materials['bond'].specular_intensity = 0.2
bpy.context.object.active_material = bpy.data.materials['bond']


def draw_molecule(molecule, center=(0, 0, 0), show_bonds=True, join=False,
name='molecule'):

collection = bpy.data.collections.new('atom')
bpy.context.scene.collection.children.link(collection)
# add atom primitive
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.mesh.primitive_uv_sphere_add()
sphere = bpy.context.object
for key,atom in molecule['atoms'].items():
if atom['element'] not in bpy.data.materials:
key = atom['element']
bpy.data.materials.new(name=key)
bpy.data.materials[key].diffuse_color = atom['color'] + [1]
bpy.data.materials[key].specular_intensity = 0.2

loc = atom['location']
atom_sphere = sphere.copy()
atom_sphere.data = sphere.data.copy()
atom_sphere.location = [loc[0],loc[1],loc[2]]
atom_sphere.dimensions = [atom['radius']*2]*3
atom_sphere.active_material = bpy.data.materials[atom['element']]
collection.objects.link(atom_sphere)

bpy.ops.object.select_all(action='DESELECT')
sphere.select_set(True)
bpy.ops.object.delete()

for key,bond in molecule['bonds'].items():
s = bond[0]
e = bond[1]

cylinder_between(s[0],s[1],s[2],e[0],e[1],e[2])


if join:
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.join()

if __name__ == '__main__':
r = 0.3 # radius
with open(r'E:\blenderproject\bl3\BP.json') as in_file:
molecule = json.load(in_file)

draw_molecule(molecule)
代码参考参考资料[1,2]中的内容。

将BP.json的文件路径改为先前创建好的文件的路径。 一些其他需要修改的地方(bond的半径,颜色等)也可以自行修改。

点击运行或按alt+P执行程序。可以得到下图:

执行后界面

3.2.2 扩展整列

切换到layout,选择处于原点的原子。

按a全选,再按ctrl+j结合所有元素组合

组合后界面

点击修改器属性,添加阵列修改器,数量选择20,相对位移x改为0.886,其他为0。再添加一个,这个相对偏移上y改为0.886。

修改阵列

最后shift+a添加面光、平面、相机。选取合适的角度进行渲染拍摄吧。参考资料[3]

准备拍摄

参考资料

[1] github 代码 blender-chemicals

[2] Blender & Python 两点坐标建立圆柱

[3]【Blender科研绘图】案例2-石墨烯