// // name: snowflake.pde // // desc: renders snowflakes, with varying degrees of realism // // info: bugs, blame and beratement -> <- //re // => www.kiddphunk.com/experiments/ // // remember: andre the giant has a posse. // // todo: * nap // /////////////////////////////////////////////////////////////////////////////// int res = 750; // i & j dimentions int grid = 100; // spacing of snow grid int i = -100; int j = -100; boolean grid_set = false; // for highly realistic snowflakes, set 'realism=true' and 'detail=4' // for detailed, printable snowflakes, set 'realism=false' and 'detail=2' // for simple, printable snowflakes, set 'realism=false' and 'detail=1' boolean realism = true; // turn-on high realism rendering int max_detail = 6; // maximum amount of over-renders int min_detail = 2; // minimum amount of over-renders int max_size = 45; // maximum size of flake arm int min_size = 15; // minimum size of flake arm int max_depth = 12; // maximum recursive arm depth int min_depth = 4; // minumum recursive arm depth int width_thresh1 = 10; // first width threshold value int width_thresh2 = 70; // second width threshold value int width_thresh3 = 95; // third width threshold value int width_1 = 2; // first crystal width int width_2 = 3; // second crystal width int width_3 = 4; // third crystal width int min_trans = 90; // minimum snow transparency boolean snowstorm = false; // render a snowstorm as opposed to ordered lists /* boolean renderPS = true; // render output to postscript hardcopy as well // (needs SimplePostscript java class installed) */ // for printable snowflakes, set 'ground_color=0' and 'snow_color=255' and 'blue_back=false' // for highly realistic snowflakes, set 'ground_color=255' and 'snow_color=255' and 'blue_back=true' int ground_color = 255; int snow_color = 255; int complexity = 4; boolean first_random = false; boolean blue_back = true; boolean alt_realism = false; /////////////////////////////////////////////////////////////////////////////// float branch_angle = 30; float branching = 0.33; float shrinking = 0.66; float offset_angle = 0; float minx = 0; float miny = 0; float maxx = 0; float maxy = 0; int depth = 2; int nsize = 40; int count = 1; int detail = max_detail; //SimplePostscript ps = null; ///////////////////////////////////////////////////////////////////// void setup() { framerate(3); size(750, 300); /* if (renderPS) { ps = SimplePostscript.open("snowflakes.ps", 0, 0, res, res); } */ if (blue_back) { background(53, 49, 144); } else { background(ground_color); } } void loop() { if ((++count % detail == 0)) { offset_angle = random(PI/3.0); detail = int(random(min_detail, max_detail+1)); i+=grid; if (i > int(res)-grid) { j+=grid; i=grid; } if (j > int(res)) { // if (renderPS) { // ps.close(); // } } if (snowstorm) { scale(1, 1); rotateX(2*PI*random(0, 1)); rotateY(2*PI*random(0, 1)); i = int(50+random(res-100)); j = int(50+random(res-100)); translate(i, j); if (j < 200 || j > 500) { scale(.25, .25); } } } if (keyPressed) { if (key == 'r' || key == 'R') { i = j = grid; first_random = true; complexity = setVariables(100); background(53, 49, 144); } } if (grid_set) { translate(i,j); } drawSnowflake(offset_angle, complexity); } int setVariables(int complexity_power) { branch_angle = random(15, 165); branching = 0.2 + random(0, 1)*0.6; shrinking = 0.3 + random(0, 1)*0.4; if (complexity_power == 100) { int r = int(random(1, 11)); if (r >= 10) { r = 100; } complexity_power = r; } switch (complexity_power) { case 1: realism = false; min_size = 5; max_size = 10; min_depth = 4; max_depth = 6; min_detail = 1; max_detail = 1; framerate(12); break; case 2: realism = false; min_size = 5; max_size = 10; min_depth = 4; max_depth = 6; min_detail = 1; max_detail = 2; framerate(12); break; case 3: realism = false; min_size = 8; max_size = 15; min_depth = 4; max_depth = 8; min_detail = 2; max_detail = 3; framerate(12); break; case 4: realism = true; min_size = 8; max_size = 15; min_depth = 8; max_depth = 12; min_detail = 5; max_detail = 9; min_trans = 95; width_thresh1 = 80; width_thresh2 = 100; width_thresh3 = 100; if (snowstorm) { min_size = 2; max_size = 15; } if (!grid_set) { grid = int(2.5*max_size); i = grid; j = grid; grid_set = true; } framerate(8); break; case 5: realism = true; min_size = 13; max_size = 23; min_depth = 4; max_depth = 8; width_thresh1 = 60; width_thresh2 = 90; width_thresh3 = 100; min_trans = 95; min_detail = 2; max_detail = 6; break; case 6: realism = true; min_size = 10; max_size = 20; min_depth = 4; max_depth = 8; width_thresh1 = 100; width_thresh2 = 100; width_thresh3 = 100; min_trans = 85; min_detail = 4; max_detail = 6; break; default: case 7: realism = true; min_size = 15; max_size = 45; min_depth = 4; max_depth = 12; width_thresh1 = 40; width_thresh2 = 70; width_thresh3 = 95; min_trans = 90; min_detail = 3; max_detail = 6; break; case 8: realism = true; min_size = 5; max_size = 50; min_depth = 6; max_depth = 12; width_thresh1 = 20; width_thresh2 = 60; width_thresh3 = 90; min_trans = 45; min_detail = 5; max_detail = 8; break; case 9: realism = true; min_size = 30; max_size = 90; min_depth = 6; max_depth = 12; width_thresh1 = 20; width_thresh2 = 60; width_thresh3 = 90; min_trans = 85; min_detail = 12; max_detail = 20; width_1 = 4; width_2 = 10; width_3 = 20; break; case 100: // randomize if (first_random) { realism = false; int c = int(random(1, 100)); if (c > 30) { realism = true; } if (c > 70) { alt_realism = true; } // realism = false; max_size = int(random(15, 25)); min_size = max_size - 15; max_depth = int(random(5, 13)); min_depth = max_depth-4; width_thresh1 = int(random(0, 30)); width_thresh2 = int(random(0, 30)); width_thresh3 = int(random(0, 30)); // width_thresh2 = int(random(70, 100)); // width_thresh3 = int(random(80, 100)); min_trans = int(random(70, 100)); max_detail = int(random(7, 20)); min_detail = max_detail-int(random(2, 5)); width_1 = int(random(1, 4)); width_2 = int(random(1, max_size-10)); width_3 = int(random(1, max_size-20)); branch_angle = int(random(10, 40)); branching = 0.2 + random(0, 1)*0.6; shrinking = 0.3 + random(0, 1)*0.4; grid = int(2.5*max_size); i = grid; j = grid; grid_set = true; background(53, 49, 144); println("c: "+c+" realism: "+realism+" max_size: "+max_size+" min_size: "+min_size+" max_depth: "+max_depth+" min_depth: "+min_depth); println("w_th1: "+width_thresh1+" w_th2: "+width_thresh2+" w_th3: "+width_thresh3+" min_trans: "+min_trans+" min_detail: "+min_detail+" max_detail: "+max_detail); println("w_1: "+width_1+" w_2: "+width_2+" w_3: "+width_3+" branch_ang: "+branch_angle+" branching: "+branching+" shrinking: "+shrinking); first_random = false; } } if (!grid_set) { i = grid = int(3.0*max_size); j = 2*grid; grid_set = true; } depth = int(random(min_depth, max_depth)); nsize = int(random(min_size, max_size)); if (shrinking*branching > 0.36) { shrinking /= 2; } if (shrinking*branching < 0.1) { branching *= 2; } return complexity_power; } void drawSnowflake(float offset_angle, int complexity_power) { // rotate a random amount so that every flake // isn't oriented in same direction rotate(offset_angle); // randomize current set of snowflake variables setVariables(complexity_power); // render 6-armed snowflake for (int a=0; a<6; a++) { drawBranch(0, 0, nsize, nsize, 0, 1); rotate(PI/3.0); } } void drawBranch(int startx, int starty, int endx, int endy, float width, int curr_depth) { int cntx = (int)(startx+(endx-startx)*branching); int cnty = (int)(starty+(endy-starty)*branching); int nendx = (int)(cntx+(endx-startx)*shrinking); int nendy = (int)(cnty+(endy-starty)*shrinking); drawLine(cntx, cnty, RotateX(nendx,nendy,cntx,cnty,branch_angle), RotateY(nendx,nendy,cntx,cnty,branch_angle)); drawLine(cntx, cnty, RotateX(nendx,nendy,cntx,cnty,-branch_angle), RotateY(nendx,nendy,cntx,cnty,-branch_angle)); if (curr_depth != depth) { drawBranch(startx, starty, cntx, cnty, width*0.6, curr_depth+1); drawBranch(cntx, cnty, endx, endy, width*0.6, curr_depth+1); } } void drawLine(int startx, int starty, int endx, int endy) { if (startx < minx) { minx = startx; } if (starty < miny) { miny = starty; } if (startx > maxx) { maxx = startx; } if (starty > maxy) { maxy = starty; } if (endx < minx) { minx = endx; } if (endy < miny) { miny = endy; } if (endx > maxx) { maxx = endx; } if (endy > maxy) { maxy = endy; } int curr_width = 1; // draw detailed snowflake rendering boolean real = realism; if (alt_realism) { int c = int(random(1, 100)); if (c > 50) { real = false; } } if (real) { int rand_val = int(random(0, 100)); curr_width = 1; if (rand_val > width_thresh1) { curr_width = width_1; } if (rand_val > width_thresh2) { curr_width = width_2; } if (rand_val > width_thresh3) { curr_width = width_3; } fill(snow_color, int(random(min_trans, 100))); noStroke(); beginShape(QUADS); vertex(startx, starty); vertex(startx+curr_width, starty); vertex(endx+curr_width, endy); vertex(endx, endy); endShape(); // else draw simple snowflake } else { /* if (renderPS) { ps.setlinewidth(0.25); ps.setgray(0); ps.moveto(startx, starty); ps.lineto(endx, endy); ps.stroke(); } */ stroke(snow_color); line(startx, starty, endx, endy); } } int RotateX(int pointx, int pointy, int centerx, int centery, float angle) { angle = angle/180*PI; int x = (int)((pointx-centerx)*cos(angle) - (pointy-centery)*sin(angle) + centerx); return x; } int RotateY(int pointx, int pointy, int centerx, int centery, float angle) { angle = angle/180*PI; int y = (int)((pointx-centerx)*sin(angle) + (pointy-centery)*cos(angle) + centery); return y; } ///////////////////////////////////////////////////////////////////////////////