My goal here was to create a Mobius strip generator. It’s not quite as flexible as I’d like. You can adjust the twists in the band, but the figure-8 shape is hardcoded. I’d also hoped to do something more interesting with the coloring to better show the continuity of sides. I was expecting the 2-D shapes to have a directionality on one side so that viewed from ‘behind’ they would be invisible (I think OpenGL does this?). Anyway, I couldn’t figure out a good way to have different colored faces on the strip, so I added the balls to make it more dynamic. I also tried to get the balls to travel along the surface of the strip, but getting the translations right was a nightmare, so I settled for this. Overall, I like the look of it, but it’s not quite what I’d hoped it would be.
In fact, the Mobius strip was not my first idea. I originally wanted to make an infintely zooming/splashing water drop. When I first thought of it, I was not thinking about doing it programmatically. Rather than just move on, I wasted some time trying to get a bunch of little particles to act like something like a water drop (alas, I was unable to get far, but I learned that particle collision stuff is tricky). Next, I thought about trying to program just the shapes of water drops and splash crowns, etc. I didn’t get very far along there before coming up with an alternative that seemed more feasible.
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | //resolution of mobius strip int numPoints = 80; //180 //strip width int stripWidth = 120; //40; //size of strip float radius = 600; //200; //number of twists int twists = 1; //adjust twist position relative to loop float twist_offset = 45.0; //size of balls float ball_r = 30; //10; //number of balls int ball_cnt = 9; //speed of balls int ball_speed = 4; //variables PVector[] ball_loc; float ball_ang; float ang; int count = 0; int saveFrames = 10; //20 void setup(){ size(1500,1500,P3D); //size(500,500,P3D); ball_ang = 0; ball_loc = new PVector[ball_cnt]; for(int i=0; i< ball_cnt; i++){ ball_loc[i] = new PVector(0,0,0); } } void draw(){ background(0); smooth(); directionalLight(255,255,255,-1,0,0); directionalLight(255,255,255,0,1,0); ambientLight(127,127,127); translate(width/2, height/2, 0); rotateY(2.67); rotateZ(-2.43); //For Selecting orientation // rotateY(map(mouseX, 0, width, 0, 2*PI)); // rotateZ(map(mouseY, 0, height, 0, -2*PI)); // print("RY: " + map(mouseX, 0, width, 0, 2*PI) + " RZ: " + map(mouseY, 0, height, 0, -2*PI)); //draw strip mobius(); //draw balls rotating for(int i=0; i < ball_cnt; i++){ ang = ball_ang + (360/ball_cnt)*i; ball_loc[i].set(mobiusCenter(ang)); pushMatrix(); pushStyle(); translate(ball_loc[i].x,ball_loc[i].y,ball_loc[i].z); if(ang % 360 < 180){ color b = color(255-map(ang % 180,0,180,0,255),255 -map(ang%180,0,180,0,255),255); fill(b); }else{ color b = color(map(ang % 180,0,180,0,255),map(ang%180,0,180,0,255),255); fill(b); } noStroke(); sphere(ball_r); popMatrix(); popStyle(); } ball_ang += ball_speed; if(ball_ang == 720){ ball_ang = 0; } if(count < saveFrames){ saveFrame(); count++; } } void mobius(){ float angle = 0; float angleStep = 180.0/numPoints; float twistStep = twists * angleStep / 2; float twistAngle = twist_offset; //translate(200,200,0); //noStroke(); strokeWeight(1); beginShape(TRIANGLE_STRIP); for(int i=0; i <= numPoints; i++){ //cycle the colors w/ the angle color c = color(255*sin(radians(angle/2)),255-255*sin(radians(angle/2)),0); fill(c); float py = (stripWidth / 2) * cos(radians(twistAngle)); //raise and lower y to avoid intersection at the middle py += sin(radians(angle))*(stripWidth / 2); float radiusMod = (stripWidth / 2) * sin(radians(twistAngle)); float px = cos(radians(angle)) * (radius) + cos(radians(angle)) * radiusMod; float pz = sin(radians(angle)) * px + sin(radians(angle)) * radiusMod; angle += angleStep; twistAngle += twistStep; vertex(px,py, pz); py = (stripWidth / 2) * cos(radians(twistAngle) + PI); py += sin(radians(angle))*(stripWidth / 2); radiusMod = (stripWidth / 2) * sin(radians(twistAngle) + PI); px = cos(radians(angle)) * radius + cos(radians(angle)) * radiusMod; pz = sin(radians(angle)) * px + sin(radians(angle)) * radiusMod; vertex(px,py,pz); angle += angleStep; twistAngle += twistStep; } endShape(); } PVector mobiusCenter(float angle){ float py = sin(radians(angle))*(stripWidth / 2); //the y off set at the center float px = cos(radians(angle)) * radius; float pz = sin(radians(angle)) * px; PVector p = new PVector(px,py,pz); return p; } PVector mobiusNorm(float angle){ float px = cos(radians(angle)); float pz = sin(radians(angle)) * px; float angx = atan2(pz,px); float angy = twist_offset + twists * (angle * numPoints /180) / 2; PVector p = new PVector(angx,angy); return p; } |