OpenSCAD 教程/第 4 章
上一章最后一个示例的脚本变得相当长。这是因为用更复杂的轮子设计(需要创建许多语句)替换了简单的圆柱形轮子(需要一个语句来创建)。要将轮子从简单的设计更改为复杂的设计,您必须识别所有定义简单轮子的圆柱体命令,并将它们替换为定义复杂轮子的命令。此过程听起来类似于您必须经历的更改轮子直径的步骤。当没有使用变量时,您必须识别脚本中的对应值,并将它们一一替换为新值。这个重复且耗时的过程通过使用 wheel_radius 变量得到了改进,该变量使您能够快速轻松地更改轮子的直径。但是,当您想完全更改轮子的设计时,您能做些什么来改进相应的容易出错的过程呢?答案是肯定的!您可以使用模块,它类似于应用于整个部件/模型的变量。您可以将设计的一部分或甚至整个模型定义为模块。
首先,请回忆一下复杂轮子的设计。
wheel_with_spherical_sides_and_holes.scad $fa = 1; $fs = 0.4; wheel_radius=10; side_spheres_radius=50; hub_thickness=4; cylinder_radius=2; cylinder_height=2*wheel_radius; difference() { // Wheel sphere sphere(r=wheel_radius); // Side sphere 1 translate([0,side_spheres_radius + hub_thickness/2,0]) sphere(r=side_spheres_radius); // Side sphere 2 translate([0,- (side_spheres_radius + hub_thickness/2),0]) sphere(r=side_spheres_radius); // Cylinder 1 translate([wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 2 translate([0,0,wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 3 translate([-wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 4 translate([0,0,-wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); } |
您可以通过以下方式将上述轮子定义为模块。
blank_model.scad $fa = 1; $fs = 0.4; module wheel() { wheel_radius=10; side_spheres_radius=50; hub_thickness=4; cylinder_radius=2; cylinder_height=2*wheel_radius; difference() { // Wheel sphere sphere(r=wheel_radius); // Side sphere 1 translate([0,side_spheres_radius + hub_thickness/2,0]) sphere(r=side_spheres_radius); // Side sphere 2 translate([0,- (side_spheres_radius + hub_thickness/2),0]) sphere(r=side_spheres_radius); // Cylinder 1 translate([wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 2 translate([0,0,wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 3 translate([-wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 4 translate([0,0,-wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); } } |
您需要做几件事。您应该注意的第一件事是,为了定义模块,您必须键入 module 关键字,后跟要赋予该模块的名称。在本例中,模块名为 wheel。模块名称后面跟着一对括号。目前括号内没有任何内容,因为还没有为该模块定义任何参数。最后,括号后面跟着一对大括号。所有定义相应对象的命令都放在大括号内。末尾不需要分号。
您应该注意的第二件事是,OpenSCAD 还没有创建任何轮子。这是因为您只是定义了 wheel 模块,但还没有使用它。为了创建一个轮子,您需要添加一个创建轮子的语句,类似于添加创建任何基本对象(立方体、球体等)的语句。
wheel_created_by_module.scad $fa = 1; $fs = 0.4; module wheel() { wheel_radius=10; side_spheres_radius=50; hub_thickness=4; cylinder_radius=2; cylinder_height=2*wheel_radius; difference() { // Wheel sphere sphere(r=wheel_radius); // Side sphere 1 translate([0,side_spheres_radius + hub_thickness/2,0]) sphere(r=side_spheres_radius); // Side sphere 2 translate([0,- (side_spheres_radius + hub_thickness/2),0]) sphere(r=side_spheres_radius); // Cylinder 1 translate([wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 2 translate([0,0,wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 3 translate([-wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 4 translate([0,0,-wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); } } wheel(); |
您可以将定义模块视为扩展 OpenSCAD 脚本语言。当您定义了一个 wheel 模块时,就像拥有一个额外的可用基本对象。在本例中,新对象是您定义的轮子。然后,您可以像使用任何其他可用基本对象一样使用此模块。
尝试在汽车的脚本中定义上述轮子模块。尝试使用定义的 wheel 模块创建汽车的轮子。 |
car_with_wheels_created_by_module.scad module wheel() { wheel_radius=10; side_spheres_radius=50; hub_thickness=4; cylinder_radius=2; cylinder_height=2*wheel_radius; difference() { // Wheel sphere sphere(r=wheel_radius); // Side sphere 1 translate([0,side_spheres_radius + hub_thickness/2,0]) sphere(r=side_spheres_radius); // Side sphere 2 translate([0,- (side_spheres_radius + hub_thickness/2),0]) sphere(r=side_spheres_radius); // Cylinder 1 translate([wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 2 translate([0,0,wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 3 translate([-wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 4 translate([0,0,-wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); } } $fa = 1; $fs = 0.4; base_height = 10; top_height = 14; track = 35; body_roll = 0; wheels_turn = 0; rotate([body_roll,0,0]) { // Car body base cube([60,20,base_height],center=true); // Car body top translate([5,0,base_height/2+top_height/2 - 0.001]) cube([30,20,top_height],center=true); } // Front left wheel translate([-20,-track/2,0]) rotate([0,0,wheels_turn]) wheel(); // Front right wheel translate([-20,track/2,0]) rotate([0,0,wheels_turn]) wheel(); // Rear left wheel translate([20,-track/2,0]) rotate([0,0,0]) wheel(); // Rear right wheel translate([20,track/2,0]) rotate([0,0,0]) wheel(); // Front axle translate([-20,0,0]) rotate([90,0,0]) cylinder(h=track,r=2,center=true); // Rear axle translate([20,0,0]) rotate([90,0,0]) cylinder(h=track,r=2,center=true); |
在 wheel 模块中指定的轮子设计有许多可以用来自定义它的变量。这些变量是在 wheel 模块定义的大括号内定义的。因此,虽然 wheel 模块的输出可以定制,但 wheel 模块本身只能创建轮子的一个版本,它对应于定义的变量的值。这意味着 wheel 模块不能用来为前后轴创建不同的轮子。如果您一直在了解参数化设计的良好实践,您应该意识到这种情况是不希望的。如果 wheel 模块可以用来创建不同版本的轮子,那会好得多。为此,在 wheel 模块内定义和使用的变量,需要作为 wheel 模块的参数来定义,而不是直接在模块内部定义。这可以通过以下方式完成。
wheel_created_by_parameterized_module.scad $fa = 1; $fs = 0.4; module wheel(wheel_radius, side_spheres_radius, hub_thickness, cylinder_radius) { cylinder_height=2*wheel_radius; difference() { // Wheel sphere sphere(r=wheel_radius); // Side sphere 1 translate([0,side_spheres_radius + hub_thickness/2,0]) sphere(r=side_spheres_radius); // Side sphere 2 translate([0,- (side_spheres_radius + hub_thickness/2),0]) sphere(r=side_spheres_radius); // Cylinder 1 translate([wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 2 translate([0,0,wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 3 translate([-wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 4 translate([0,0,-wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); } } wheel(wheel_radius=10, side_spheres_radius=50, hub_thickness=4, cylinder_radius=2); |
您应该注意模块参数的定义在括号内。您还应该注意,每个参数的值不再在模块定义的大括号内分配。相反,参数的值是在每次调用模块时定义的。因此,该模块现在可以用来创建不同版本的轮子。
尝试在汽车的脚本中定义上述 wheel 模块。尝试使用 wheel 模块创建汽车的轮子。在调用 wheel 模块时,将 10、50、4 和 2 的值传递给相应的 wheel_radius、side_spheres_radius、hub_thickness 和 cylinder_radius 参数。 |
car_with_wheels_created_by_parameterized_module.scad module wheel(wheel_radius, side_spheres_radius, hub_thickness, cylinder_radius) { cylinder_height=2*wheel_radius; difference() { // Wheel sphere sphere(r=wheel_radius); // Side sphere 1 translate([0,side_spheres_radius + hub_thickness/2,0]) sphere(r=side_spheres_radius); // Side sphere 2 translate([0,- (side_spheres_radius + hub_thickness/2),0]) sphere(r=side_spheres_radius); // Cylinder 1 translate([wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 2 translate([0,0,wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 3 translate([-wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 4 translate([0,0,-wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); } } $fa = 1; $fs = 0.4; base_height = 10; top_height = 14; track = 35; body_roll = 0; wheels_turn = 0; rotate([body_roll,0,0]) { // Car body base cube([60,20,base_height],center=true); // Car body top translate([5,0,base_height/2+top_height/2 - 0.001]) cube([30,20,top_height],center=true); } // Front left wheel translate([-20,-track/2,0]) rotate([0,0,wheels_turn]) wheel(wheel_radius=10, side_spheres_radius=50, hub_thickness=4, cylinder_radius=2); // Front right wheel translate([-20,track/2,0]) rotate([0,0,wheels_turn]) wheel(wheel_radius=10, side_spheres_radius=50, hub_thickness=4, cylinder_radius=2); // Rear left wheel translate([20,-track/2,0]) rotate([0,0,0]) wheel(wheel_radius=10, side_spheres_radius=50, hub_thickness=4, cylinder_radius=2); // Rear right wheel translate([20,track/2,0]) rotate([0,0,0]) wheel(wheel_radius=10, side_spheres_radius=50, hub_thickness=4, cylinder_radius=2); // Front axle translate([-20,0,0]) rotate([90,0,0]) cylinder(h=track,r=2,center=true); // Rear axle translate([20,0,0]) rotate([90,0,0]) cylinder(h=track,r=2,center=true); |
尝试在汽车的脚本中定义 wheel_radius、side_spheres_radius、hub_thickness 和 cylinder_radius 变量,并分别为它们分配 10、50、4 和 2 的值。尝试使用这些变量在调用 wheel 模块时定义 wheel_radius、side_spheres_radius、hub_thickness 和 cylinder_radius 参数的值。 |
wheel_radius=10; side_spheres_radius=50; hub_thickness=4; cylinder_radius=2; wheel(wheel_radius=wheel_radius, side_spheres_radius=side_spheres_radius, hub_thickness=hub_thickness, cylinder_radius=cylinder_radius); |
尝试为前后轴定义不同的 wheel_radius、side_spheres_radius、hub_thickness 和 cylinder_radius 变量。尝试为这些变量分配您喜欢的值的组合。请记住,还要在 wheel 模块的相应调用中编辑变量的名称。 |
car_with_different_wheels.scad module wheel(wheel_radius, side_spheres_radius, hub_thickness, cylinder_radius) { cylinder_height=2*wheel_radius; difference() { // Wheel sphere sphere(r=wheel_radius); // Side sphere 1 translate([0,side_spheres_radius + hub_thickness/2,0]) sphere(r=side_spheres_radius); // Side sphere 2 translate([0,- (side_spheres_radius + hub_thickness/2),0]) sphere(r=side_spheres_radius); // Cylinder 1 translate([wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 2 translate([0,0,wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 3 translate([-wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 4 translate([0,0,-wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); } } $fa = 1; $fs = 0.4; base_height = 10; top_height = 14; track = 35; body_roll = 0; wheels_turn = 0; wheel_radius_front=10; side_spheres_radius_front=50; hub_thickness_front=4; cylinder_radius_front=2; wheel_radius_rear=12; side_spheres_radius_rear=30; hub_thickness_rear=8; cylinder_radius_rear=3; rotate([body_roll,0,0]) { // Car body base cube([60,20,base_height],center=true); // Car body top translate([5,0,base_height/2+top_height/2 - 0.001]) cube([30,20,top_height],center=true); } // Front left wheel translate([-20,-track/2,0]) rotate([0,0,wheels_turn]) wheel(wheel_radius=wheel_radius_front, side_spheres_radius=side_spheres_radius_front, hub_thickness=hub_thickness_front, cylinder_radius=cylinder_radius_front); // Front right wheel translate([-20,track/2,0]) rotate([0,0,wheels_turn]) wheel(wheel_radius=wheel_radius_front, side_spheres_radius=side_spheres_radius_front, hub_thickness=hub_thickness_front, cylinder_radius=cylinder_radius_front); // Rear left wheel translate([20,-track/2,0]) rotate([0,0,0]) wheel(wheel_radius=wheel_radius_rear, side_spheres_radius=side_spheres_radius_rear, hub_thickness=hub_thickness_rear, cylinder_radius=cylinder_radius_rear); // Rear right wheel translate([20,track/2,0]) rotate([0,0,0]) wheel(wheel_radius=wheel_radius_rear, side_spheres_radius=side_spheres_radius_rear, hub_thickness=hub_thickness_rear, cylinder_radius=cylinder_radius_rear); // Front axle translate([-20,0,0]) rotate([90,0,0]) cylinder(h=track,r=2,center=true); // Rear axle translate([20,0,0]) rotate([90,0,0]) cylinder(h=track,r=2,center=true); |
您可以为 wheel 模块的参数设置特定的值组合作为默认值。这可以通过以下方式实现。
$fa = 1; $fs = 0.4; module wheel(wheel_radius=10, side_spheres_radius=50, hub_thickness=4, cylinder_radius=2) { cylinder_height=2*wheel_radius; difference() { // Wheel sphere sphere(r=wheel_radius); // Side sphere 1 translate([0,side_spheres_radius + hub_thickness/2,0]) sphere(r=side_spheres_radius); // Side sphere 2 translate([0,- (side_spheres_radius + hub_thickness/2),0]) sphere(r=side_spheres_radius); // Cylinder 1 translate([wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 2 translate([0,0,wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 3 translate([-wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 4 translate([0,0,-wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); } } |
您应该注意,默认值是在模块定义的括号内分配的。通过为模块的参数定义默认值,您在使用 wheel 模块的方式上有了更大的灵活性。例如,使用该模块最简单的方法是在调用它时不指定任何参数。
wheel_created_by_default_parameters.scad … wheel(); … |
如果在调用 wheel 模块时没有指定参数的值,则使用该参数的默认值。默认值可以设置为与轮子的最常用版本相同。默认值可以通过在调用 wheel 模块时为相应参数分配新值来覆盖。可以覆盖零个或任何数量的默认值。因此,通过指定默认值,wheel 模块可以使用以下任何方式以及更多方式使用。
wheel_created_by_default_parameters.scad … wheel(); … |
wheel_with_thicker_hub.scad … wheel(hub_thickness=8); … |
wheel_with_thicker_hub_and_larger_radius.scad … wheel(hub_thickness=8, wheel_radius=12); … |
在 wheel 模块的定义中包含默认值。尝试通过覆盖任何数量的默认值来创建几个轮子。您能制作出如下所示的轮子吗? |
wheel_with_larger_side_radius.scad … wheel(side_spheres_radius=10); … |
使用模块是 OpenSCAD 的一个非常强大的功能。您应该开始将您的模型视为模块的组合。例如,汽车模型可以被认为是车身、轮子和轴模块的组合。这打开了进一步重用和重新组合模块以创建不同模型的可能性。
尝试定义一个车身模块和一个车轴模块。车身和车轴模块应该有哪些参数?尝试使用车身、轮子和车轴模块重新创建汽车。为轮子模块的参数提供一组默认值,对应于前轮。通过在脚本中定义适当的变量,在创建后轮时向轮子模块传递不同的值。为车身和车轴模块的参数也设置默认值。 |
car_with_different_wheels_and_default_body_and_axle.scad module wheel(wheel_radius=10, side_spheres_radius=50, hub_thickness=4, cylinder_radius=2) { cylinder_height=2*wheel_radius; difference() { // Wheel sphere sphere(r=wheel_radius); // Side sphere 1 translate([0,side_spheres_radius + hub_thickness/2,0]) sphere(r=side_spheres_radius); // Side sphere 2 translate([0,- (side_spheres_radius + hub_thickness/2),0]) sphere(r=side_spheres_radius); // Cylinder 1 translate([wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 2 translate([0,0,wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 3 translate([-wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 4 translate([0,0,-wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); } } module body(base_height=10, top_height=14, base_length=60, top_length=30, width=20, top_offset=5) { // Car body base cube([base_length,width,base_height],center=true); // Car body top translate([top_offset,0,base_height/2+top_height/2 - 0.001]) cube([top_length,width,top_height],center=true); } module axle(track=35, radius=2) { rotate([90,0,0]) cylinder(h=track,r=radius,center=true); } $fa = 1; $fs = 0.4; wheelbase = 40; track = 35; body_roll = 0; wheels_turn = 0; wheel_radius_rear=12; // Body rotate([body_roll,0,0]) { body(); } // Front left wheel translate([-wheelbase/2,-track/2,0]) rotate([0,0,wheels_turn]) wheel(); // Front right wheel translate([-wheelbase/2,track/2,0]) rotate([0,0,wheels_turn]) wheel(); // Rear left wheel translate([wheelbase/2,-track/2,0]) rotate([0,0,0]) wheel(wheel_radius=wheel_radius_rear); // Rear right wheel translate([wheelbase/2,track/2,0]) rotate([0,0,0]) wheel(wheel_radius=wheel_radius_rear); // Front axle translate([-wheelbase/2,0,0]) axle(); // Rear axle translate([wheelbase/2,0,0]) axle(); |
尝试重复使用车身、轮子和车轴模块来创建一个类似于以下的车辆。 |
car_with_six_wheels.scad module wheel(wheel_radius=10, side_spheres_radius=50, hub_thickness=4, cylinder_radius=2) { cylinder_height=2*wheel_radius; difference() { // Wheel sphere sphere(r=wheel_radius); // Side sphere 1 translate([0,side_spheres_radius + hub_thickness/2,0]) sphere(r=side_spheres_radius); // Side sphere 2 translate([0,- (side_spheres_radius + hub_thickness/2),0]) sphere(r=side_spheres_radius); // Cylinder 1 translate([wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 2 translate([0,0,wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 3 translate([-wheel_radius/2,0,0]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); // Cylinder 4 translate([0,0,-wheel_radius/2]) rotate([90,0,0]) cylinder(h=cylinder_height,r=cylinder_radius,center=true); } } module body(base_height=10, top_height=14, base_length=60, top_length=30, width=20, top_offset=5) { // Car body base cube([base_length,width,base_height],center=true); // Car body top translate([top_offset,0,base_height/2+top_height/2 - 0.001]) cube([top_length,width,top_height],center=true); } module axle(track=35, radius=2) { rotate([90,0,0]) cylinder(h=track,r=radius,center=true); } $fa = 1; $fs = 0.4; track = 35; body_roll = 0; wheels_turn = 0; base_length = 100; top_length = 75; top_offset = 5; front_axle_offset = 30; rear_axle_1_offset = 10; rear_axle_2_offset = 35; wheel_radius = 12; // Body rotate([body_roll,0,0]) { body(base_length=base_length, top_length=top_length, top_offset=top_offset); } // Front left wheel translate([-front_axle_offset,-track/2,0]) rotate([0,0,wheels_turn]) wheel(wheel_radius=wheel_radius); // Front right wheel translate([-front_axle_offset,track/2,0]) rotate([0,0,wheels_turn]) wheel(wheel_radius=wheel_radius); // Rear left wheel 1 translate([rear_axle_1_offset,-track/2,0]) rotate([0,0,0]) wheel(wheel_radius=wheel_radius); // Rear right wheel 1 translate([rear_axle_1_offset,track/2,0]) rotate([0,0,0]) wheel(wheel_radius=wheel_radius); // Rear left wheel 2 translate([rear_axle_2_offset,-track/2,0]) rotate([0,0,0]) wheel(wheel_radius=wheel_radius); // Rear right wheel 2 translate([rear_axle_2_offset,track/2,0]) rotate([0,0,0]) wheel(wheel_radius=wheel_radius); // Front axle translate([-front_axle_offset,0,0]) axle(); // Rear axle 1 translate([rear_axle_1_offset,0,0]) axle(); // Rear axle 2 translate([rear_axle_2_offset,0,0]) axle(); |