阅读前请先了解VESTAC4D的基础用法,有一定Python基础更佳。

获取晶体结构

晶体及分子结构文件可通过结构数据库 Materials Project开放晶体学数据库中得到cifVESTA软件支持的格式,使用VESTA打开后经扩胞等操作调整为想要的样式后导出为wrl格式供C4D使用,流程图如下。

graph TD;
获取cif等格式的结构文件 --> VESTA中调整样式;
VESTA中调整样式 --> 导出为wrl格式文件导入C4D;
导出为wrl格式文件导入C4D --> C4D中使用优化脚本;
C4D中使用优化脚本 --> 使用C4D得到图片;

两个C4D脚本

由于vasp导出后原子是近球多面体而非球体,而在搭建示意图时常常会导入成百上千原子使,会占用过多内存使渲染速度及使用流畅度大打折扣,因此编写以下脚本加速渲染及使用。使用时打开C4D自带的脚本管理器新建脚本,删除其中内容并将脚本内容复制粘贴直接运行即可。

多面体优化成球体

此脚本会将当前工程中所有多面体对象转化成同等大小的球体对象并将原多面体材质应用于新加的球体上,其他保持不变,通过修改mat[layer.GetDataID() + c4d.REFLECTION_LAYER_MAIN_VALUE_ROUGHNESS] = 0.8的值可修改材质反射层粗糙度,对输出效果进行批量调整,也可转化完成后在C4D材质编辑器中手动修改。

{ % note warning % } C4D R19及以上版本可用

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

import c4d
from c4d import gui

# doc: c4d.documents.BaseDocument # The currently active document.
# op: typing.Optional[c4d.BaseObject] # The selected object within that active document. Can be None.


def CreateAtom(P,R):

atom = c4d.BaseObject(c4d.Osphere)

# set atom radius
atom[c4d.PRIM_SPHERE_RAD] = R

# set atom postion
atom.SetAbsPos(P)

return atom


def main():
for obj in doc.GetObjects():

if not obj.CheckType(c4d.Opolygon):
continue

# get object material and reflection layer
mat = obj.GetTag(c4d.Ttexture)
mat = mat[c4d.TEXTURETAG_MATERIAL]
layer = mat.GetReflectionLayerIndex(0)

# Sets the Layer to GGX mode
mat[layer.GetDataID() + c4d.REFLECTION_LAYER_MAIN_DISTRIBUTION] = c4d.REFLECTION_DISTRIBUTION_GGX

# Defines the Roughness float value
mat[layer.GetDataID() + c4d.REFLECTION_LAYER_MAIN_VALUE_ROUGHNESS] = 0.8

# Defines the layer color value to material color
mat[layer.GetDataID() + c4d.REFLECTION_LAYER_COLOR_COLOR] = mat[c4d.MATERIAL_COLOR_COLOR]

# get object position
P= obj.GetAbsPos()
local_radius = obj.GetRad()

# get global matrix
global_mat = obj.GetMg()

# calculate global radius
R = local_radius * global_mat.v1.GetLength()

# create atom
atom = CreateAtom(P,R[0])

# apply material to atom
textureTag = atom.GetTag(c4d.Ttexture)
if not textureTag:
textureTag = atom.MakeTag(c4d.Ttexture)
textureTag[c4d.TEXTURETAG_MATERIAL] = mat

# insert atom to document
doc.InsertObject(atom)

# remove old object
obj.Remove()


if __name__=='__main__':
main()

创建指定原子组成的平台

此脚本会删除当面工程中所有对象及材质并创建不同原子的材质,之后创建原子平面应用对应的材质,可通过CreatePlat()函数中传入参数XYZlabel参数控制XYZ方向原子数及原子类型,默认是$20\times 2\times 20$的Sn原子平面。

配色参考CPK配色Wiki,原子半径比值参考元素周期表

{ % note warning % } 编写平台C4D 2023C4D R19版本不可用

{ % note warning % } 此脚本会删除当前工程中所有材质及对象不可撤销,请务必在空项目中使用此脚本。

如有Python基础可删除clear()函数使其不再删除所有对象并通过CreateAtom(P,label='H')P参数及label参数在指定坐标创建指定原子。通过第一个for循环中的matlayer对象可以批量调整材质的具体参数。也可通过C4D手动调整。

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105


import c4d

# define atoms radius map
Radius = {
"H": 37, "He": 32, "Li": 134, "Be": 90, "B": 82, "C": 77, "N": 75, "O": 73, "F": 71, "Ne": 69, "Na": 154, "Mg": 130, "Al": 118, "Si": 111, "P": 106, "S": 102, "Cl": 99, "Ar": 97, "K": 196, "Ca": 174, "Sc": 144, "Ti": 136, "V": 125, "Cr": 127, "Mn": 139, "Fe": 125, "Co": 126, "Ni": 121, "Cu": 138, "Zn": 131, "Ga": 126, "Ge": 122, "As": 119, "Se": 116, "Br": 114, "Kr": 110, "Rb": 211, "Sr": 192, "Y": 162, "Zr": 148, "Nb": 137, "Mo": 145, "Tc": 156, "Ru": 126, "Rh": 135, "Pd": 131, "Ag": 153, "Cd": 148, "In": 144, "Sn": 141, "Sb": 138, "Te": 135, "I": 133, "Xe": 130, "Cs": 225, "Ba": 198, "La": 169, "Ce": "nan", "Pr": "nan", "Nd": "nan", "Pm": "nan", "Sm": "nan", "Eu": "nan", "Gd": "nan", "Tb": "nan", "Dy": "nan", "Ho": "nan", "Er": "nan", "Tm": "nan", "Yb": "nan", "Lu": 160, "Hf": 150, "Ta": 138, "W": 146, "Re": 159, "Os": 128, "Ir": 137, "Pt": 128, "Au": 144, "Hg": 149, "Tl": 148, "Pb": 147, "Bi": 146, "Po": "nan", "At": "nan", "Rn": 145, "Fr": "nan", "Ra": "nan", "Ac": "nan", "Th": "nan", "Pa": "nan", "U": "nan", "Np": "nan", "Pu": "nan", "Am": "nan", "Cm": "nan", "Bk": "nan", "Cf": "nan", "Es": "nan", "Fm": "nan", "Md": "nan", "No": "nan", "Lr": "nan", "Rf": "nan", "Db": "nan", "Sg": "nan", "Bh": "nan", "Hs": "nan", "Mt": "nan", "Ds": "nan", "Rg": "nan", "Cn": "nan", "Nh": "nan", "Fl": "nan", "Mc": "nan", "Lv": "nan", "Ts": "nan", "Og": "nan"
}


# define atoms color map
colors = {
"H": [8, 11, 12], "He": [0, 66, 66], "Li": [68, 0, 127], "Be": [126, 157, 0], "B": [90, 0, 0], "C": [81, 89, 94], "N": [0, 19, 181], "O": [206, 0, 0], "F": [92, 151, 11], "Ne": [0, 60, 86], "Na": [75, 0, 148], "Mg": [135, 215, 0], "Al": [76, 50, 50], "Si": [97, 49, 0], "P": [215, 98, 0], "S": [132, 132, 0], "Cl": [44, 190, 0], "Ar": [11, 97, 117], "K": [96, 21, 160], "Ca": [82, 215, 0], "Sc": [25, 28, 30], "Ti": [48, 53, 56], "V": [65, 72, 75], "Cr": [38, 54, 102], "Mn": [71, 37, 114], "Fe": [173, 58, 10], "Co": [110, 0, 17], "Ni": [57, 148, 26], "Cu": [165, 98, 28], "Zn": [58, 60, 107], "Ga": [96, 44, 44], "Ge": [75, 112, 112], "As": [76, 11, 117], "Se": [215, 129, 0], "Br": [134, 19, 19], "Kr": [26, 114, 140], "Rb": [84, 23, 143], "Sr": [40, 215, 0], "Y": [0, 113, 113], "Zr": [15, 100, 100], "Nb": [35, 113, 120], "Mo": [50, 140, 140], "Tc": [35, 126, 126], "Ru": [14, 112, 112], "Rh": [0, 96, 110], "Pd": [0, 77, 103], "Ag": [50, 56, 58], "Cd": [117, 71, 0], "In": [113, 67, 65], "Sn": [81, 89, 92], "Sb": [106, 51, 128], "Te": [176, 94, 0], "I": [117, 0, 117], "Xe": [42, 126, 143], "Cs": [61, 2, 112], "Ba": [0, 166, 0], "La": [0, 91, 138], "Ce": [53, 53, 0], "Pr": [29, 79, 0], "Nd": [5, 79, 0], "Pm": [0, 103, 48], "Sm": [0, 117, 66], "Eu": [0, 149, 104], "Gd": [0, 168, 126], "Tb": [0, 182, 142], "Dy": [0, 194, 155], "Ho": [0, 215, 148], "Er": [0, 192, 89], "Tm": [0, 176, 57], "Yb": [0, 157, 33], "Lu": [0, 138, 14], "Hf": [0, 100, 163], "Ta": [0, 72, 163], "W": [11, 117, 178], "Re": [15, 96, 138], "Os": [15, 75, 119], "Ir": [2, 58, 105], "Pt": [34, 38, 41], "Au": [138, 106, 0], "Hg": [37, 37, 65], "Tl": [134, 58, 52], "Pb": [60, 67, 71], "Bi": [122, 49, 144], "Po": [138, 66, 0], "At": [89, 53, 44], "Rn": [42, 100, 119], "Fr": [42, 0, 75], "Ra": [0, 96, 0], "Ac": [0, 50, 136], "Th": [0, 152, 215], "Pa": [0, 129, 215], "U": [0, 112, 215], "Np": [0, 98, 215], "Pu": [0, 80, 215], "Am": [0, 2, 153], "Cm": [37, 8, 143], "Bk": [66, 8, 153], "Cf": [120, 21, 168], "Es": [145, 10, 176], "Fm": [145, 10, 152], "Md": [145, 0, 134], "No": [155, 0, 105], "Lr": [164, 0, 75], "Rf": [168, 0, 63], "Db": [173, 0, 53], "Sg": [181, 0, 44], "Bh": [187, 0, 33], "Hs": [192, 0, 23], "Mt": [197, 0, 15]
}

# clear all objects in document
def clear():
for obj in doc.GetObjects():
obj.Remove()
for mat in doc.GetMaterials():
mat.Remove()

clear()



# create atoms' material
mats = {}
for atom in colors:
if type(colors[atom]) == list:

for ori_mat in doc.GetMaterials():
if ori_mat.GetName() == atom:
ori_mat.Remove()

mat = c4d.BaseMaterial(c4d.Mmaterial)
color = colors[atom]
color = c4d.Vector(*[c/225 for c in color])


#mat.RemoveReflectionLayerIndex(0)
# add reflect layer
layer = mat.AddReflectionLayer()

# Sets the Layer to GGX mode
mat[layer.GetDataID() + c4d.REFLECTION_LAYER_MAIN_DISTRIBUTION] = c4d.REFLECTION_DISTRIBUTION_GGX

# Defines the Roughness float value
mat[layer.GetDataID() + c4d.REFLECTION_LAYER_MAIN_VALUE_ROUGHNESS] = 0.75

# Defines the layer color value
mat[layer.GetDataID() + c4d.REFLECTION_LAYER_COLOR_COLOR] = color

# use reflect layer
mat[c4d.MATERIAL_USE_REFLECTION] = True

# set material base color
mat[c4d.MATERIAL_COLOR_COLOR] = color

# set material name
mat.SetName(atom)

mats[atom] = mat

# insert materials into document
doc.InsertMaterial(mat)

def CreateAtom(P,label='H'):

atom = c4d.BaseObject(c4d.Osphere)

# set atom radius
atom[c4d.PRIM_SPHERE_RAD] = Radius[label]*0.02

# apply atom's material to atom
textureTag = atom.GetTag(c4d.Ttexture)
if not textureTag:
textureTag = atom.MakeTag(c4d.Ttexture)
textureTag[c4d.TEXTURETAG_MATERIAL] = mats[label]

# set atom postion
atom.SetAbsPos(c4d.Vector(*P))
atom.SetName(label)

# add atom to document
doc.InsertObject(atom)

return atom


def CreatePlat(X=20, Y=2, Z=20, label='Sn'):

plat = c4d.BaseObject(c4d.Onull)

d = Radius[label]*0.04
for x in range(X):
for y in range(Y):
for z in range(Z):
atom = CreateAtom([x*d,y*d,z*d], label=label)
atom.SetName(label+'{}'.format(x+y+z))
atom.InsertUnder(plat)

doc.InsertObject(plat)

CreatePlat()

脚本编写参考官方文档官方案例