본문 바로가기

Robot/Robot Program - ROS

블렌더(Blender)를 이용하여 3D 모델 그리기

예전에 저는 스크립트로 CAD를 하는 OpenSCAD를 잠시 봤던 적이 있습니다.[바로가기] 아무래도 기계 엔지니어가 아니다 보니 멋드러진 툴로 현란하게 그리지 못하고 저렇게 코드를 이용한 CAD가 더 흥미롭더라구요^^. 뭐 그리고 한 동안 잊고 있었는데... 최근 파이썬 로보틱스라는 책[바로가기]을 읽다가 블렌더(Blender) 이야기가 나오더라구요. 그리고 기억했죠.. 저도 블렌더를 소개한 적이 있었더라구요^^[바로가기] 뭐 그때는 리눅스에 정말 초..초 간단히 설치하는게 내용이었지만요^^ 이 블렌더에는 Python 스크립트로 CAD 작업을 가능하게 했더라구요... 아~ 그래서 역시 저 답게 또 따라하기를 했죠... 도대체 전 언제쯤 이거 안하고 정말 멋진 내용을 올릴까요?ㅠㅠ.

뭐 아무튼~... Blender의 실행화면입니다.

저 부분을 바꿔서...

Scripting으로 바꾸면 Python 코드를 입력할 수 있는 창이 나타납니다.

그리고 교재에서 제공하는 코드를 붙여넣었죠^^

import bpy

#This function will draw base plate
def Draw_Base_Plate():
    #Added two cubes for cutting sides of base plate
    
    bpy.ops.mesh.primitive_cube_add(radius=0.05, location=(0.175,0,0.09))
    bpy.ops.mesh.primitive_cube_add(radius=0.05, location=(-0.175,0,0.09))

    #Adding base plate
    bpy.ops.mesh.primitive_cylinder_add(radius=0.15,depth=0.005, location=(0,0,0.09))
    
    #Adding booleab difference modifier from first cube
    
    bpy.ops.object.modifier_add(type='BOOLEAN')
    bpy.context.object.modifiers["Boolean"].operation = 'DIFFERENCE'
    bpy.context.object.modifiers["Boolean"].object = bpy.data.objects["Cube"]
    bpy.ops.object.modifier_apply(modifier="Boolean")

    #Adding booleab difference modifier from second cube
    
    bpy.ops.object.modifier_add(type='BOOLEAN')
    bpy.context.object.modifiers["Boolean"].operation = 'DIFFERENCE'
    bpy.context.object.modifiers["Boolean"].object = bpy.data.objects["Cube.001"]
    bpy.ops.object.modifier_apply(modifier="Boolean")

    #Deselect cylinder and delete cubes
    bpy.ops.object.select_pattern(pattern="Cube")
    bpy.ops.object.select_pattern(pattern="Cube.001")
    bpy.data.objects['Cylinder'].select = False
    bpy.ops.object.delete(use_global=False)
    
#This function will draw motors and wheels
def Draw_Motors_Wheels():
    #Create first Wheel
    
    bpy.ops.mesh.primitive_cylinder_add(radius=0.045,depth=0.01, location=(0,0,0.07))
    #Rotate
    bpy.context.object.rotation_euler[1] = 1.5708
    #Transalation
    bpy.context.object.location[0] = 0.135

    #Create second wheel
    bpy.ops.mesh.primitive_cylinder_add(radius=0.045,depth=0.01, location=(0,0,0.07))
    #Rotate
    bpy.context.object.rotation_euler[1] = 1.5708
    #Transalation
    bpy.context.object.location[0] = -0.135

    #Adding motors
    
    bpy.ops.mesh.primitive_cylinder_add(radius=0.018,depth=0.06, location=(0.075,0,0.075))
    bpy.context.object.rotation_euler[1] = 1.5708
    
    bpy.ops.mesh.primitive_cylinder_add(radius=0.018,depth=0.06, location=(-0.075,0,0.075))
    bpy.context.object.rotation_euler[1] = 1.5708
    
    #Adding motor shaft
    bpy.ops.mesh.primitive_cylinder_add(radius=0.006,depth=0.04, location=(0.12,0,0.075))
    bpy.context.object.rotation_euler[1] = 1.5708
    
    bpy.ops.mesh.primitive_cylinder_add(radius=0.006,depth=0.04, location=(-0.12,0,0.075))
    bpy.context.object.rotation_euler[1] = 1.5708
    
    #Addubg Caster Wheel
    
    bpy.ops.mesh.primitive_cylinder_add(radius=0.015,depth=0.05, location=(0,0.125,0.065))
    bpy.ops.mesh.primitive_cylinder_add(radius=0.015,depth=0.05, location=(0,-0.125,0.065))
    
    #Adding Kinect
    
    bpy.ops.mesh.primitive_cube_add(radius=0.04, location=(0,0,0.26))    
    
#Draw middle plate
def Draw_Middle_Plate():
    bpy.ops.mesh.primitive_cylinder_add(radius=0.15,depth=0.005, location=(0,0,0.22))

#Adding top plate
def Draw_Top_Plate():
    bpy.ops.mesh.primitive_cylinder_add(radius=0.15,depth=0.005, location=(0,0,0.37))

#Adding support tubes
def Draw_Support_Tubes():
    #Cylinders
    bpy.ops.mesh.primitive_cylinder_add(radius=0.007,depth=0.30, location=(0.09,0.09,0.23))
    bpy.ops.mesh.primitive_cylinder_add(radius=0.007,depth=0.30, location=(-0.09,0.09,0.23))
    bpy.ops.mesh.primitive_cylinder_add(radius=0.007,depth=0.30, location=(-0.09,-0.09,0.23))
    bpy.ops.mesh.primitive_cylinder_add(radius=0.007,depth=0.30, location=(0.09,-0.09,0.23))


#Main code

if __name__ == "__main__":
    Draw_Base_Plate()
    Draw_Motors_Wheels()
    Draw_Middle_Plate()
    Draw_Top_Plate()
    Draw_Support_Tubes()

그리고 Run Script를 해주면~~~

저렇게 .. 뭔가 멋진 모양이 나타납니다. 우와~~~~ 일단 감탄 5초 한다음에.. 그래도 튜토리얼인데 살짝 들여다 볼까요^^ 아 그전에 블렌더의 Python API에 대한 문서[바로가기]를 가보시면 뭐 다있는 내용입니다.

#Draw middle plate
def Draw_Middle_Plate():
    bpy.ops.mesh.primitive_cylinder_add(radius=0.15,depth=0.005, location=(0,0,0.22))

#Adding top plate
def Draw_Top_Plate():
    bpy.ops.mesh.primitive_cylinder_add(radius=0.15,depth=0.005, location=(0,0,0.37))

심플합니다. 중간과 윗판을 그린것인데... 딱 봐도 뭔지 알 정도로 cylinder로 구현되어 있습니다. 반지름(radius)과 길이(depth)를 지정하고 위치를 잡아주면 됩니다.^^.

#Adding support tubes
def Draw_Support_Tubes():
    #Cylinders
    bpy.ops.mesh.primitive_cylinder_add(radius=0.007,depth=0.30, location=(0.09,0.09,0.23))
    bpy.ops.mesh.primitive_cylinder_add(radius=0.007,depth=0.30, location=(-0.09,0.09,0.23))
    bpy.ops.mesh.primitive_cylinder_add(radius=0.007,depth=0.30, location=(-0.09,-0.09,0.23))
    bpy.ops.mesh.primitive_cylinder_add(radius=0.007,depth=0.30, location=(0.09,-0.09,0.23))

저건 기둥들을 잡아 준 것인데 역시 cylinder로 그렸습니다.^^.

아~~ 저부분만 따로 그린 코드는

#This function will draw motors and wheels
def Draw_Motors_Wheels():
    #Create first Wheel
    
    bpy.ops.mesh.primitive_cylinder_add(radius=0.045,depth=0.01, location=(0,0,0.07))
    #Rotate
    bpy.context.object.rotation_euler[1] = 1.5708
    #Transalation
    bpy.context.object.location[0] = 0.135

    #Create second wheel
    bpy.ops.mesh.primitive_cylinder_add(radius=0.045,depth=0.01, location=(0,0,0.07))
    #Rotate
    bpy.context.object.rotation_euler[1] = 1.5708
    #Transalation
    bpy.context.object.location[0] = -0.135

    #Adding motors
    bpy.ops.mesh.primitive_cylinder_add(radius=0.018,depth=0.06, location=(0.075,0,0.075))
    bpy.context.object.rotation_euler[1] = 1.5708
    
    bpy.ops.mesh.primitive_cylinder_add(radius=0.018,depth=0.06, location=(-0.075,0,0.075))
    bpy.context.object.rotation_euler[1] = 1.5708
    
    #Adding motor shaft
    bpy.ops.mesh.primitive_cylinder_add(radius=0.006,depth=0.04, location=(0.12,0,0.075))
    bpy.context.object.rotation_euler[1] = 1.5708
    
    bpy.ops.mesh.primitive_cylinder_add(radius=0.006,depth=0.04, location=(-0.12,0,0.075))
    bpy.context.object.rotation_euler[1] = 1.5708
    
    #Addubg Caster Wheel
    bpy.ops.mesh.primitive_cylinder_add(radius=0.015,depth=0.05, location=(0,0.125,0.065))
    bpy.ops.mesh.primitive_cylinder_add(radius=0.015,depth=0.05, location=(0,-0.125,0.065))
    
    #Adding Kinect
    bpy.ops.mesh.primitive_cube_add(radius=0.04, location=(0,0,0.26))    

좀 길긴 하지만, 두 바퀴는 cylinder로 그린다음 y축 중심으로 90도 회전하고, 위치를 다시 잡아준 것입니다. 그리고, 모터와 앞 뒤 바퀴용인 캐스터를 그려넣은 것이죠^^

이제 base판인데요.. 이 판은 꽤 재미있게 그립니다. 먼저 저런 cube를 놓고...

원판을 cylinder로 그린다음... 원판에서 cube를 빼버린 겁니다.^^

#This function will draw base plate
def Draw_Base_Plate():
    #Added two cubes for cutting sides of base plate
    
    bpy.ops.mesh.primitive_cube_add(radius=0.05, location=(0.175,0,0.09))
    bpy.ops.mesh.primitive_cube_add(radius=0.05, location=(-0.175,0,0.09))

    #Adding base plate
    bpy.ops.mesh.primitive_cylinder_add(radius=0.15,depth=0.005, location=(0,0,0.09))
    
    #Adding booleab difference modifier from first cube
    
    bpy.ops.object.modifier_add(type='BOOLEAN')
    bpy.context.object.modifiers["Boolean"].operation = 'DIFFERENCE'
    bpy.context.object.modifiers["Boolean"].object = bpy.data.objects["Cube"]
    bpy.ops.object.modifier_apply(modifier="Boolean")

    #Adding booleab difference modifier from second cube
    
    bpy.ops.object.modifier_add(type='BOOLEAN')
    bpy.context.object.modifiers["Boolean"].operation = 'DIFFERENCE'
    bpy.context.object.modifiers["Boolean"].object = bpy.data.objects["Cube.001"]
    bpy.ops.object.modifier_apply(modifier="Boolean")

    #Deselect cylinder and delete cubes
    bpy.ops.object.select_pattern(pattern="Cube")
    bpy.ops.object.select_pattern(pattern="Cube.001")
    bpy.data.objects['Cylinder'].select = False
    bpy.ops.object.delete(use_global=False)

그러면...

이 그림이 되는 거죠^^

이제 다 그렸네요^^

이걸 STL파일로 export 시키면 저렇게 이쁘당한 모양을 얻을 수 있습니다. 아 3D 데이터를 바로 확인하기에는 별도로 Mesh Lab[바로가기]도 괜찮다고 하네요

괜찮네요~~~ 이제 도면 작업도 간단한 거라면 좀 더 편하게 할 수 있을듯 하네요^^

반응형