오늘은 모델링 작업을 훨씬 효율적이고 체계적으로 만들어주는 아주 중요한 개념인 모듈(module)에 대해 배워보겠습니다.
부품을 조립하듯 모델링하기
복잡한 물체를 만들 때를 한번 상상해볼까요? 예를 들어, 책상을 만든다면 다리 네 개와 상판 하나를 따로 만든 뒤, 마지막에 조립하는 것이 편리할 겁니다. 다리 네 개는 모양이 모두 같으니, 하나만 잘 설계해두면 나머지는 똑같이 복사해서 사용하면 되겠죠.
OpenSCAD의 module이 바로 이런 역할을 합니다. module은 우리가 만들고 싶은 '부품'의 설계도라고 생각하시면 됩니다. 한번 설계도를 만들어두면, 필요할 때마다 그 설계도의 이름만 불러서 몇 개든지 똑같은 부품을 만들어 배치할 수 있습니다.
마치 프로그래밍 언어에서 함수를 정의하고 필요할 때마다 호출해서 사용하는 것과 원리가 똑같습니다.
module을 정의하는 방법은 다음과 같습니다.
module 부품명() {
// 여기에 부품의 모양을 만드는 코드를 넣습니다.
}
만약 부품의 크기나 모양을 조금씩 바꾸고 싶다면, 매개변수(parameter)를 추가할 수도 있습니다.
module 부품명(매개변수1, 매개변수2) {
// 매개변수를 사용하여 부품의 모양을 조절하는 코드를 넣습니다.
}
예제: 컴퓨터 키보드의 키캡 만들기
가장 좋은 예는 바로 여러분이 지금 사용하고 계실지도 모르는 컴퓨터 키보드입니다. 키보드에는 모양이 거의 똑같은 수많은 키캡들이 배열되어 있죠.
이 키캡 하나를 module로 정의해두면 어떨까요?
keycap이라는 이름의 모듈을 만들어두고, 키보드 판 위 원하는 위치로 이동(translate)한 뒤 keycap();이라고 호출만 하면 키캡이 하나씩 뚝딱 만들어질 겁니다.
아주 간단하게 코드로 표현하면 이런 모습이겠죠.
// 먼저 keycap 이라는 부품 설계도를 정의합니다.
module keycap() {
// 여기에는 키캡의 복잡한 모양을 만드는 코드가 들어갑니다.
}
// 이제 설계도를 사용해 키캡을 만듭니다.
// 첫 번째 키캡은 원점에 만듭니다.
translate([0, 0, 0]) keycap();
// 두 번째 키캡은 x축으로 1만큼 이동해서 만듭니다.
translate([1, 0, 0]) keycap();
// 세 번째 키캡은 x축으로 2만큼 이동해서 만듭니다.
translate([2, 0, 0]) keycap();
이처럼, 단 한 번의 정의로 수십, 수백 개의 키캡을 손쉽게 배열할 수 있게 되는 것입니다. 이것이 바로 module의 강력함입니다.
keycap 모듈 자세히 살펴보기
자, 그럼 이제부터 우리가 만들 keycap 모듈의 전체 코드를 차근차근 분석해보겠습니다.
우리가 만들 키캡의 모양을 머릿속으로 먼저 그려볼까요? 키캡은 속이 비어있는 작은 상자 모양입니다. 그런데 그냥 네모난 상자가 아니라, 바닥은 넓고 위로 갈수록 약간 좁아지는 사다리꼴 형태를 하고 있죠. 그리고 손가락이 닿는 윗면은 편안한 타건감을 위해 살짝 오목하게 파여 있습니다.
이 모양을 만들기 위해, 저희는 '차집합'을 의미하는 difference() 명령을 사용할 겁니다. 이 명령은 마치 조각칼과 같습니다. 첫 번째로 놓인 물체에서, 그 뒤에 오는 물체들의 모양을 전부 파내는 역할을 하죠.
우리의 전략
- 먼저, 속이 꽉 찬 사다리꼴 모양의 덩어리를 하나 만듭니다.
- 그 다음, 그 안쪽을 파내기 위해 약간 더 작은 사다리꼴 덩어리로 속을 빼냅니다.
- 마지막으로, 윗면을 오목하게 깎아내기 위해 아주 커다란 구(sphere)의 일부를 이용해 윗부분을 잘라냅니다.
이제 이 과정을 코드로 살펴보겠습니다.
모듈 정의 및 매개변수
module keycap(
bottom_dims = [18, 18], // 표준 1U 키캡의 바닥 크기 (mm)
top_dims = [13, 13], // 일반적인 윗면 크기
height = 10,
wall_thickness = 1.5,
dish_radius = 50, // 윗면의 둥근 정도
dish_depth = 1
) {
먼저 모듈의 이름과 함께, 괄호 안에 여러 매개변수들을 정의했습니다. 이 매개변수들 덕분에 우리는 키캡의 바닥 크기, 높이, 두께, 윗면의 파인 정도 등을 자유롭게 조절할 수 있습니다. 예를 들어 bottom_dims는 키캡 바닥의 가로, 세로 크기를, wall_thickness는 키캡 벽의 두께를 의미합니다.
1. 키캡의 기본 뼈대 만들기
difference() {
// 1. 키캡의 전체적인 외부 형태 (속이 꽉 찬 사다리꼴)
linear_extrude(height = height, scale = [top_dims[0]/bottom_dims[0], top_dims[1]/bottom_dims[1]]) {
square(bottom_dims, center = true);
}
difference()를 시작합니다. 이 중괄호 안에 들어가는 첫 번째 물체가 기본 재료가 되고, 나머지는 파내는 조각칼이 됩니다. 이 부분이 바로 첫 번째 재료, 즉 속이 꽉 찬 사다리꼴 덩어리입니다. square 명령으로 바닥면 사각형을 만들고, linear_extrude 명령으로 height만큼 위로 쌓아 올립니다. 이때 scale 옵션을 이용해 위로 올라가면서 점점 작아지도록 만들어 사다리꼴 형태를 구현했습니다. (이 linear_extrude에 대해서는 다음 강좌에서 더 자세히 다룰 예정이니, 지금은 '사각형을 위로 잡아늘여 입체를 만든다' 정도로만 이해하셔도 좋습니다.)
2. 키캡의 속 파내기
// 2. 키캡의 속을 파내기 위한 내부 형태
translate([0, 0, -1]) {
linear_extrude(height = height + 2, scale = [
(top_dims[0] - wall_thickness*2) / (bottom_dims[0] - wall_thickness*2),
(top_dims[1] - wall_thickness*2) / (bottom_dims[1] - wall_thickness*2)
]) {
square([bottom_dims[0] - wall_thickness*2, bottom_dims[1] - wall_thickness*2], center = true);
}
}
두 번째로, 속을 파낼 조각칼입니다. 이 역시 사다리꼴 모양이지만, 원래 덩어리보다 wall_thickness만큼 안쪽으로 작게 만들었습니다. 그리고 translate로 아래로 조금 내리고, 높이를 더 높게 만들어서, 원래 덩어리의 바닥과 윗면을 모두 확실하게 관통하여 파낼 수 있도록 했습니다.
3. 윗면을 오목하게 깎기
// 3. 윗면을 둥글게 파내기 위한 거대한 구(sphere)
translate([0, 0, height - dish_depth + dish_radius]) {
sphere(r = dish_radius);
}
}
}
마지막 조각칼입니다. 이것은 윗면의 오목한 부분을 만들기 위한 것입니다. dish_radius라는 아주 큰 반지름을 가진 구를 하나 만듭니다. 그리고 translate를 이용해 이 거대한 구의 중심을 키캡보다 훨씬 높은 곳에 위치시킵니다. 이렇게 하면, 구의 아랫부분만이 살짝 키캡의 윗면과 겹치게 되고, difference() 명령이 이 겹치는 부분만큼을 깔끔하게 잘라내어 우리가 원하는 오목한 모양을 만들어줍니다.