Double Möbius strip

I am currently working on a mobius strip animation based on this example: Mobius Strip Animation - #6 by glv

However, I am trying to figure out a way to increase the folds and double the strip. This is my first attempt at working with 3D, and it is a tricky entry point and the math may be beyond my skill level, but I wonder if anyone has suggestions on how to increase the folds. Here is my code:

let rad;
let v;
let turn = 0;
let num;

function setup() {
  createCanvas(windowWidth, windowHeight, WEBGL);
  colorMode(HSB, 360, 100, 100, 100);
  rad = width*.3;
  v = width*.1
  num = height*.5;
  frameRate(30)
}

function draw() {
  //background(40, 20, 100);
  background(10);
  lights();
  push();
  rotateY(turn);
  rotateX(turn);
  rotateZ(turn);
  //noStroke();
  drawTrack(100, rad, v);
  drawEdges(100, rad, v);
  turn += 0.003
  pop();
}

function drawTrack(steps, rad, v) {
  beginShape(TRIANGLE_STRIP);
  fill(0);
  strokeWeight(2);
  stroke(255);
  for (let step = 0; step < (steps + 1); step += 1) {
    let u = step * TAU / steps;
    let x = (rad - v * cos(0.5 * u)) * cos(u);
    let y = (rad - v * cos(0.5 * u)) * sin(u);
    let z = -v * sin(0.5 * u);
    vertex(x, y, z);
    x = (rad + v * cos(0.5 * u)) * cos(u);
    y = (rad + v * cos(0.5 * u)) * sin(u);
    z = v * sin(0.5 * u);
    vertex(x, y, z);
  }
  endShape(CLOSE);
}

function drawEdges(steps, rad, v) {
  for (let step = 0; step < (steps + 1); step += 1) {
    fill(260, random(100), 100);
    stroke(0)
    let u = step * TAU / steps;
    let x = (rad - v * cos(0.5 * u)) * cos(u);
    let y = (rad - v * cos(0.5 * u)) * sin(u);
    let z = -v * sin(0.5 * u);
    push();
    translate(x, y, z);
    //box(10)c
    box(random(6,10))
    pop();
    x = (rad + v * cos(0.5 * u)) * cos(u);
    y = (rad + v * cos(0.5 * u)) * sin(u);
    z = v * sin(0.5 * u);
    push();
    translate(x, y, z);
    box(random(6,10))
    //box(10);
    pop();
  }
}
``
1 Like

To understand what is going on here you need some familiarity with trigonometry, especially the trigonometric functions sin and cos.

In the drawTrack and drawEdges functions the variable u represents the angle around a circle in radians. The constant TAU represents a complete revolution around a circle (i.e. 2 * π radians which is equivalent to 360°). So u is an angle that increases incrementally depending on the number of steps.

If you were simply plotting a circle you would simply leave one dimension constant (z = 0 for example), and you would compute the two other dimensions by multiplying the radius of the circle by either to cosine or the sine of the angle for the x and y dimensions respectively. However, since you’re drawing a strip, and it is being twisted, each edge of the strip will be offset from the edge of the circle, and you can use sine/cosine again to calculate the offset based on the twist. The thing that jumps out in the code is all of the use of 0.5 * u. We can deduce that anywhere we see this it represents the current angle of twist (since a Mobius strip has a ½ twist). So by simply multiplying by a different value instead of 0.5 we will get a different amount of twist.

Here’s an example:

const DefaultTwists = 0.5;

let rad;
let v;
let turn = 0;
let num;

let twistSlider;

function setup() {
	createCanvas(windowWidth, windowHeight, WEBGL);
	twistSlider = createSlider(0, 10, DefaultTwists, 0);
	twistSlider.position(10, 10);
	colorMode(HSB, 360, 100, 100, 100);
	rad = width * 0.3;
	v = width * 0.1;
	num = height * 0.5;
	frameRate(30)
}

function draw() {
	//background(40, 20, 100);
	orbitControl(2, 1, 0.05);
	background(10);
	lights();
	push();
	//noStroke();
	drawTrack(100, rad, v);
	drawEdges(100, rad, v);
	turn += 0.003
	pop();
}

function drawTrack(steps, rad, v) {
	beginShape(TRIANGLE_STRIP);
	fill(0);
	strokeWeight(2);
	stroke(255);
	let twists = twistSlider.value();
	for (let step = 0; step < (steps + 1); step += 1) {
		let u = step * TAU / steps;
		let x = (rad - v * cos(twists * u)) * cos(u);
		let y = (rad - v * cos(twists * u)) * sin(u);
		let z = -v * sin(twists * u);
		vertex(x, y, z);
		x = (rad + v * cos(twists * u)) * cos(u);
		y = (rad + v * cos(twists * u)) * sin(u);
		z = v * sin(twists * u);
		vertex(x, y, z);
	}
	endShape(CLOSE);
}

function drawEdges(steps, rad, v) {
	let twists = twistSlider.value();
	for (let step = 0; step < (steps + 1); step += 1) {
		fill(260, random(100), 100);
		stroke(0)
		let u = step * TAU / steps;
		let x = (rad - v * cos(twists * u)) * cos(u);
		let y = (rad - v * cos(twists * u)) * sin(u);
		let z = -v * sin(twists * u);
		push();
		translate(x, y, z);
		//box(10)c
		box(random(6, 10))
		pop();
		x = (rad + v * cos(twists * u)) * cos(u);
		y = (rad + v * cos(twists * u)) * sin(u);
		z = v * sin(twists * u);
		push();
		translate(x, y, z);
		box(random(6, 10))
		//box(10);
		pop();
	}
}
1 Like

Hello,

@fleshcircuit l like what you did with it!

I modified your version and provided an example:

Double Möbius strip
let rad;
let v;
let turn = 0;
let num;

function setup() {
  createCanvas(windowWidth, windowHeight, WEBGL);
  colorMode(HSB, 360, 100, 100, 100);
  rad = width*.3;
  v = width*.1
  num = height*.5;
  frameRate(30)
}

function draw() {
  //background(40, 20, 100);
  background(10);
  lights();
  push();
  rotateY(turn);
  rotateX(turn);
  rotateZ(turn);
  //noStroke();
  drawTrack(100, rad, v);
  //drawEdges(100, rad, v);
  turn += 0.003
  pop();
}

function drawTrack(steps, rad, v) {
  beginShape(TRIANGLE_STRIP);
  fill(0);
  strokeWeight(2);
  stroke(255);
  for (let step = 0; step < (2*steps + 1); step += 1) {
    let u = step * TAU / steps;
    
    let x = (rad - v * cos(0.5 * u)) * cos(u/2);
    let y = (rad - v * cos(0.5 * u)) * sin(u/2);
    let z = -v * sin(0.5 * u);
    vertex(x, y, z);
    
    x = (rad + v * cos(0.5 * u)) * cos(u/2);
    y = (rad + v * cos(0.5 * u)) * sin(u/2);
    z = v * sin(0.5 * u);
    vertex(x, y, z);
  }
  endShape(CLOSE);
}

function drawEdges(steps, rad, v) {
  for (let step = 0; step < (steps + 1); step += 1) {
    fill(260, random(100), 100);
    stroke(0)
    let u = step * TAU / steps;
    let x = (rad - v * cos(0.5 * u)) * cos(u);
    let y = (rad - v * cos(0.5 * u)) * sin(u);
    let z = -v * sin(0.5 * u);
    push();
    translate(x, y, z);
    //box(10)c
    box(random(6,10))
    pop();
    x = (rad + v * cos(0.5 * u)) * cos(u);
    y = (rad + v * cos(0.5 * u)) * sin(u);
    z = v * sin(0.5 * u);
    push();
    translate(x, y, z);
    box(random(6,10))
    //box(10);
    pop();
  }
}
``

Output:

You can add more loops:

You will have to decipher what I did for more loops… it was familiar and I just played around with it a bit.

:)