Brandon Taylor

21 Jan 2014

bttaylorMobius

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.

20140121_054541

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.

20140121_054631

 

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;
}