OpenSCAD 教程/第 2 章
您在上章创建的模型是使用 OpenSCAD 的一个很好的起点,但也许在看到它之后,您会发现一些应该更改的方面。在这里,我们将讨论修改设计组件的策略。一种方法是使用 scale 命令,它是另一个转换命令。修改创建汽车车身底部的语句,如下所示,以便将车身的长度按 1.2 的比例增加。
car_with_lengthened_body_base.scad … // Car body base scale([1.2,1,1]) cube([60,20,10],center=true); … |
您应该注意到,scale 命令的使用方式与 transform 和 rotate 命令类似。它被添加到现有语句的左侧,语句之间不包含分号,并且它有一个作为输入参数的三值向量。与 translate 和 rotate 命令类似,每个值对应于沿 X、Y 和 Z 轴的缩放比例。
尝试修改 scale 命令的输入,以便沿 X 轴将车身底部按 1.2 的比例缩放,沿 Y 轴按 0.1 或 2 的比例缩放。您是否获得了可以作为火星车或坦克的东西?您是否对这些模型与原始汽车相比的外观差异感到惊讶? |
也可以将相同的 scale 命令或任何其他变换命令应用于多个对象。使用以下代码将 scale 命令应用于汽车车身的底部和顶部。
car_with_lengthened_body.scad scale([1.2,1,1]) { // Car body base cube([60,20,10],center=true); // Car body top translate([5,0,10 - 0.001]) cube([30,20,10],center=true); } |
您应该注意的第一件事是,为了将 scale 命令应用于多个对象,使用了花括号。定义相应对象以及它们的分号的语句都放在花括号内。花括号在末尾不需要分号。
您应该注意的第二件事是,空格和注释的使用如何提高脚本的可读性。以下脚本完全相同,您可以自行决定想阅读哪一个。
scale([1.2,1,1]) { cube([60,20,10],center=true); translate([5,0,10 - 0.001]) cube([30,20,10],center=true); } |
尝试将 scale 命令应用于您的整个模型。您是否记得将所有语句都包含在花括号内?为了使车轮不发生变形,沿 X 和 Z 轴的缩放因子之间应该是什么关系?为了获得比例相同但尺寸加倍的汽车,缩放因子应该是什么? |
- 为了使车轮不发生变形,沿 X 和 Z 轴的缩放因子应该相等。
scaled_car.scad $fa = 1; $fs = 0.4; scale([2,2,2]) { // Car body base cube([60,20,10],center=true); // Car body top translate([5,0,10 - 0.001]) cube([30,20,10],center=true); // Front left wheel translate([-20,-15,0]) rotate([90,0,0]) cylinder(h=3,r=8,center=true); // Front right wheel translate([-20,15,0]) rotate([90,0,0]) cylinder(h=3,r=8,center=true); // Rear left wheel translate([20,-15,0]) rotate([90,0,0]) cylinder(h=3,r=8,center=true); // Rear right wheel translate([20,15,0]) rotate([90,0,0]) cylinder(h=3,r=8,center=true); // Front axle translate([-20,0,0]) rotate([90,0,0]) cylinder(h=30,r=2,center=true); // Rear axle translate([20,0,0]) rotate([90,0,0]) cylinder(h=30,r=2,center=true); } |
以下脚本是您在第一章中创建的模型。
$fa = 1; $fs = 0.4; // Car body base cube([60,20,10],center=true); // Car body top translate([5,0,10 - 0.001]) cube([30,20,10],center=true); // Front left wheel translate([-20,-15,0]) rotate([90,0,0]) cylinder(h=3,r=8,center=true); // Front right wheel translate([-20,15,0]) rotate([90,0,0]) cylinder(h=3,r=8,center=true); // Rear left wheel translate([20,-15,0]) rotate([90,0,0]) cylinder(h=3,r=8,center=true); // Rear right wheel translate([20,15,0]) rotate([90,0,0]) cylinder(h=3,r=8,center=true); // Front axle translate([-20,0,0]) rotate([90,0,0]) cylinder(h=30,r=2,center=true); // Rear axle translate([20,0,0]) rotate([90,0,0]) cylinder(h=30,r=2,center=true); |
尝试将前轮绕 Z 轴旋转 20 度,就像汽车正在右转一样。为了使您的模型更逼真,尝试将汽车车身(底部和顶部)绕 X 轴旋转 5 度,方向与转向相反。要转动车轮,请修改现有 rotate 命令的输入参数,要转动车身,请添加新的 rotate 命令。 |
turning_car.scad $fa = 1; $fs = 0.4; rotate([5,0,0]) { // Car body base cube([60,20,10],center=true); // Car body top translate([5,0,10 - 0.001]) cube([30,20,10],center=true); } // Front left wheel translate([-20,-15,0]) rotate([90,0,-20]) cylinder(h=3,r=8,center=true); // Front right wheel translate([-20,15,0]) rotate([90,0,-20]) cylinder(h=3,r=8,center=true); // Rear left wheel translate([20,-15,0]) rotate([90,0,0]) cylinder(h=3,r=8,center=true); // Rear right wheel translate([20,15,0]) rotate([90,0,0]) cylinder(h=3,r=8,center=true); // Front axle translate([-20,0,0]) rotate([90,0,0]) cylinder(h=30,r=2,center=true); // Rear axle translate([20,0,0]) rotate([90,0,0]) cylinder(h=30,r=2,center=true); |
您应该已经了解到,模型大多数情况下并非旨在以一种版本存在。OpenSCAD 脚本语言的强大之处之一在于,它可以轻松地重复使用模型,或者只是在您对最终版本感到满意之前,对模型进行反复玩弄。现在该对您的汽车进行一些修改了!
尝试将车轮的半径更改为 10 个单位。您是否很容易找到要修改的值?您是否必须重复执行四次相同的操作? |
car_with_larger_wheels.scad // Front left wheel translate([-20,-15,0]) rotate([90,0,0]) cylinder(h=3,r=10,center=true); // Front right wheel translate([-20,15,0]) rotate([90,0,0]) cylinder(h=3,r=10,center=true); // Rear left wheel translate([20,-15,0]) rotate([90,0,0]) cylinder(h=3,r=10,center=true); // Rear right wheel translate([20,15,0]) rotate([90,0,0]) cylinder(h=3,r=10,center=true); |
虽然更改车轮尺寸并不难,但它本来可以更简单。首先,它本来可以更容易找到要更改的值。其次,您只需要更改一个值,因为所有车轮的半径都相同。所有这些都可以通过使用变量来实现。在下面的脚本中,引入了用于定义车轮半径的变量。
wheel_radius = 8; // Front left wheel translate([-20,-15,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // Front right wheel translate([-20,15,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // Rear left wheel translate([20,-15,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // Rear right wheel translate([20,15,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); |
每个变量都有两个部分:名称和值。在本例中,变量名称为“wheel_radius”。有效的变量名只使用字母数字字符和下划线 (A-Z、a-z、0-9 和 _)。在变量名之后,等于号将名称与值隔开,然后是值本身。最后,在末尾需要一个分号来表示该语句的完成。最好将变量集中定义在文档的开头。
定义变量后,可以在代码中使用它来表示其值。在本例中,cylinder 命令已修改为使用 wheel_radius 变量作为输入参数 r。当 OpenSCAD 评估此脚本时,它将设置输入参数 r 等于 wheel_radius 变量的值。
尝试使用名为 wheel_radius 的变量来定义汽车车轮的尺寸。尝试通过修改 wheel_radius 变量的值来更改车轮尺寸几次。您是否发现使用 wheel_radius 变量更改车轮尺寸更容易了多少? |
car_with_smaller_wheels.scad $fa = 1; $fs = 0.4; wheel_radius = 6; // Car body base cube([60,20,10],center=true); // Car body top translate([5,0,10 - 0.001]) cube([30,20,10],center=true); // Front left wheel translate([-20,-15,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // Front right wheel translate([-20,15,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // Rear left wheel translate([20,-15,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // Rear right wheel translate([20,15,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // Front axle translate([-20,0,0]) rotate([90,0,0]) cylinder(h=30,r=2,center=true); // Rear axle translate([20,0,0]) rotate([90,0,0]) cylinder(h=30,r=2,center=true); |
有一件重要的事情您应该牢记 OpenSCAD 中变量的行为。OpenSCAD 中的变量的行为类似于常量。它们只能保存一个值,并且在创建模型的过程中始终保留这个值。那么,如果在脚本开头为 wheel_radius 赋值,然后在定义两个前轮之后为它赋值,会发生什么?后轮的尺寸是否会与前轮不同?
尝试在定义前轮之后立即为 wheel_radius 变量赋值。您的汽车的前后轮尺寸是否不同? |
car_with_same_sized_wheels.scad $fa = 1; $fs = 0.4; wheel_radius = 6; // Car body base cube([60,20,10],center=true); // Car body top translate([5,0,10 - 0.001]) cube([30,20,10],center=true); // Front left wheel translate([-20,-15,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // Front right wheel translate([-20,15,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); wheel_radius = 12; // Rear left wheel translate([20,-15,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // Rear right wheel translate([20,15,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // Front axle translate([-20,0,0]) rotate([90,0,0]) cylinder(h=30,r=2,center=true); // Rear axle translate([20,0,0]) rotate([90,0,0]) cylinder(h=30,r=2,center=true); |
您应该注意到,所有车轮的尺寸都相同。如果存在对变量的多次赋值,OpenSCAD 将使用最后一次赋值的值。即使在最后一次赋值之前定义了使用此变量的语句,它们也将使用最后一次赋值的值。
在这种情况下,OpenSCAD 还会发出警告:警告:wheel_radius 在第 3 行被赋值,但在第 17 行被覆盖
在 { 花括号 } 内的变量赋值仅适用于这些括号内。在不同级别的括号包围下重复赋值不被视为冲突。 |
您现在可以轻松地玩弄车轮的尺寸。如果您可以用同样的轻松方式自定义模型的更多方面,那就太好了。您应该注意,修改车轮的尺寸不会影响模型的任何其他方面,不会以任何方式破坏您的模型。但并非总是如此。
尝试通过定义 base_height 和 top_height 变量,并对定义底部和顶部的相应语句进行适当更改,来修改汽车车身底部和顶部的尺寸。将 base_height 变量的值设置为 5,将 top_height 变量的值设置为 8。您发现了什么? |
car_with_floating_body_top.scad base_height = 5; top_height = 8; // Car body base cube([60,20,base_height],center=true); // Car body top translate([5,0,10 - 0.001]) cube([30,20,top_height],center=true); |
很明显,当底座和顶部分离时,汽车的车身不再是一个整体。这是因为车身顶部的正确位置取决于车身底座的高度和车身顶部的的高度。请记住,为了使顶部位于底座的顶部,您需要将顶部沿着 Z 轴平移一个距离,该距离等于底座高度的一半加上顶部高度的一半。如果您想将底座和顶部的的高度参数化,那么您也应该将顶部沿着 Z 轴的平移参数化。
尝试使用 `base_height` 和 `top_height` 变量将车身顶部的 Z 轴平移参数化,使其位于车身底座的顶部。尝试为 `base_height` 和 `top_height` 变量分配不同的值。车身顶部的 位置是否保持正确? |
car_with_properly_attached_body_top.scad base_height = 5; top_height = 8; wheel_radius = 8; // 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); |
car_with_higher_body.scad base_height = 8; top_height = 14; |
您应该记住,每次参数化模型的某个方面时,您也应该参数化其他依赖的方面,以防止模型分解。
尝试使用名为 `track` 的新变量参数化轨道(左右车轮之间的距离)。尝试为 `track` 变量分配不同的值。您观察到什么?您的模型的任何其他方面是否依赖于 `track` 变量的值?如果是,请使用 `track` 变量对它进行参数化,以使您的模型不会分解。 |
car_with_unattached_wheels.scad track = 40; // Front left wheel translate([-20,-track/2,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // Front right wheel translate([-20,track/2,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // Rear left wheel translate([20,-track/2,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // Rear right wheel translate([20,track/2,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); |
car_with_properly_attached_wheels.scad track = 40; // Front left wheel translate([-20,-track/2,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // Front right wheel translate([-20,track/2,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // Rear left wheel translate([20,-track/2,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // Rear right wheel translate([20,track/2,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // 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); |
挑战
[edit | edit source]以下脚本对应于参数化了轮子半径、底座高度、顶部高度和轨道的汽车模型。
car_from_parameterized_script.scad $fa = 1; $fs = 0.4; wheel_radius = 8; base_height = 10; top_height = 10; track = 30; // 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([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // Front right wheel translate([-20,track/2,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // Rear left wheel translate([20,-track/2,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // Rear right wheel translate([20,track/2,0]) rotate([90,0,0]) cylinder(h=3,r=wheel_radius,center=true); // 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_width` 变量参数化车轮的宽度,使用 `wheels_turn` 变量参数化前轮绕 Z 轴的旋转,以及使用 `body_roll` 变量参数化车身绕 X 轴的旋转。尝试为 `wheel_radius`、`base_height`、`top_height`、`track`、`wheel_width`、`wheels_turn` 和 `body_roll` 分配不同的值,以创建您喜欢的汽车版本。 |
turning_car_from_parameterized_script.scad $fa = 1; $fs = 0.4; wheel_radius = 10; base_height = 10; top_height = 14; track = 40; wheel_width = 10; body_roll = -5; wheels_turn = 20; 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([90,0,wheels_turn]) cylinder(h=wheel_width,r=wheel_radius,center=true); // Front right wheel translate([-20,track/2,0]) rotate([90,0,wheels_turn]) cylinder(h=wheel_width,r=wheel_radius,center=true); // Rear left wheel translate([20,-track/2,0]) rotate([90,0,0]) cylinder(h=wheel_width,r=wheel_radius,center=true); // Rear right wheel translate([20,track/2,0]) rotate([90,0,0]) cylinder(h=wheel_width,r=wheel_radius,center=true); // 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); |
现在您应该清楚地了解到,参数化您的模型可以释放出重用、自定义和迭代您的设计的能力,以及毫不费力地探索不同可能性。
参数化您自己的模型
[edit | edit source]您是否已经将新技能应用到实际操作中?您是否自己创建了其他模型?
尝试参数化您创建的模型的一些或更多方面。看看您可以走多远!尝试为定义的变量分配各种组合的值。看看您的设计版本可以有多么不同。 |