본문으로 건너뛰기
3D 아틀리에
로우크롭 트랙터 (파몰 H형) 3D 모형

끌어서 회전, 휠·두 손가락으로 확대

이 모형에 대하여

파몰 H는 미국 인터내셔널 하베스터가 1939년부터 1953년까지 생산한 중형 로우크롭 트랙터다. 산업 디자이너 레이먼드 로위가 다듬은 둥근 라디에이터 덮개와 붉은 도장으로 이 시기 북미 농장의 대표적인 모습이 되었다.

로우크롭 트랙터는 옥수수·목화처럼 줄지어 심은 작물 사이를 지나가도록 만들어졌다. 앞바퀴 두 개를 한가운데로 모은 세발자전거형 앞차축이 이랑 하나 사이를 달리고, 키 큰 뒷바퀴가 양쪽 이랑을 넘는다. 엔진 옆면은 덮개 없이 드러나 있고, 긴 조향축이 보닛 위를 지나 앞 받침대의 기어함으로 이어진다.

이 모델은 이러한 H형의 특징, 곧 갈매기 무늬 러그가 박힌 큰 뒷타이어, 좁은 보닛 위로 솟은 배기관과 흡기 프리클리너, 둥근 펜더와 팬 모양 좌석, 오른쪽의 벨트 풀리를 실제 크기로 재현했다.

만든 방법

뒷타이어는 단면 프로필을 회전체로 돌린 뒤 비스듬한 상자 46개를 bmesh 로 붙여 갈매기 무늬 러그를 만들었고, 좌우 바퀴는 같은 메시를 공유한다. 보닛과 라디에이터 덮개는 위 모서리가 둥근 단면을 앞뒤로 돌출했고, 펜더는 뒷차축을 중심으로 한 원호 띠에 두께를 주었다. 조향 기둥과 핸들은 두 점 사이의 방향 벡터로 기울였다. 엔진은 블록·헤드·매니폴드·발전기·마그네토 등 큰 부품 위주로 단순화했고, 배선과 연결 링크, 유압 장치는 생략했다. 보닛 옆 글자는 3D 텍스트로 넣었다.

build.py

이 파일 하나를 Blender 에서 실행하면 위의 모형이 만들어집니다. 390줄.

# 로우크롭 트랙터 (1939~1953 파몰 H형) — Blender Python 코드만으로 만든 모델.
# 큰 뒷바퀴와 앞쪽에 모인 쌍바퀴(세발자전거형), 좁고 긴 보닛, 보닛 위로 솟은 배기관·흡기관,
# 보닛 위를 지나 앞 받침대까지 이어지는 긴 조향축이 이 형식을 알아보게 하는 특징이다.
# 뒷타이어는 회전체(lathe) 단면에 갈매기(쉐브론) 러그 46개를 bmesh 로 붙여 만들고,
# 보닛·라디에이터 덮개는 둥근 단면 돌출, 펜더는 원호 띠에 두께를 주어 만들었다.
# 같은 바퀴·러그·볼트는 메시를 공유하는 복제로 배치했다. 단위 m, 앞쪽이 -Y.
from atelier import *
SHOT = {"azimuth": -40, "elevation": 13, "lens": 55, "light": "studio", "background": "#26303a"}
# ---------------------------------------------------------------- 재질
RED = mat('IH_Red_Paint', '#a51f18', 0.38, 0.0, coat=0.4)
RUBBER = mat('Tire_Rubber', '#262626', 0.85, 0.0)
IRON = mat('Cast_Iron_Dark', '#3b3836', 0.6, 0.5)
STEEL = mat('Worn_Steel', '#8b8d8f', 0.35, 0.9)
CHROME = mat('Chrome', '#d6d8da', 0.12, 1.0)
EXHAUST = mat('Exhaust_Rust', '#4a3426', 0.75, 0.3)
BLACK = mat('Black_Enamel', '#1f1f21', 0.4, 0.0)
CREAM = mat('Cream_Lettering', '#e6dcc2', 0.45, 0.0)
LENS = mat('Lamp_Lens', '#efe6c8', 0.08, 0.0, emit='#fff2c8', emit_strength=0.6)
GLASSB = glass('Precleaner_Glass', '#c9d6d0', 0.08)
# ---------------------------------------------------------------- 치수
RA_Y, RA_Z = 0.95, 0.775 # 뒷차축 (y, z)
REAR_X = 0.86 # 뒷바퀴 중심 x
FA_Y, FA_Z = -1.33, 0.345 # 앞차축
FRONT_X = 0.165 # 앞 쌍바퀴 간격 절반
def obj_from_bm(name, bm, material, loc=(0, 0, 0), rot=(0, 0, 0), shade=True):
me = bpy.data.meshes.new(name)
bm.to_mesh(me)
bm.free()
ob = bpy.data.objects.new(name, me)
link(ob)
ob.location = Vector(loc)
ob.rotation_euler = Euler(rot)
assign(ob, material)
if shade:
smooth(ob)
return ob
def bm_lathe(bm, profile, seg, closed=False):
"""profile=[(r, z)] 를 Z축 회전 — 기존 bm 에 추가."""
rings = []
for i in range(seg):
a = 2 * math.pi * i / seg
나머지 342줄 펼치기
rings.append([bm.verts.new((r * math.cos(a), r * math.sin(a), z)) for r, z in profile])
n = len(profile) - (0 if closed else 1)
for i in range(seg):
r0, r1 = rings[i], rings[(i + 1) % seg]
for j in range(n):
k = (j + 1) % len(profile)
bm.faces.new((r0[j], r1[j], r1[k], r0[k]))
def rod(name, p0, p1, r, material, seg=16):
"""두 점을 잇는 원기둥."""
p0, p1 = Vector(p0), Vector(p1)
d = p1 - p0
ob = cylinder(name, r=r, h=d.length, loc=p0, material=material, seg=seg)
ob.rotation_euler = d.to_track_quat('Z', 'Y').to_euler()
smooth(ob)
return ob
def rounded_profile(w, z0, z1, rc, n=8):
"""아래가 평평하고 위 모서리가 둥근 단면 (x, z)."""
hw = w / 2
pts = [(-hw, z0), (hw, z0), (hw, z1 - rc)]
for i in range(1, n):
a = math.pi / 2 * i / n
pts.append((hw - rc + rc * math.cos(a), z1 - rc + rc * math.sin(a)))
for i in range(0, n + 1):
a = math.pi / 2 + math.pi / 2 * i / n
pts.append((-hw + rc + rc * math.cos(a), z1 - rc + rc * math.sin(a)))
return pts
# ---------------------------------------------------------------- 뒷바퀴
def rear_tire():
bm = bmesh.new()
prof = [(0.495, 0.118), (0.56, 0.138), (0.64, 0.146), (0.695, 0.132), (0.722, 0.095),
(0.732, 0.04), (0.734, 0.0), (0.732, -0.04), (0.722, -0.095), (0.695, -0.132),
(0.64, -0.146), (0.56, -0.138), (0.495, -0.118)]
bm_lathe(bm, prof, 120)
N = 23
for side in (1, -1):
for i in range(N):
th = 2 * math.pi * i / N + (math.pi / N if side < 0 else 0.0)
m = (Matrix.Rotation(th, 4, 'Z') @ Matrix.Translation((0.738, 0, side * 0.066))
@ Matrix.Rotation(math.radians(38) * side, 4, 'X')
@ Matrix.Diagonal((0.075, 0.05, 0.165, 1.0)))
res = bmesh.ops.create_cube(bm, size=1.0, matrix=m)
bmesh.ops.recalc_face_normals(bm, faces=bm.faces)
return obj_from_bm('Rear_Tire_11-38', bm, RUBBER)
def rear_rim():
bm = bmesh.new()
prof = [(0.525, 0.14), (0.50, 0.125), (0.488, 0.10), (0.488, -0.10), (0.50, -0.125), (0.525, -0.14),
(0.515, -0.145), (0.478, -0.11), (0.478, 0.11), (0.515, 0.145)]
bm_lathe(bm, prof, 96, closed=True)
ob = obj_from_bm('Rear_Rim', bm, RED)
# 오목한 휠 디스크
disc = lathe('Rear_Wheel_Disc', [(0.48, 0.03), (0.40, 0.05), (0.26, 0.075), (0.12, 0.075),
(0.12, 0.06), (0.26, 0.06), (0.40, 0.035), (0.48, 0.015)], material=RED, seg=64)
hub = cylinder('Rear_Hub', r=0.13, h=0.16, loc=(0, 0, 0.02), material=RED, seg=32)
cap = cylinder('Rear_Axle_End', r=0.075, h=0.08, loc=(0, 0, 0.18), material=STEEL, seg=24)
parts = [ob, disc, hub, cap]
bolt = cylinder('Rear_Wheel_Bolt', r=0.016, h=0.03, loc=(0.2, 0, 0.07), material=STEEL, seg=8)
parts.append(bolt)
for i in range(1, 8):
a = 2 * math.pi * i / 8
parts.append(duplicate(bolt, loc=(0.2 * math.cos(a), 0.2 * math.sin(a), 0.07), linked=False))
# 디스크 보강 리브
for i in range(6):
a = 2 * math.pi * (i + 0.5) / 6
rb = box('Rear_Disc_Rib', (0.24, 0.035, 0.03), loc=(0.32 * math.cos(a), 0.32 * math.sin(a), 0.055),
rot=(0, math.radians(-12), a), material=RED)
parts.append(rb)
return join(parts, 'Rear_Wheel_Rim')
tire = rear_tire()
rim = rear_rim()
for sx, nm in ((1, 'Right'), (-1, 'Left')):
t = tire if sx == 1 else duplicate(tire, name='Rear_Tire_Left')
t.location = (sx * REAR_X, RA_Y, RA_Z)
t.rotation_euler = (0, math.pi / 2, 0)
if sx == 1:
t.name = 'Rear_Tire_Right'
r = rim if sx == 1 else duplicate(rim, name='Rear_Wheel_Left')
r.location = (sx * REAR_X, RA_Y, RA_Z)
r.rotation_euler = (0, sx * math.pi / 2, 0)
if sx == 1:
r.name = 'Rear_Wheel_Right'
# ---------------------------------------------------------------- 앞 쌍바퀴
def front_tire():
bm = bmesh.new()
prof = [(0.215, 0.055), (0.25, 0.068), (0.29, 0.07), (0.318, 0.06), (0.333, 0.045), (0.343, 0.036),
(0.345, 0.026), (0.336, 0.018), (0.336, 0.010), (0.345, 0.004), (0.345, -0.004), (0.336, -0.010),
(0.336, -0.018), (0.345, -0.026), (0.343, -0.036), (0.333, -0.045), (0.318, -0.06), (0.29, -0.07),
(0.25, -0.068), (0.215, -0.055)]
bm_lathe(bm, prof, 72)
return obj_from_bm('Front_Tire_5.50-16', bm, RUBBER)
def front_rim():
rimb = lathe('Front_Rim', [(0.225, 0.062), (0.205, 0.05), (0.205, -0.05), (0.225, -0.062),
(0.215, -0.066), (0.196, -0.05), (0.196, 0.05), (0.215, 0.066)], material=RED, seg=48)
disc = lathe('Front_Wheel_Disc', [(0.2, 0.0), (0.12, 0.03), (0.07, 0.03), (0.07, 0.018),
(0.12, 0.018), (0.2, -0.012)], material=RED, seg=40)
hub = lathe('Front_Hub_Cap', [(0.07, 0.0), (0.07, 0.06), (0.05, 0.085), (0.0, 0.09)], material=RED, seg=32)
return join([rimb, disc, hub], 'Front_Wheel_Rim')
ft = front_tire()
fr = front_rim()
for sx in (1, -1):
nm = 'Right' if sx == 1 else 'Left'
t = ft if sx == 1 else duplicate(ft)
t.name = f'Front_Tire_{nm}'
t.location = (sx * FRONT_X, FA_Y, FA_Z)
t.rotation_euler = (0, math.pi / 2, 0)
w = fr if sx == 1 else duplicate(fr)
w.name = f'Front_Wheel_{nm}'
w.location = (sx * FRONT_X, FA_Y, FA_Z)
w.rotation_euler = (0, sx * math.pi / 2, 0)
# 앞 받침대(페데스털)와 짧은 앞차축
rod('Front_Axle', (-0.13, FA_Y, FA_Z), (0.13, FA_Y, FA_Z), 0.04, IRON)
fork = box('Front_Fork_Yoke', (0.2, 0.13, 0.16), loc=(0, FA_Y, FA_Z + 0.03), material=RED, base=True)
bevel(fork, 0.02, 2)
rod('Front_Steering_Spindle', (0, FA_Y + 0.02, FA_Z + 0.17), (0, -1.27, 0.76), 0.062, RED)
ped = extrude_profile('Front_Bolster_Pedestal', [(-0.08, 0.50), (0.08, 0.50), (0.17, 0.74), (-0.17, 0.74)], 0.2,
loc=(0, -1.28, 0), material=RED)
bevel(ped, 0.02, 2)
# ---------------------------------------------------------------- 엔진·차대
rail_l = box('Frame_Rail_Left', (0.07, 1.62, 0.13), loc=(-0.19, -0.42, 0.57), material=RED, base=True)
rail_r = duplicate(rail_l, loc=(0.19, -0.42, 0.57), name='Frame_Rail_Right')
bolster = box('Front_Bolster', (0.46, 0.2, 0.12), loc=(0, -1.25, 0.62), material=RED, base=True)
bevel(bolster, 0.015, 2)
pan = box('Engine_Oil_Pan', (0.26, 0.95, 0.12), loc=(0, -0.5, 0.56), material=RED, base=True)
bevel(pan, 0.03, 2)
block = box('Engine_Block_C152', (0.27, 1.02, 0.42), loc=(0, -0.53, 0.68), material=RED, base=True)
bevel(block, 0.02, 2)
head = box('Cylinder_Head', (0.25, 0.98, 0.07), loc=(0, -0.53, 1.10), material=RED, base=True)
bevel(head, 0.012, 2)
# 측면 상세: 흡배기 매니폴드, 기화기, 마그네토, 시동모터
man = rod('Exhaust_Manifold', (0.17, -0.95, 1.0), (0.17, -0.1, 1.0), 0.04, EXHAUST)
for i, y in enumerate((-0.86, -0.64, -0.42, -0.2)):
rod('Manifold_Port', (0.14, y, 1.0), (0.18, y, 1.0), 0.032, EXHAUST, seg=12)
carb = box('Carburetor', (0.09, 0.12, 0.14), loc=(0.22, -0.52, 0.86), material=IRON, base=True)
bevel(carb, 0.01, 1)
rod('Intake_Pipe', (0.17, -0.52, 0.99), (0.24, -0.52, 0.99), 0.03, IRON)
mag = rod('Magneto', (-0.17, -0.70, 0.88), (-0.26, -0.70, 0.88), 0.06, BLACK, seg=20)
rod('Starter_Motor', (-0.17, -0.02, 0.78), (-0.17, -0.32, 0.78), 0.06, BLACK, seg=20)
oilf = cylinder('Oil_Filter', r=0.055, h=0.17, loc=(-0.2, -0.35, 0.84), material=RED, seg=20)
for i in range(4):
y = -0.86 + i * 0.22
rod(f'Spark_Plug_Wire_{i + 1}', (-0.13, y, 1.12), (-0.2, -0.70, 0.94), 0.007, BLACK, seg=6)
cylinder(f'Spark_Plug_{i + 1}', r=0.012, h=0.05, loc=(-0.13, y, 1.08), material=CREAM, seg=8)
# 블록 측면: 냉각수 플러그, 밸브 덮개(왼쪽), 냉각 호스, 팬
for i in range(3):
for sx in (1, -1):
cylinder('Core_Plug', r=0.025, h=0.012, loc=(sx * 0.135, -0.86 + i * 0.3, 0.9),
rot=(0, sx * math.pi / 2, 0), material=STEEL, seg=12, base=False)
vc = box('Valve_Chamber_Cover', (0.02, 0.62, 0.12), loc=(-0.14, -0.5, 0.94), material=RED)
bevel(vc, 0.006, 1)
for i in range(4):
cylinder('Cover_Bolt', r=0.01, h=0.012, loc=(-0.152, -0.74 + i * 0.16, 0.94),
rot=(0, -math.pi / 2, 0), material=STEEL, seg=8, base=False)
rod('Upper_Radiator_Hose', (0, -1.04, 1.12), (0, -1.16, 1.18), 0.035, BLACK, seg=12)
lathe('Water_Outlet', [(0.0, 0.0), (0.05, 0.0), (0.05, 0.08), (0.0, 0.08)], loc=(0, -0.98, 1.10),
rot=(math.pi / 2, 0, 0), material=RED, seg=16)
rod('Lower_Radiator_Hose', (0.1, -1.04, 0.76), (0.1, -1.16, 0.76), 0.03, BLACK, seg=12)
rod('Fan_Shaft', (0, -1.04, 0.96), (0, -1.13, 0.96), 0.03, IRON, seg=12)
for i in range(4):
a = math.pi / 4 + i * math.pi / 2
box('Fan_Blade', (0.18, 0.012, 0.07), loc=(0.11 * math.cos(a), -1.115, 0.96 + 0.11 * math.sin(a)),
rot=(math.radians(25), a, 0), material=IRON)
cylinder('Governor_Housing', r=0.06, h=0.08, loc=(0.0, -1.05, 0.70), rot=(math.pi / 2, 0, 0), material=RED,
seg=20, base=False)
rod('Generator', (0.2, -0.98, 0.84), (0.2, -0.72, 0.84), 0.065, BLACK, seg=20)
rod('Generator_Pulley', (0.2, -1.02, 0.84), (0.2, -0.98, 0.84), 0.045, IRON, seg=16)
rod('Fuel_Line', (0.06, 0.05, 1.11), (0.22, -0.46, 0.99), 0.008, STEEL, seg=6)
# 라디에이터
rad = box('Radiator_Core', (0.48, 0.12, 0.62), loc=(0, -1.2, 0.72), material=IRON, base=True)
# 클러치 하우징 (엔진 → 변속기)
lathe('Clutch_Housing', [(0.0, 0.0), (0.2, 0.0), (0.26, 0.2), (0.0, 0.2)], loc=(0, -0.05, 0.86),
rot=(-math.pi / 2, 0, 0), material=RED, seg=40)
# 벨트 풀리 (오른쪽)
lathe('Belt_Pulley', [(0.0, 0.0), (0.15, 0.0), (0.16, 0.01), (0.16, 0.15), (0.15, 0.16), (0.0, 0.16)],
loc=(0.27, 0.07, 0.86), rot=(0, math.pi / 2, 0), material=RED, seg=48)
rod('Pulley_Shaft', (0.18, 0.07, 0.86), (0.28, 0.07, 0.86), 0.05, IRON)
# 변속기·차동장치 케이스
trans = box('Transmission_Case', (0.58, 0.78, 0.56), loc=(0, 0.6, 0.52), material=RED, base=True)
bevel(trans, 0.05, 3)
for sx in (1, -1):
rod('Rear_Axle_Housing', (sx * 0.28, RA_Y, RA_Z), (sx * 0.74, RA_Y, RA_Z), 0.09, RED, seg=24)
rod('Final_Drive_Flange', (sx * 0.28, RA_Y, RA_Z), (sx * 0.33, RA_Y, RA_Z), 0.15, RED, seg=32)
db = box('Brake_Housing', (0.1, 0.3, 0.3), loc=(sx * 0.34, 0.55, 0.78), material=RED)
bevel(db, 0.04, 3)
# 발판
fb = box('Foot_Platform', (0.34, 0.5, 0.025), loc=(sx * 0.48, 0.42, 0.66), material=STEEL, base=True)
for k in range(5):
box('Platform_Tread_Bar', (0.3, 0.02, 0.012), loc=(sx * 0.48, 0.22 + k * 0.1, 0.684),
material=STEEL, base=True)
rod('Platform_Bracket', (sx * 0.3, 0.6, 0.67), (sx * 0.3, 0.6, 0.6), 0.02, IRON)
for i, sx in enumerate((0.07, -0.07)):
rod('Brake_Pedal_Arm', (0.3 + 0.03 * i, 0.5, 0.78), (0.4 + 0.03 * i, 0.32, 0.86), 0.015, IRON, seg=8)
box('Brake_Pedal_Pad', (0.07, 0.04, 0.09), loc=(0.4 + 0.03 * i, 0.32, 0.86), material=IRON)
rod('Clutch_Pedal_Arm', (-0.3, 0.45, 0.78), (-0.42, 0.3, 0.86), 0.015, IRON, seg=8)
box('Clutch_Pedal_Pad', (0.07, 0.04, 0.09), loc=(-0.42, 0.3, 0.86), material=IRON)
# 견인봉(드로바)
db = box('Drawbar', (0.62, 0.08, 0.04), loc=(0, 1.32, 0.42), material=IRON)
bevel(db, 0.01, 1)
for sx in (1, -1):
rod('Drawbar_Strut', (sx * 0.28, 0.85, 0.55), (sx * 0.28, 1.32, 0.43), 0.025, IRON, seg=10)
for k in range(5):
cylinder('Drawbar_Hole_Pin', r=0.012, h=0.05, loc=(-0.2 + k * 0.1, 1.32, 0.415), material=STEEL, seg=8)
rc = box('Rear_Cover_Plate', (0.44, 0.02, 0.4), loc=(0, 0.995, 0.58), material=RED, base=True)
bevel(rc, 0.008, 1)
for i in range(6):
for zz in (0.62, 0.95):
cylinder('Rear_Cover_Bolt', r=0.012, h=0.015, loc=(-0.19 + i * 0.076, 1.005, zz),
rot=(-math.pi / 2, 0, 0), material=STEEL, seg=8, base=False)
box('PTO_Shield', (0.18, 0.12, 0.1), loc=(0, 1.02, 0.6), material=RED)
rod('PTO_Shaft', (0, 0.98, 0.6), (0, 1.12, 0.6), 0.025, STEEL, seg=12)
# ---------------------------------------------------------------- 보닛·라디에이터 덮개
HOOD_Y0, HOOD_Y1 = -1.16, 0.30
hood = extrude_profile('Hood', rounded_profile(0.5, 1.12, 1.42, 0.16), HOOD_Y1 - HOOD_Y0,
loc=(0, (HOOD_Y0 + HOOD_Y1) / 2, 0), material=RED)
smooth(hood)
bevel(hood, 0.01, 2, angle=50)
shell = extrude_profile('Radiator_Shell', rounded_profile(0.58, 0.72, 1.45, 0.2, 10), 0.16,
loc=(0, -1.25, 0), material=RED)
smooth(shell)
bevel(shell, 0.012, 2, angle=50)
# 그릴 — 짙은 바탕판 위 가로 살
box('Grille_Backing', (0.46, 0.012, 0.6), loc=(0, -1.334, 0.79), material=IRON, base=True)
for k in range(12):
z = 0.82 + k * 0.047
gb = box('Grille_Bar', (0.44, 0.02, 0.02), loc=(0, -1.345, z), material=RED)
box('Grille_Center_Bar', (0.035, 0.024, 0.58), loc=(0, -1.347, 0.80), material=RED, base=True)
# 보닛 옆 상표 띠 (크림색 줄)
for sx in (1, -1):
box('Hood_Stripe', (0.004, 1.2, 0.012), loc=(sx * 0.2505, -0.42, 1.2), material=CREAM)
t = text3d('Hood_Lettering', 'FARMALL', size=0.085, depth=0.003,
loc=(sx * 0.252, -0.55, 1.23), rot=(math.pi / 2, 0, sx * math.pi / 2), material=CREAM)
if sx < 0:
t.rotation_euler = (math.pi / 2, 0, -math.pi / 2)
# 계기판 / 연료탱크 마감
dash = extrude_profile('Dash_Panel', rounded_profile(0.5, 1.02, 1.42, 0.16), 0.03,
loc=(0, HOOD_Y1 + 0.015, 0), material=RED)
smooth(dash)
cylinder('Fuel_Cap', r=0.05, h=0.05, loc=(0, -0.05, 1.41), material=STEEL, seg=20)
cylinder('Radiator_Cap', r=0.04, h=0.05, loc=(0.08, -1.25, 1.44), material=STEEL, seg=20)
gauge = cylinder('Ammeter_Gauge', r=0.035, h=0.02, loc=(0.12, HOOD_Y1 + 0.03, 1.3),
rot=(-math.pi / 2, 0, 0), material=CREAM, seg=20)
# 배기관(오른쪽)과 흡기 프리클리너(가운데)
cylinder('Muffler', r=0.06, h=0.42, loc=(0.12, -0.55, 1.38), material=EXHAUST, seg=24)
cylinder('Exhaust_Stack', r=0.035, h=0.38, loc=(0.12, -0.55, 1.79), material=EXHAUST, seg=16)
cap = cylinder('Exhaust_Rain_Cap', r=0.05, h=0.012, loc=(0.135, -0.55, 2.17), rot=(0, math.radians(-25), 0),
material=EXHAUST, seg=20)
cylinder('Air_Intake_Pipe', r=0.045, h=0.25, loc=(0.0, -0.95, 1.38), material=RED, seg=20)
cylinder('Precleaner_Base', r=0.07, h=0.03, loc=(0.0, -0.95, 1.63), material=STEEL, seg=24)
cylinder('Precleaner_Bowl', r=0.065, h=0.11, loc=(0.0, -0.95, 1.66), material=GLASSB, seg=24)
lathe('Precleaner_Cap', [(0.0, 0.0), (0.075, 0.0), (0.075, 0.02), (0.05, 0.05), (0.0, 0.055)],
loc=(0, -0.95, 1.77), material=STEEL, seg=24)
# 전조등 (라디에이터 덮개 옆)
for sx in (1, -1):
rod('Headlight_Bracket', (sx * 0.29, -1.25, 1.2), (sx * 0.37, -1.25, 1.2), 0.012, IRON, seg=8)
lathe('Headlight_Body', [(0.0, 0.0), (0.05, 0.0), (0.075, 0.05), (0.08, 0.1), (0.0, 0.1)],
loc=(sx * 0.4, -1.2, 1.2), rot=(math.pi / 2, 0, 0), material=RED, seg=24)
cylinder('Headlight_Lens', r=0.07, h=0.01, loc=(sx * 0.4, -1.3, 1.2), rot=(math.pi / 2, 0, 0),
material=LENS, seg=24)
torus('Headlight_Bezel', 0.075, 0.008, loc=(sx * 0.4, -1.302, 1.2), rot=(math.pi / 2, 0, 0),
material=CHROME, seg=24, rseg=6)
# ---------------------------------------------------------------- 조향 장치
WHEEL_C = Vector((0.0, 0.86, 1.70))
UJ = Vector((-0.13, 0.32, 1.50))
col_dir = (WHEEL_C - UJ).normalized()
rod('Steering_Column', UJ, WHEEL_C, 0.022, IRON)
rod('Steering_Shaft', (-0.13, -1.22, 1.50), UJ, 0.02, IRON)
sphere('Steering_U_Joint', 0.035, loc=UJ, material=IRON, seg=16, rings=8)
gb = box('Steering_Gear_Box', (0.12, 0.14, 0.12), loc=(-0.13, -1.25, 1.42), material=RED, base=True)
bevel(gb, 0.02, 2)
for y in (-0.55, 0.05):
rod('Shaft_Support', (-0.13, y, 1.40), (-0.13, y, 1.49), 0.012, IRON, seg=8)
q = col_dir.to_track_quat('Z', 'Y')
sw_rim = torus('Steering_Wheel_Rim', 0.21, 0.016, material=BLACK, seg=48, rseg=10)
sw_hub = cylinder('Steering_Wheel_Hub', r=0.04, h=0.06, loc=(0, 0, -0.03), material=BLACK, seg=16)
spokes = [sw_rim, sw_hub]
for i in range(3):
a = 2 * math.pi * i / 3 + math.pi / 2
s = rod('Steering_Spoke', (0, 0, 0), (0.2 * math.cos(a), 0.2 * math.sin(a), -0.012), 0.011, STEEL, seg=8)
spokes.append(s)
sw = join(spokes, 'Steering_Wheel')
sw.location = WHEEL_C
sw.rotation_euler = q.to_euler()
# ---------------------------------------------------------------- 좌석
leaf = rod('Seat_Spring_Bar', (0, 0.80, 1.07), (0, 1.36, 1.15), 0.03, IRON)
seat = lathe('Pan_Seat', [(0.0, 0.0), (0.16, 0.005), (0.2, 0.03), (0.225, 0.09), (0.215, 0.095),
(0.19, 0.04), (0.155, 0.018), (0.0, 0.013)], loc=(0, 1.38, 1.16), material=STEEL, seg=48)
seat.scale = (1.0, 0.9, 1.0)
seat.rotation_euler = (math.radians(-8), 0, 0)
rod('Seat_Post', (0, 1.36, 1.10), (0, 1.38, 1.18), 0.04, IRON)
# ---------------------------------------------------------------- 펜더
def fender(name, sx):
bm = bmesh.new()
a0, a1, n = math.radians(12), math.radians(150), 40
R = 0.87
xs = [(0.70, 0.0), (0.98, 0.0), (1.02, -0.045)]
rows = []
for i in range(n + 1):
a = a0 + (a1 - a0) * i / n
row = []
for x, dr in xs:
rr = R + dr
row.append(bm.verts.new((sx * x, RA_Y + rr * math.cos(a), RA_Z + rr * math.sin(a))))
rows.append(row)
for i in range(n):
for j in range(len(xs) - 1):
bm.faces.new((rows[i][j], rows[i][j + 1], rows[i + 1][j + 1], rows[i + 1][j]))
ob = obj_from_bm(name, bm, RED)
solidify(ob, 0.008)
return ob
for sx in (1, -1):
fender('Rear_Fender', sx)
# 펜더 지지대: 차축 하우징에서 펜더 안쪽으로
for a in (60, 120):
ar = math.radians(a)
rod('Fender_Brace', (sx * 0.66, RA_Y + 0.12 * math.cos(ar), RA_Z + 0.12 * math.sin(ar)),
(sx * 0.72, RA_Y + 0.865 * math.cos(ar), RA_Z + 0.865 * math.sin(ar)), 0.018, RED, seg=8)

다른 모형