2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

BlenderでカーボンナノチューブのCGをつくる

Posted at

概要

BlenderとPythonでいい感じのカーボンナノチューブのCGをつくります.
Pythonの分子動力学シミュレーションライブラリASEにはナノチューブの構造を作ってくれる素晴らしい関数が用意されています.さらに結合の情報を取得することもできるのであとは描画するだけ!

コード

なんとナノチューブはこれだけでできてしまいます.

from ase.build import nanotube
from ase.geometry.analysis import Analysis


def create_cnt(n, m, l):
    cnt = nanotube(n, m, length=l)
    cnt.pbc = [False, False, False]

結合は少し厄介.

    # to retrieve bond information
    ana = Analysis(cnt)
    CCBonds = ana.get_bonds('C', 'C', unique=True)[0]
    center_array = [(cnt.positions[pair[0]] + cnt.positions[pair[1]]) / 2 for pair in CCBonds]
    theta_array = [calc_rotation(cnt.positions[pair[0]], cnt.positions[pair[1]]) for pair in CCBonds]

ここでcalc_rotation関数は,BlendeでC-C結合の円柱を描画するために必要な値を取り出す関数.

def calc_rotation(coord_1, coord_2):
    if coord_1[2] < coord_2[2]:
        coord_1, coord_2 = coord_2, coord_1

    center = (coord_1 + coord_2) / 2
    length = np.linalg.norm(coord_1 - coord_2)
    theta_y = np.arccos((coord_1[2] - center[2]) / (length / 2))

    half = np.array([0, 0, length / 2])
    before = center + half

    angle = np.array([0, theta_y, 0])
    after = rotate_3d((before - center), angle) + center

    theta_loc = np.arctan2(coord_1[1] - center[1], coord_1[0] - center[0])
    theta_after = np.arctan2(after[1] - center[1], after[0] - center[0])
    theta_z = theta_loc - theta_after

    return np.array([0, theta_y, theta_z])


def rotate_3d(coord: np.array, angle: np.array):
    px, py, pz = angle

    Rx = np.array([
        [1, 0, 0],
        [0, np.cos(px), np.sin(px)],
        [0, -np.sin(px), np.cos(px)]
    ])
    Ry = np.array([
        [np.cos(py), 0, -np.sin(py)],
        [0, 1, 0],
        [np.sin(py), 0, np.cos(py)],
    ])
    Rz = np.array([
        [np.cos(pz), np.sin(pz), 0],
        [-np.sin(pz), np.cos(pz), 0],
        [0, 0, 1],
    ])

    return Rz * Ry * Rx @ coord

最後に描画用の関数を整えて・・・

def create_atom(loc, radius, material):
    bpy.ops.mesh.primitive_uv_sphere_add(segments=32, ring_count=16, radius=radius, calc_uvs=True, enter_editmode=False, align='WORLD', location=loc, rotation=(0.0, 0.0, 0.0), scale=(1.0, 1.0, 1.0))
    configurate_object(material)


def create_bond(loc, theta, radius, material):
    bpy.ops.mesh.primitive_cylinder_add(vertices=32, radius=radius, depth=1.46, end_fill_type='NGON', calc_uvs=True, enter_editmode=False, align='WORLD', location=loc, rotation=theta, scale=(1.0, 1.0, 1.0))
    configurate_object(material)
    

def configurate_object(material):
    mesh = bpy.context.object.data
    for f in mesh.polygons:
        f.use_smooth = True
    mesh.materials.append(material)


def get_materials():
    carbon = bpy.data.materials.new('color')
    carbon.diffuse_color = (0.05, 0.05, 0.05, 1)
    carbon.roughness = 1.0
    boron = bpy.data.materials.new('color')
    boron.diffuse_color = (255/255, 0, 240/255, 1)
    boron.roughness = 1.0
    nitrogen = bpy.data.materials.new('color')
    nitrogen.diffuse_color = (0, 10/255, 255/255, 1)
    nitrogen.roughness = 1.0
    bond = bpy.data.materials.new('color')
    bond.diffuse_color = (0.05, 0.05, 0.05, 1)
    bond.roughness = 1.0
    
    return {
        'Carbon': carbon,
        'Boron': boron,
        'Nitrogen': nitrogen,
        'Bond': bond,
    }

create_cnt関数完成!

def create_cnt(n, m, l):
    cnt = nanotube(n, m, length=l)
    cnt.pbc = [False, False, False]
    
    # to retrieve bond information
    ana = Analysis(cnt)
    CCBonds = ana.get_bonds('C', 'C', unique=True)[0]
    center_array = [(cnt.positions[pair[0]] + cnt.positions[pair[1]]) / 2 for pair in CCBonds]
    theta_array = [calc_rotation(cnt.positions[pair[0]], cnt.positions[pair[1]]) for pair in CCBonds]
    bond_array = np.concatenate([center_array, theta_array], axis=1)

    materials = get_materials()
    # draw atoms
    for i, loc in enumerate(cnt.positions):
        create_atom(loc, 0.17, materials['Carbon'])
    # draw bonds
    for i, (loc, theta) in enumerate(zip(center_array, theta_array)):
        create_bond(loc, theta, 0.06, materials['Bond'])

サンプル

6_5_CNT.png
4tubes.png
交互に色を変えてあげるだけで六方晶窒化ホウ素ナノチューブ(BNNT)もできちゃいます!
6_5_CNT_10_7_BNNT.png

#備考
GitHubにてコード公開中.

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?