Skip to content

Instantly share code, notes, and snippets.

@Neon22
Created April 19, 2016 11:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Neon22/d2ea54bffa304e4911cffb2e807b8e49 to your computer and use it in GitHub Desktop.
Save Neon22/d2ea54bffa304e4911cffb2e807b8e49 to your computer and use it in GitHub Desktop.
random spaceship generator for openSCAD
//
// OpenSCAD version of the openCscad tool here:
// - https://github.com/smcameron/opencscad
// User editable parameters
// None yet
//---------------------------------
// Random seed control is critical.
// The seed defines all the variation. Using the same seed will give the same ship.
//
$seed = floor(rands(0,1000000,1)[0]);
// $seed = 970439;
max_random_values = 300;
echo("Seed=",$seed);
function randn(n,idx=0) = floor(rands(0,n,max_random_values, $seed)[idx]);
function randf(n,idx=0) = rands(0,n*1000,max_random_values, $seed)[idx] / 1000.0;
// echo(randn(10,0), randn(10,1));
// echo(randf(12.5,0), randf(12.5,1));
cyl_res = 40;
sph_res = 80;
Gseed = false;
verbose = false;
//---------------------------------
// from opencscad
module cyl(h,r1,r2,ctr=false) {
//if (verbose) {echo("cyl", h, r1, r2, ctr);}
cylinder(h=h, r1=r1, r2=r2, center=ctr, $fn=cyl_res);
}
//---------------------------------
// cylinder_rings
//
module cylinder_rings(length, r1, r2, nrings, rand_idx) {
if (verbose) {echo("cyl_rings", nrings, rand_idx);}
ringspacing = length / (nrings + 1.0);
ringheight = ringspacing / 3.0;
z = -(ringspacing * nrings) / 2.0;
dstart = ringspacing;
rstart = r1 * 1.3;
dr = ((r2 * 1.3) - rstart) / nrings;
//
for (i = [0:nrings]) {
z = (i+1) * ringspacing + dstart;
r = (i+1) * dr + rstart;
translate([0, 0, z])
cyl(ringheight, r, r, true);
}
}
// cylinder_ribs
module cylinder_ribs(length, r1, r2, nribs, rand_idx) {
if (verbose) {echo("cyl_ribs", rand_idx);}
dangle = 360.0 / nribs/4;
extra_factor = randf(1, rand_idx)+1;
//
for (i=[0:nribs]) {
angle = dangle*i;
rotate([0, 0, angle])
intersection() {
union() {
translate([max(r1, r2) * 1.05, 0, 0]);
cube(size=[max(r1, r2) * 2, max(r1, r2) * 2, length + 2], center=true);
translate([max(r1, r2) * -1.05, 0, 0]);
cube(size=[max(r1, r2) * 2, max(r1, r2) * 2, length + 2], center=true);
translate([0, max(r1, r2), 0]);
cube(size=[max(r1, r2) * 2.1, max(r1, r2) * 2.1, length + 2], center=true);
}
cyl(length, r1*extra_factor, r2*(extra_factor*0.8), true);
}
}
}
// cylindrical_thing
module cylindrical_thing(length, r1, r2, rand_idx) {
if (verbose) {echo("cyl_thing", rand_idx);}
cyl(length, r1, r2, true);
cylinder_rings(length, r1, r2, randn(3, rand_idx) + 5);
}
// cylinder_protrusions
module cylinder_protrusions(length, r1, r2, nprotrusions, rand_idx, excess=1.5) {
if (verbose) {echo("cylinder_protusions", rand_idx);}
intersection() {
// cyl(length, r1 * excess, r2 * excess, true);
cylindrical_thing(length, r1 * excess, r2 * excess, rand_idx);
//
union() {
rand_local = rand_idx+1;
for (i = [0:nprotrusions]) {
h = ((randn(80, rand_local) + 20) / 100.0) * length;
z = -((length - h) / 2.0) * (randn(100, rand_local+1) / 100.0);
x = min(r1, r2) * randf(0.2, rand_local+2);
angle = randf(360.0, rand_local+3);
translate([0, 0, z])
rotate([0, 0, angle])
cube(size=[x, max(r1, r2) * 3, h], center=true);
rand_local = rand_local + 1;
}
}
}
}
// random_cylinder_protrusions
module random_cylinder_protrusions(length, r1, r2, nelaborations, rand_idx) {
if (verbose) {echo("rand_cyl_protrusions", rand_idx);}
nprots = randn(5, rand_idx) + 5;
pheight = randf(0.1, rand_idx+1);
l = (1.0 - randf(0.7, rand_idx+2)) * length / nelaborations;
offset = randf((length / 2.0) - (l / 2.0), rand_idx+3);
if (randn(100, rand_idx+4) < 50) {
offset = -offset; }
translate([0, 0, offset])
cylinder_protrusions(l, ((r1 + r2) / 2.0) * (1 + pheight), ((r1 + r2) / 2.0) * (1 + pheight), nprots, rand_idx+5);
}
// random_cylinder_ribs
module random_cylinder_ribs(length, r1, r2, nelaborations, rand_idx) {
if (verbose) {echo("rand_cyl_ribs", rand_idx); }
nribs = randn(5, rand_idx) + 5;
ribheight = randf(0.3, rand_idx+1);
l = (1.0 - randf(0.7, rand_idx+2)) * length / nelaborations;
offset = randf((length / 2.0) - (l / 2.0), rand_idx+3);
if (randn(100, rand_idx+4) < 50) {
offset = -offset; }
translate([0, 0, offset])
cylinder_ribs(l, ((r1 + r2) / 2.0) * (1 + ribheight), ((r1 + r2) / 2.0) * (1 + ribheight), nribs, rand_idx+5);
}
// random_cylinder_rings
module random_cylinder_rings(length, r1, r2, nelaborations, rand_idx) {
if (verbose) {echo("rand_cyl_rings", rand_idx);}
nrings = randn(4, rand_idx) + 1;
ringheight = randf(0.05, rand_idx+1);
l = (1.0 - randf(0.7, rand_idx+2)) * length / nelaborations;
offset = randf((length / 2.0) - (l / 2.0), rand_idx+3);
if (randn(100, rand_idx+4) < 50) {
offset = -offset;}
translate([0, 0, offset])
cylinder_rings(l, r1 * (1 + ringheight), r2 * (1 + ringheight), nrings, rand_idx+5);
}
// block_pile
module block_pile(length, r1, r2, rand_idx) {
if (verbose) {echo("block_pile", rand_idx);}
w = max(r1, r2);
pod_module(length * 0.9, w * 0.7);
block_count = randn(40, rand_idx) + 20;
rand_local = rand_idx;
for (i =[0:block_count]) {
x = 0.8 * (randf(w, rand_local+1) - (w / 2.0));
y = 0.8 * (randf(w, rand_local+2) - (w / 2.0));
z = 0.8 * (randf(length - (length / 2.0),rand_local+3));
sx = randf(w / 2.0, rand_local+4) + w / 2.0;
sy = randf(w / 2.0, rand_local+5) + w / 2.0;
sz = randf(w / 2.0, rand_local+6) + w / 2.0;
translate([x, y, z])
cube(size=[sx, sy, sz], center=true);
rand_local = rand_local + 1;
}
}
// elaborate_cylinder
module elaborate_cylinder(length, r1, r2, nelaborations, with_spheres=false, rand_idx) {
if (verbose) {echo("elaborate_cylinder",length, r1, r2, nelaborations, with_spheres, rand_idx);}
cyl(length, r1, r2, true);
for (i = [0:nelaborations]) {
e = randn(3, rand_idx);
if (e==0) {
random_cylinder_protrusions(length, r1, r2, nelaborations, rand_idx+1+i);
} else if (e==1) {
random_cylinder_ribs(length, r1, r2, nelaborations, rand_idx+1+i);
} else if (e==2) {
random_cylinder_rings(length, r1, r2, nelaborations, rand_idx+1+i);
}
}
//
if (with_spheres) {
translate([0, 0, -length / 2.0])
if (randn(100, rand_idx+2) < 30) {
if (verbose) {echo(" elab=sph-cyl");}
difference() {
sphere(r1, $fn=sph_res);
//
translate([0, 0, -r1/2.0])
cyl(r1 * 1.2, r1 * 0.9, r1 * 0.7, true);
}
} else if (randn(100, rand_idx+3) < 30) {
if (verbose) {echo(" elab=thrustcluster");}
rotate(180, 0, 1, 0)
thruster_cluster(r1, rand_idx+4);
} else {
if (verbose) {echo(" elab=sphonly");}
sphere(r1, $fn=sph_res);
}
//
translate([0, 0, length / 2.0])
if (randn(100, rand_idx+5) < 50) {
if (verbose) {echo(" sph-r2");}
sphere(r2, $fn=sph_res);
} else {
difference() {
if (verbose) {echo(" sph2-cyl");}
sphere(r2, $fn=sph_res);
//
translate([0, 0, r2 / 2.0])
cyl(r1 * 1.2, r2 * 0.9, r2 * 0.7, true);
}
}
}
//
}
// thruster_module
module thruster_module(length, r1, r2, rand_idx) {
if (verbose) {echo("thruster_module", length, r1, r2, rand_idx);}
nelaborations = randn(2, rand_idx)+1;
difference() {
elaborate_cylinder(length, r1, r2, nelaborations, false, rand_idx+1);
//
translate([0, 0, length * 0.05])
cyl(length, r1 * 0.95, r2 * 0.95, true);
}
}
// thruster
module thruster_variant(length, r1, r2, rand_idx) {
if (verbose) {echo("thruster_variant", length, r1, r2, rand_idx);}
v = randf(0.3, rand_idx) - 0.15 + 1.0;
v2 = randf(0.3, rand_idx+1) - 0.15 + 1.0;
thruster_module(length, r1 * v, r2 * v2, rand_idx+2);
}
// thruster_cluster
module thruster_cluster(r, rand_idx) {
if (verbose) {echo("thruster_cluster", rand_idx);}
ttype = randn(3, rand_idx);
cyl(r * 0.2, r, r, true);
v1 = randf(0.3, rand_idx+1) - 0.15 + 1.0;
v2 = randf(0.3, rand_idx+2) - 0.15 + 1.0;
v3 = randf(0.3, rand_idx+3) - 0.15 + 1.0;
translate([0, 0, r * 0.1]) {
if (ttype==0) {
if (verbose) {echo("thrust");}
thruster_variant(r * v1 * 1.5, r * v2 * 0.4, r * v3, rand_idx+4);
} else {
if (verbose) {echo("thrust xN");}
n = randn(7, rand_idx+4) + 2;
r1 = r * 0.5 * v1;
r2 = r * 0.2 * v2;
r3 = r * 0.7;
thruster_variant(r1 * v3 * 1.5, r1 * v2 * 0.4, r1 * v3, rand_idx+5);
angle = 360.0 / n;
for (i=[0:n]) {
a = i*angle;
rotate([0,0,a])
translate([r3,0,0])
thruster_module(r2 * v3 * 1.5, r2 * v2 * 0.4, r2 * v3, rand_idx+6+i);
}
}
}
}
// fuselage_module
module fuselage_module(length, r1, r2, rand_idx) {
if (verbose) {echo("fuselage_module", rand_idx);}
nelabs = randn(3, rand_idx) + 2;
squashx = 1.0;
squashy = randf(0.5, rand_idx+1) + 0.5;
if (randn(100, rand_idx+2) < 50) {
squashx = randf(0.5, rand_idx+3) + 0.5;
squashy = 1.0;
}
scale([squashx, squashy, 1.0]) {
if (randn(100, rand_idx+4) < 50)
elaborate_cylinder(length, r1, r2, nelabs, true, rand_idx+5);
else
block_pile(length, r1, r2, rand_idx+5);
}
}
// spar_module
module spar_module(length, angle, rand_idx) {
if (verbose) {echo("spar_module", rand_idx);}
squash = 0.3 + randf(0.7, rand_idx);
r = length / (10.0 + randf(10.0, rand_idx+1));
rotate([0,angle,0])
scale([1.0, squash, 1.0])
cyl(length, r, r * randf(0.4, rand_idx+2) + 0.4, false);
}
// pod_module
module pod_module(length, r, rand_idx) {
if (verbose) {echo("pod_module", rand_idx);}
scale([r / 10.0, r / 10.0, length / 20.0])
sphere(r=10.0, $fn=sph_res);
}
// ring
module ring(length, rand_idx) {
if (verbose) {echo("ring", rand_idx);}
r = length * randf(0.5, rand_idx) + 0.5;
h = (r * 0.4) - randf(0.2, rand_idx+1);
difference() {
cyl(h, r, r, true);
cyl(h + 1, r * 0.95, r * 0.95, true);
}
}
// outrigger_module
module outrigger_module(length, rand_idx) {
if (verbose) {echo("outrigger_module", rand_idx);}
dualpod = (randn(100, rand_idx) < 50);
angle = randn(60, rand_idx+1) + 90;
//
spar_length = length;//(1+randn(2));
spar_module(spar_length, angle, rand_idx+2);
translate([sin(angle) * spar_length, 0, cos(angle) * spar_length])
//translate([0,0,spar_length/3/(2+randn(4))])
if (randn(100, rand_idx+2) < 50)
pod_module(length / 3.0, length / 10.0, rand_idx+3);
else
fuselage_module(length / 3.0, length / 10.0, length / 12.0, rand_idx+3);
//
if (dualpod) {
if (verbose) {echo(" dualpod"); }
dprad = randf(spar_length * 0.8, rand_idx+3) + spar_length * 0.1;
translate([sin(angle) * dprad, 0, cos(angle) * dprad])
//translate([0,0,-spar_length/3/(1+randn(4))])
if (randn(100, rand_idx+4) < 50)
pod_module(length / 3.0, length / 10.0, rand_idx+5);
else
fuselage_module(length / 3.0, length / 10.0, length / 12.0, rand_idx+5);
}
//
if (randn(100, rand_idx+5) < 10) {
if (verbose) {echo(" ring");}
dprad = randf(length * 0.8, rand_idx+6) + length * 0.1;
translate([0, 0, cos(angle) * dprad])
ring(length, rand_idx+7);
}
}
// outrigger_set_module
module outrigger_set_module(maxlength, minlength, rand_idx) {
if (verbose) {echo("outrigger_set_module", rand_idx);}
length = randf(maxlength - minlength, rand_idx) + minlength;
if (randn(100, rand_idx+1) < 20) {
n = randn(8, rand_idx+2) + 1;
angle = 360.0 / n;
for (i=[0:n]) {
rotate([0,0,angle*i])
outrigger_module(length, rand_idx+2+i);
}
} else {
angle = randn(360, rand_idx+3);
if (randn(100, rand_idx+4) < 30) {
angle = randn(4, rand_idx+5) * 90;
}
rotate([0, 0, angle])
outrigger_module(length, rand_idx+6);
}
}
// cut_in_half
module cut_in_half(size) {
if (verbose) {echo("cut in half");}
intersection() {
translate([0, -size/2.0, -size/2.0])
cube(size=size, center=false);
//
children(0);
}
}
// bilaterally_symmetricalize
module bilaterally_symmetricalize(size) {
if (verbose) {echo("Symmetry");}
cut_in_half(size) children(0);
mirror([1,0,0])
cut_in_half(size) children(0);
}
// ship_module
module ship_module(rand_idx=0) {
if (verbose) {echo("Ship module");}
fuselage_module(30 + randn(60), randn(10) + 8, randn(10) + 8, rand_idx);
outrigger_count = randn(2, rand_idx+1)+1;
for (i=[0:outrigger_count]) {
outrigger_set_module(60, 5, rand_idx+2+i);
}
}
// Main
module ship() {
if (randn(100) < 20) {
echo("ship",$seed);
bilaterally_symmetricalize(10000) ship_module();
} else {
ship_module();
}
}
rotate([90,0,0])
ship();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment