Created
April 19, 2016 11:08
-
-
Save Neon22/d2ea54bffa304e4911cffb2e807b8e49 to your computer and use it in GitHub Desktop.
random spaceship generator for openSCAD
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // 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