Mit difference() erzeugst du in OpenSCAD Löcher und Ausschnitte, indem du Schneidkörper von einem Grundkörper abziehst. In diesem Tutorial baust du Schritt für Schritt Bohrungen und einen Winkelhalter mit Befestigungslöchern.
Voraussetzungen
Du brauchst OpenSCAD und die Grundlagen aus Teil 6 des Kurses.
Kapitel 2 – Richtig konstruieren
Im vorherigen Teil haben wir mit union() mehrere Grundkörper zu einer gemeinsamen Konstruktion zusammengefasst.
Jetzt lernen wir die zweite wichtige boolesche Operation kennen:
difference();
Mit difference() wird Geometrie von einem anderen Körper abgezogen.
Damit lassen sich beispielsweise erzeugen:
-
Bohrungen
-
Ausschnitte
-
Durchbrüche
-
Taschen
-
Hohlräume
-
Kabelöffnungen
-
Steckerausschnitte
Gerade für technische 3D-Druckteile gehört difference() deshalb zu den wichtigsten OpenSCAD-Befehlen überhaupt.
Lernziel:
Nach dieser Lektion kannst du Körper voneinander abziehen und damit parametrische Bohrungen und Ausschnitte erzeugen. Außerdem kannst duunion()unddifference()miteinander kombinieren.
OpenSCAD difference(): So funktioniert die Subtraktion
Ein einfaches Beispiel:
difference() {
cube([40, 30, 10]);
cylinder(
h=10,
d=10,
$fn=64
);
}
Der erste Körper innerhalb von difference() ist der Grundkörper.
Alle folgenden Körper werden davon abgezogen.
Das Prinzip lautet also:
Grundkörper
-
Schneidkörper
=
Ergebnis
Die Reihenfolge ist wichtig
Bei union() spielt die Reihenfolge der enthaltenen Körper meist keine große Rolle.
Bei difference() dagegen schon.
Beispiel:
difference() {
grundkoerper();
schneidkoerper1();
schneidkoerper2();
}
Dabei gilt:
-
Das erste Objekt bleibt bestehen.
-
Das zweite wird abgezogen.
-
Das dritte wird ebenfalls abgezogen.
Weitere Objekte würden ebenfalls vom ersten Körper entfernt.
Eine Bohrung erzeugen
Nehmen wir einen einfachen Quader:
cube([40, 30, 10]);
Um eine mittige Bohrung zu erzeugen, verwenden wir einen Zylinder:
difference() {
cube([40, 30, 10]);
translate([
20,
15,
0
])
cylinder(
h=10,
d=8,
$fn=64
);
}
Der Zylinder besitzt 8 mm Durchmesser und wird in der Mitte des Quaders positioniert.
Schneidkörper etwas größer machen
Bei booleschen Operationen ist es meist sinnvoll, einen Schneidkörper nicht exakt an den Außenflächen enden zu lassen.
Statt:
cylinder(
h=10,
d=8
);
verwenden wir beispielsweise:
translate([0, 0, -1])
cylinder(
h=12,
d=8,
$fn=64
);
Der Zylinder ragt damit sowohl unten als auch oben etwas aus dem Quader heraus.
Warum ist der Überstand sinnvoll?
Wenn zwei Flächen exakt aufeinanderliegen, können bei geometrischen Berechnungen ungünstige Grenzfälle entstehen.
Deshalb ist es eine gute Angewohnheit, Schneidkörper etwas größer als nötig zu machen.
Ein kleiner Überstand von beispielsweise:
1
Millimeter ist bei vielen einfachen Konstruktionen ausreichend.
Überstand parametrisch definieren
ueberstand = 1;
Dann kann die Bohrung beispielsweise so aufgebaut werden:
translate([
breite / 2,
tiefe / 2,
-ueberstand
])
cylinder(
h=hoehe + 2 * ueberstand,
d=bohrung_d,
$fn=64
);
Der Schneidkörper reicht damit auf beiden Seiten über das Bauteil hinaus.
Parametrische Bohrung
Das vollständige Beispiel:
breite = 40;
tiefe = 30;
hoehe = 10;
bohrung_d = 8;
ueberstand = 1;
difference() {
cube([
breite,
tiefe,
hoehe
]);
translate([
breite / 2,
tiefe / 2,
-ueberstand
])
cylinder(
h=hoehe + 2 * ueberstand,
d=bohrung_d,
$fn=64
);
}
Ändern wir beispielsweise:
breite = 60;
bleibt die Bohrung automatisch mittig.
Mehrere Bohrungen
Innerhalb von difference() können beliebig viele Schneidkörper verwendet werden.
Beispiel:
difference() {
cube([60, 30, 10]);
translate([15, 15, -1])
cylinder(
h=12,
d=8,
$fn=64
);
translate([45, 15, -1])
cylinder(
h=12,
d=8,
$fn=64
);
}
Rechteckige Ausschnitte
Auch Quader können als Schneidkörper verwendet werden.
Beispiel:
difference() {
cube([60, 40, 10]);
translate([
15,
10,
-1
])
cube([
30,
20,
12
]);
}
Damit entsteht ein rechteckiger Durchbruch.
Solche Ausschnitte eignen sich beispielsweise für:
-
Displays
-
Steckverbinder
-
Kabel
-
Lüftungsöffnungen
-
Führungen
-
Taschen
union() und difference() kombinieren
Jetzt verwenden wir wieder unseren Winkelhalter aus Teil 6.
Er besteht aus:
union() {
// Grundplatte
// Rückwand
}
Diesen kompletten Grundkörper können wir innerhalb einer difference() verwenden:
difference() {
union() {
// Grundkörper
}
// Schneidkörper
}
Die Struktur kann man sich so vorstellen:
difference
├── union
│ ├── Grundplatte
│ └── Rückwand
├── Bohrung 1
└── Bohrung 2
Praxisprojekt: Winkelhalter mit Befestigungsbohrungen
Wir bauen den Winkelhalter aus Teil 6 weiter aus.
Parameter des Halters
breite = 80;
tiefe = 40;
hoehe = 50;
wand = 6;
Parameter der Bohrungen
bohrung_d = 5;
rand = 10;
ueberstand = 1;
Grundkörper
union() {
// Grundplatte
cube([
breite,
tiefe,
wand
]);
// Rückwand
translate([
0,
0,
wand
])
cube([
breite,
wand,
hoehe - wand
]);
}
Linke Bohrung
translate([
rand,
tiefe / 2,
-ueberstand
])
cylinder(
h=wand + 2 * ueberstand,
d=bohrung_d,
$fn=64
);
Die Bohrung befindet sich:
-
randMillimeter von der linken Außenkante entfernt -
mittig in Y-Richtung
-
vollständig durch die Grundplatte
Rechte Bohrung
Die zweite Bohrung können wir aus der Gesamtbreite berechnen:
translate([
breite - rand,
tiefe / 2,
-ueberstand
])
cylinder(
h=wand + 2 * ueberstand,
d=bohrung_d,
$fn=64
);
Damit bleibt der Abstand zur rechten Außenkante automatisch gleich.
Vollständiger Winkelhalter
// -------------------------
// Parameter
// -------------------------
breite = 80;
tiefe = 40;
hoehe = 50;
wand = 6;
bohrung_d = 5;
rand = 10;
ueberstand = 1;
// -------------------------
// Modell
// -------------------------
difference() {
// ---------------------
// Grundkörper
// ---------------------
union() {
// Grundplatte
cube([
breite,
tiefe,
wand
]);
// Rückwand
translate([
0,
0,
wand
])
cube([
breite,
wand,
hoehe - wand
]);
}
// ---------------------
// Bohrungen
// ---------------------
// linke Bohrung
translate([
rand,
tiefe / 2,
-ueberstand
])
cylinder(
h=wand + 2 * ueberstand,
d=bohrung_d,
$fn=64
);
// rechte Bohrung
translate([
breite - rand,
tiefe / 2,
-ueberstand
])
cylinder(
h=wand + 2 * ueberstand,
d=bohrung_d,
$fn=64
);
}
Parametrische Vorteile
Ändern wir:
bohrung_d = 6;
werden automatisch beide Bohrungen größer.
Ändern wir:
rand = 15;
verschieben sich beide Bohrungen entsprechend nach innen.
Ändern wir:
breite = 100;
bleibt die rechte Bohrung automatisch im gleichen Abstand zur rechten Außenkante.
Genau solche Abhängigkeiten machen parametrische Konstruktionen besonders flexibel.
Eine Bohrung durch die Rückwand
Auch die senkrechte Rückwand kann durchbohrt werden.
Dazu müssen wir den Schneidzylinder drehen.
Beispiel:
translate([
breite / 2,
-ueberstand,
hoehe / 2
])
rotate([-90, 0, 0])
cylinder(
h=wand + 2 * ueberstand,
d=bohrung_d,
$fn=64
);
Dabei wird:
-
der Zylinder erzeugt
-
um 90 Grad gedreht
-
an die gewünschte Position verschoben
-
vom Grundkörper abgezogen
Verschachtelte Operationen lesen
Mit zunehmender Komplexität wird der Code stärker verschachtelt.
Zum Beispiel:
difference() {
union() {
cube(...);
translate(...)
cube(...);
}
translate(...)
cylinder(...);
}
Man kann sich die Struktur als Baum vorstellen:
difference
├── union
│ ├── cube
│ └── translate
│ └── cube
└── translate
└── cylinder
Diese Denkweise hilft später enorm beim Verständnis größerer OpenSCAD-Modelle.
Mitmach-Aufgabe
Erstelle einen parametrischen Winkelhalter mit folgenden Abmessungen:
Halter
| Parameter | Wert |
|---|---|
| Breite | 100 mm |
| Tiefe | 50 mm |
| Höhe | 60 mm |
| Wandstärke | 6 mm |
Bohrungen
| Parameter | Wert |
|---|---|
| Durchmesser | 6 mm |
| Randabstand | 15 mm |
Die Grundplatte soll zwei Befestigungsbohrungen besitzen.
Die linke Bohrung befindet sich 15 mm von der linken Außenkante entfernt.
Die rechte Bohrung soll automatisch 15 mm von der rechten Außenkante entfernt liegen.
Verwende:
union()
difference()
translate()
cylinder()
Musterlösung
// -------------------------
// Parameter
// -------------------------
breite = 100;
tiefe = 50;
hoehe = 60;
wand = 6;
bohrung_d = 6;
rand = 15;
ueberstand = 1;
// -------------------------
// Modell
// -------------------------
difference() {
// Grundkörper
union() {
// Grundplatte
cube([
breite,
tiefe,
wand
]);
// Rückwand
translate([
0,
0,
wand
])
cube([
breite,
wand,
hoehe - wand
]);
}
// linke Bohrung
translate([
rand,
tiefe / 2,
-ueberstand
])
cylinder(
h=wand + 2 * ueberstand,
d=bohrung_d,
$fn=64
);
// rechte Bohrung
translate([
breite - rand,
tiefe / 2,
-ueberstand
])
cylinder(
h=wand + 2 * ueberstand,
d=bohrung_d,
$fn=64
);
}
Was haben wir gelernt?
Nach dieser Lektion kennst du die zweite wichtige boolesche Operation:
difference();
Du weißt:
-
der erste Körper bleibt erhalten
-
alle folgenden Körper werden abgezogen
-
Zylinder eignen sich hervorragend für Bohrungen
-
Quader können als rechteckige Schneidkörper verwendet werden
-
Schneidkörper sollten möglichst etwas überstehen
-
beliebig viele Geometrien können gleichzeitig entfernt werden
-
union()unddifference()lassen sich verschachteln -
Bohrungspositionen können vollständig parametrisch berechnet werden
Damit können wir bereits viele typische technische Bauteile für den 3D-Druck konstruieren.
Im nächsten Teil
Im nächsten Teil lernen wir die dritte grundlegende boolesche Operation kennen:
intersection();
Während union() Körper vereinigt und difference() Geometrie entfernt, behält intersection() nur den Bereich, in dem sich mehrere Körper überschneiden.
Damit lassen sich unter anderem interessante Formkörper und gezielt begrenzte Geometrien erzeugen.
Häufige Fragen
Wie entsteht mit difference() eine Bohrung?
Ein Zylinder wird vom Grundkörper abgezogen. Er muss an der gewünschten Bohrungsposition liegen und für ein durchgehendes Loch die gesamte Materialstärke durchdringen. Ein kleiner Überstand auf beiden Seiten erleichtert eine saubere Subtraktion.
Warum verschwindet bei difference() der falsche Körper?
Nur das erste Kind im Block bleibt als Grundkörper erhalten; alle folgenden Kinder werden davon abgezogen. Soll der Grundkörper aus mehreren Teilen bestehen, fasse diese zuerst mit union() zusammen.
Passendes Cheatsheet
Im Cheatsheet „Boolesche Operationen“ findest du ergänzende Grundlagen zum Nachschlagen. Du kannst das Cheatsheet auch direkt als PDF herunterladen.
