I did something similar in past and recall issues with closing my Moebius strip:
Update:
I revisited my code from a year ago and updated it based on my suggestion to you!
I was overlapping to close shape but replaced it with a clean “close” of the shape:
beginShape(QUAD_STRIP);
for (float th1 = th_ini; th1<th_fin + 0; th1+=TAU/100) // was th_fin + TAU/100 to overlap
{
R = 350;
float v = 60;
float u = th1;
mobPlot = mobius2(R, v, u);
vertex(mobPlot[0], mobPlot[1], mobPlot[2]);
mobPlot = mobius2(R, -v, u);
vertex(mobPlot[0], mobPlot[1], mobPlot[2]);
}
if (close)
{
mobPlot = mobius2(R, -60, 0);
vertex(mobPlot[0], mobPlot[1], mobPlot[2]);
mobPlot = mobius2(R, 60, 0);
vertex(mobPlot[0], mobPlot[1], mobPlot[2]);
}
endShape();
}
@Chrisir Thanks for inspiring me to visit this topic again! I spent a few hours on my original versions last night and they are in a much better state.
I suggested the gap was caused by rounding errors due to repeated addition of irrational numbers. I did provide some starting code but have decided to provide a full solution showing how to avoid the gap. The code below produced this Mobius Strip.
import peasy.*;
PeasyCam pcam;
PVector[] s;
// Radius of Mobius strip
float r = 100;
// Width of mobius strip
float w = 40;
// Number of slices round the strip
int nbrSlices = 20;
void setup() {
size(400, 400, P3D);
pcam = new PeasyCam(this, 300);
// Calculate strip
s = new PVector[nbrSlices * 2];
float deltaT = TWO_PI / (nbrSlices - 1);
// Calculate strip vertices
for (int i = 0; i < nbrSlices; i++) {
float t = i * deltaT;
float t2 = t / 2;
float cos_t2 = cos(t2);
float sin_t2 = sin(t2);
float cos_t = cos(t);
float sin_t = sin(t);
s[i] = new PVector( (r + w*cos_t2)*cos_t, (r + w*cos_t2)*sin_t, w * sin_t2 );
s[nbrSlices + i] = new PVector( (r - w*cos_t2)*cos_t, (r - w*cos_t2)*sin_t, -w * sin_t2 );
}
// Draw mobius
}
void draw() {
background(0);
lights();
stroke(255);
strokeWeight(2);
fill(200, 30, 30);
beginShape(QUAD_STRIP);
for (int i = 0; i < nbrSlices; i++) {
vertex(s[i].x, s[i].y, s[i].z);
vertex(s[i+nbrSlices].x, s[i+nbrSlices].y, s[i+nbrSlices].z);
}
endShape();
}
I used some normal() methods in code and it displays a smooth transition but the lighting was not correct (see link above). I will explore this further.
I extended my Möbius strip shape by adding additional QUAD_STRIPS that were transparent and this provided a clean transition at the seam.
I coloured the Möbius strip with a gradient (color wheel) and used the “extra transparent QUAD_STRIPS” for a smooth transition for this effect.
I have fixed location lights() (start of loop) and rotate my Möbius shape after and this is when I see the “lighting issues” at the seam. If the light is rotated along with Möbius shape the lighting issues do not present themselves (expected since this view appeared seamless).
PeasyCam is rotating everything including the lights(); try the example with noStrokes() and nbrSlices = 50. There is a noticeable issue at seam ((QUAD_STRIP) but not so apparent as next step 2.
Remove all the references to PeasyCam and add this and increase nbrSlices = 50:
And I see the same “lighting issues” that I discussed:
I wanted to see if the “lighting issues” were present in this example and they are for my use of lights().
The description here discusses this issue:
Sets the current normal vector. Used for drawing three dimensional shapes and surfaces, normal() specifies a vector perpendicular to a shape’s surface which, in turn, determines how lighting affects it. Processing attempts to automatically assign normals to shapes, but since that’s imperfect, this is a better option when you want more control.
If you only use ambient light you don’t have the problem because the surface normals are ignored. If you un-comment the directional light line the problem appears because of the way Processing estimates the normal vector.
float theta;
PVector[] s;
// Radius of Mobius strip
float r = 100;
// Width of mobius strip
float w = 40;
// Number of slices round the strip
int nbrSlices = 50;
void setup() {
size(400, 400, P3D);
// Calculate strip
s = new PVector[nbrSlices * 2];
float deltaT = TWO_PI / (nbrSlices - 1);
// Calculate strip vertices
for (int i = 0; i < nbrSlices; i++) {
float t = i * deltaT;
float t2 = t / 2;
float cos_t2 = cos(t2);
float sin_t2 = sin(t2);
float cos_t = cos(t);
float sin_t = sin(t);
s[i] = new PVector( (r + w*cos_t2)*cos_t, (r + w*cos_t2)*sin_t, w * sin_t2 );
s[nbrSlices + i] = new PVector( (r - w*cos_t2)*cos_t, (r - w*cos_t2)*sin_t, -w * sin_t2 );
}
}
void draw() {
translate(width/2, height/2);
background(0);
ambientLight(200,200,200);
// directionalLight(100,100,100, 0,1,1);
noStroke();
fill(200, 15, 15);
rotateX(theta);
theta += TAU / 200;
beginShape(QUAD_STRIP);
for (int i = 0; i < nbrSlices; i++) {
vertex(s[i].x, s[i].y, s[i].z);
vertex(s[i+nbrSlices].x, s[i+nbrSlices].y, s[i+nbrSlices].z);
}
endShape();
}```