Klein-Bottle Non-Orientable Fold
Generated by GridFlow AI | Tags: klein-bottle, non-orientable, mathematical-art, recursive-projection, psychedelic-synesthesia, 3d-surface, hyperdimensional, iridescent
💡 AI 提示词
Create a Klein Bottle Surface Non-Orientable Fold artwork with psychedelic synesthesia visual style using recursive 3D-to-2D projection as the primary rendering technique🔧 核心算法要点
- Klein bottle parametric surface computation using the figure-8 immersion formula with separate equations for the tube and neck sections
- Recursive 3D-to-2D projection with 4D hyperbolic rotation for hyper-dimensional visualization of non-orientable topology
- Multi-layer compositing using four separate createGraphics buffers (background, main geometry, glow, overlay) with screen, add, and overlay blend modes
- Iridescent color calculation based on surface normals with HSB color mapping that shifts between cyan and magenta with spectral gold accents
- Pixel-level background rendering using loadPixels/updatePixels with spiral gradient computation for deep void atmosphere
- Recursive fold entity rendering with curveVertex-based organic forms that spawn child folds at multiple depth levels
🎨 原始代码
var sketch = function(p) {
var bgGfx, mainGfx, glowGfx, overlayGfx, depthGfx;
var kleinPoints = [];
var time = 0;
var foldDepth = 0;
var iridescencePhase = 0;
var hyperRotate = 0;
var mouseInfluence = { x: 0, y: 0, active: false };
var keyToggle = 0;
var palette = {
deepVoid: [10, 5, 8],
iridescentCyan: [180, 100, 100],
iridescentMagenta: [300, 100, 100],
spectralGold: [45, 90, 95],
voidViolet: [270, 80, 20],
foldGreen: [120, 70, 80]
};
// Klein bottle parametric equations
function kleinU(u) { return u; }
function kleinV(v) { return v; }
// Compute Klein bottle surface point
function computeKleinPoint(u, v, fold) {
var u2 = u * 2;
var cosU = p.cos(u);
var sinU = p.sin(u);
var cos2U = p.cos(u2);
var sin2U = p.sin(u2);
var cosV = p.cos(v);
var sinV = p.sin(v);
var r = 2 - p.cos(u2);
var x, y, z;
if (u < p.PI) {
x = r * cosU + 2 * (1 - p.cos(u2) / 2) * cosU * cosV;
y = r * sinU;
z = 2 * (1 - p.cos(u2) / 2) * sinU * cosV;
} else {
x = r * cosU + 2 * (1 - p.cos(u2) / 2) * (cosU + 1);
y = r * sinU;
z = 2 * (1 - p.cos(u2) / 2) * sinV;
}
// Apply non-orientable fold distortion
var foldFactor = p.sin(fold * p.TWO_PI) * 0.5;
x += foldFactor * sinU * sin(v * 2);
z += foldFactor * cosU * cos(v * 3);
return { x: x * 40, y: y * 40, z: z * 40, u: u, v: v };
}
// Project 3D to 2D with recursive hyper-projection
function project3Dto2D(point, recursion) {
var scale = 1.2;
var perspective = 600;
var centerX = p.width / 2;
var centerY = p.height / 2;
// Apply hyperbolic rotation in 4D space
var angle4D = hyperRotate * 0.3 + point.u * 0.5;
var w = p.cos(angle4D) * point.z + p.sin(angle4D) * point.x * 0.3;
// Recursive depth factor for non-orientable topology
var depthFactor = 1 + recursion * p.sin(time * 0.5 + point.v * 2) * 0.2;
var z4d = point.z * depthFactor + w * 0.4;
var zPerspective = perspective + z4d * 2;
if (zPerspective <= 0) zPerspective = 1;
var scaleFactor = scale * (perspective / zPerspective);
return {
x: point.x * scaleFactor + centerX + mouseInfluence.x * 20,
y: point.y * scaleFactor + centerY + mouseInfluence.y * 20,
z: z4d,
scale: scaleFactor
};
}
// Iridescent color calculation based on surface orientation
function iridescentColor(normal, phase) {
var hue = (normal.x * 60 + normal.y * 60 + phase * 120 + iridescencePhase) % 360;
var saturation = 85 + p.sin(normal.z * p.PI + phase) * 15;
var brightness = 70 + p.cos(normal.x * normal.y + phase * 2) * 25;
// Shift between cyan and magenta with spectral gold accents
var colorShift = p.sin(phase * 3 + time * 0.7) * 0.5 + 0.5;
if (colorShift > 0.7) {
hue = (hue + 30) % 360;
saturation *= 1.2;
}
return p.color(hue, saturation, brightness);
}
// Render recursive non-orientable fold
function renderRecursiveFold(x, y, depth, maxDepth) {
if (depth > maxDepth) return;
var size = (maxDepth - depth + 1) * 15;
var alpha = (1 - depth / maxDepth) * 180;
var foldAngle = p.sin(time * 2 + depth * 0.5) * p.PI;
var c = p.color(palette.foldGreen[0], palette.foldGreen[1], palette.foldGreen[2] * (1 - depth * 0.15));
c.setAlpha(alpha);
mainGfx.push();
mainGfx.translate(x, y);
mainGfx.rotate(foldAngle + depth * 0.3);
mainGfx.noFill();
mainGfx.stroke(c);
mainGfx.strokeWeight(2 - depth * 0.15);
mainGfx.beginShape();
var steps = 8 + depth * 2;
for (var i = 0; i <= steps; i++) {
var angle = (i / steps) * p.TWO_PI;
var r = size * (1 + 0.3 * p.sin(angle * 3 + time + depth));
var px = p.cos(angle) * r * (1 + 0.2 * p.cos(angle * 2));
var py = p.sin(angle) * r * (1 + 0.15 * p.sin(angle * 4));
mainGfx.curveVertex(px, py);
}
mainGfx.endShape(p.CLOSE);
// Recursive child folds
if (depth < maxDepth) {
var children = 3 + (depth % 2);
for (var j = 0; j < children; j++) {
var childAngle = (j / children) * p.TWO_PI + time * 0.3 + depth * 0.5;
var childDist = size * 0.6 + p.sin(time + j) * 10;
var childX = p.cos(childAngle) * childDist;
var childY = p.sin(childAngle) * childDist;
renderRecursiveFold(childX, childY, depth + 1, maxDepth);
}
}
mainGfx.pop();
}
// Render Klein bottle wireframe with recursive subdivision
function renderKleinWireframe() {
var uSteps = 48;
var vSteps = 64;
kleinPoints = [];
// Compute all points
for (var i = 0; i <= uSteps; i++) {
kleinPoints[i] = [];
var u = (i / uSteps) * p.TWO_PI * 2;
for (var j = 0; j <= vSteps; j++) {
var v = (j / vSteps) * p.TWO_PI * 2;
kleinPoints[i][j] = computeKleinPoint(u, v, foldDepth);
}
}
// Render wireframe with recursive projection
for (var i = 0; i < uSteps; i++) {
for (var j = 0; j < vSteps; j++) {
var p1 = kleinPoints[i][j];
var p2 = kleinPoints[(i + 1) % (uSteps + 1)][j];
var p3 = kleinPoints[i][(j + 1) % (vSteps + 1)];
var proj1 = project3Dto2D(p1, 2);
var proj2 = project3Dto2D(p2, 2);
var proj3 = project3Dto2D(p3, 2);
var normal = {
x: p2.x - p1.x + p3.x - p1.x,
y: p2.y - p1.y + p3.y - p1.y,
z: p2.z - p1.z + p3.z - p1.z
};
var normalMag = p.sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);
if (normalMag > 0) {
normal.x /= normalMag;
normal.y /= normalMag;
normal.z /= normalMag;
}
var c = iridescentColor(normal, p1.u / p.TWO_PI);
var alpha = 100 + p.sin(p1.v + time) * 50;
c.setAlpha(alpha);
mainGfx.stroke(c);
mainGfx.strokeWeight(0.5 + p.sin(p1.u * 0.5 + p1.v * 0.3 + time) * 0.5);
mainGfx.line(proj1.x, proj1.y, proj2.x, proj2.y);
mainGfx.line(proj1.x, proj1.y, proj3.x, proj3.y);
// Non-orientable fold highlight
if (j % 8 === 0 && i % 6 === 0) {
var glowAlpha = (p.sin(foldDepth * p.PI + p1.u * 0.3) * 0.5 + 0.5) * 150;
var glowC = p.color(palette.spectralGold[0], palette.spectralGold[1], palette.spectralGold[2]);
glowC.setAlpha(glowAlpha);
glowGfx.stroke(glowC);
glowGfx.strokeWeight(2);
glowGfx.point(proj1.x, proj1.y);
}
}
}
}
// Create deep void background with volumetric gradients
function renderBackground() {
bgGfx.loadPixels();
var res = 3;
for (var x = 0; x < p.width; x += res) {
for (var y = 0; y < p.height; y += res) {
var cx = p.width / 2;
var cy = p.height / 2;
var dx = x - cx;
var dy = y - cy;
var dist = p.sqrt(dx * dx + dy * dy);
var maxDist = p.sqrt(cx * cx + cy * cy);
var t = dist / maxDist;
var spiralAngle = p.atan2(dy, dx) + time * 0.1;
var spiral = p.sin(spiralAngle * 4 + t * 10 - foldDepth * 5) * 0.5 + 0.5;
var hue = (spiral * 120 + palette.voidViolet[0] + time * 5) % 360;
var sat = palette.voidViolet[1] * (1 - t * 0.5);
var bri = palette.voidViolet[2] * (1 - t * 0.8) + spiral * 15;
var c = p.color(hue, sat, bri);
for (var px = 0; px < res && x + px < p.width; px++) {
for (var py = 0; py < res && y + py < p.height; py++) {
bgGfx.pixels[(y + py) * bgGfx.width * 4 + (x + px) * 4] = p.red(c);
bgGfx.pixels[(y + py) * bgGfx.width * 4 + (x + px) * 4 + 1] = p.green(c);
bgGfx.pixels[(y + py) * bgGfx.width * 4 + (x + px) * 4 + 2] = p.blue(c);
bgGfx.pixels[(y + py) * bgGfx.width * 4 + (x + px) * 4 + 3] = 255;
}
}
}
}
bgGfx.updatePixels();
}
// Render spectral fold overlays
function renderSpectralOverlays() {
overlayGfx.clear();
var foldCount = 5;
for (var f = 0; f < foldCount; f++) {
var foldAngle = time * 0.5 + f * (p.TWO_PI / foldCount) + foldDepth * 2;
var foldRadius = p.width * 0.3 + p.sin(time + f) * 50;
var foldX = p.width / 2 + p.cos(foldAngle) * foldRadius;
var foldY = p.height / 2 + p.sin(foldAngle) * foldRadius;
var c = p.color(
(palette.iridescentCyan[0] + f * 30) % 360,
palette.iridescentCyan[1] - f * 10,
palette.iridescentCyan[2] - f * 15
);
c.setAlpha(30 + p.sin(time * 2 + f) * 20);
overlayGfx.noFill();
overlayGfx.stroke(c);
overlayGfx.strokeWeight(1);
var layers = 3;
for (var l = 0; l < layers; l++) {
var layerSize = 100 + l * 60 + p.sin(time * 1.5 + f + l) * 30;
overlayGfx.ellipse(foldX, foldY, layerSize, layerSize * (0.8 + p.sin(foldAngle * 2) * 0.2));
}
}
// Recursive fold entities at center
var centerX = p.width / 2 + p.sin(time * 0.3) * 50;
var centerY = p.height / 2 + p.cos(time * 0.4) * 50;
renderRecursiveFold(centerX, centerY, 0, 4);
}
p.setup = function() {
var container = document.getElementById('p5-wrapper');
p.createCanvas(container.offsetWidth, container.offsetHeight).parent(container);
bgGfx = p.createGraphics(p.width, p.height);
mainGfx = p.createGraphics(p.width, p.height);
glowGfx = p.createGraphics(p.width, p.height);
overlayGfx = p.createGraphics(p.width, p.height);
depthGfx = p.createGraphics(p.width, p.height);
p.colorMode(p.HSB, 360, 100, 100, 100);
p.frameRate(60);
renderBackground();
};
p.draw = function() {
time += 0.008;
foldDepth = (foldDepth + 0.003) % 1;
iridescencePhase += 0.02;
hyperRotate += 0.015;
mainGfx.clear();
glowGfx.clear();
// Update mouse influence decay
if (!mouseInfluence.active) {
mouseInfluence.x *= 0.95;
mouseInfluence.y *= 0.95;
}
// Render Klein bottle surface
renderKleinWireframe();
// Render spectral overlays
renderSpectralOverlays();
// Composite all layers with advanced blend modes
p.background(0);
// Base void layer
p.image(bgGfx, 0, 0);
// Main geometry layer with screen blend
p.blendMode(p.SCREEN);
p.image(mainGfx, 0, 0);
// Glow layer for ethereal bloom
p.blendMode(p.ADD);
p.tint(255, 40);
p.image(glowGfx, 0, 0);
// Overlay layer with multiply for depth
p.blendMode(p.OVERLAY);
p.tint(255, 60);
p.image(overlayGfx, 0, 0);
// Reset blend mode
p.blendMode(p.BLEND);
// Add subtle vignette
p.noStroke();
var vignetteSteps = 20;
for (var i = 0; i < vignetteSteps; i++) {
var t = i / vignetteSteps;
var alpha = p.map(t, 0, 1, 0, 40);
var size = p.map(t, 0, 1, 0, p.width * 0.7);
var c = p.color(0, 0, 0, alpha);
p.fill(c);
var w = p.width * (1 - t * 0.3);
var h = p.height * (1 - t * 0.3);
p.ellipse(p.width / 2, p.height / 2, size * 2 + w, size * 2 + h);
}
// Interactive highlight at mouse position
if (mouseInfluence.active || p.mouseX !== 0 || p.mouseY !== 0) {
var mDist = p.dist(p.mouseX, p.mouseY, p.width / 2, p.height / 2);
var mAlpha = p.map(mDist, 0, p.width / 2, 80, 0);
p.stroke(palette.spectralGold[0], palette.spectralGold[1], palette.spectralGold[2], mAlpha);
p.strokeWeight(2);
p.noFill();
var ringSize = 100 + p.sin(time * 3) * 30;
p.ellipse(p.mouseX, p.mouseY, ringSize, ringSize);
// Connection lines to nearest Klein points
for (var i = 0; i < 5; i++) {
var t = i / 5;
var angle = t * p.TWO_PI + time;
var px = p.width / 2 + p.cos(angle) * p.width * 0.3;
var py = p.height / 2 + p.sin(angle) * p.height * 0.3;
var distToMouse = p.dist(p.mouseX, p.mouseY, px, py);
if (distToMouse < 200) {
var lineAlpha = p.map(distToMouse, 0, 200, 50, 0);
p.stroke(palette.iridescentMagenta[0], palette.iridescentMagenta[1], palette.iridescentMagenta[2], lineAlpha);
p.line(p.mouseX, p.mouseY, px, py);
}
}
}
};
p.mouseMoved = function() {
mouseInfluence.x = (p.mouseX - p.width / 2) / (p.width / 2);
mouseInfluence.y = (p.mouseY - p.height / 2) / (p.height / 2);
mouseInfluence.active = true;
};
p.mouseDragged = function() {
mouseInfluence.x = (p.mouseX - p.width / 2) / (p.width / 2);
mouseInfluence.y = (p.mouseY - p.height / 2) / (p.height / 2);
mouseInfluence.active = true;
};
p.mouseReleased = function() {
mouseInfluence.active = false;
};
// Click: Reset fold cycle and spawn burst
p.mousePressed = function() {
foldDepth = 0;
hyperRotate = 0;
// Spawn burst of fold particles
var burstGfx = p.createGraphics(p.width, p.height);
burstGfx.noStroke();
for (var i = 0; i < 50; i++) {
var angle = p.random(p.TWO_PI);
var speed = p.random(50, 150);
var x = p.mouseX;
var y = p.mouseY;
var life = 1;
while (life > 0) {
x += p.cos(angle) * speed * 0.016;
y += p.sin(angle) * speed * 0.016;
life -= 0.02;
var c = p.color(
(palette.iridescentCyan[0] + life * 60) % 360,
100,
100,
life * 50
);
burstGfx.fill(c);
burstGfx.ellipse(x, y, 3, 3);
}
}
p.blendMode(p.ADD);
p.image(burstGfx, 0, 0);
p.blendMode(p.BLEND);
};
// Keyboard interactions
p.keyPressed = function() {
if (p.key === ' ') {
// Space: Toggle color mode
keyToggle = (keyToggle + 1) % 3;
if (keyToggle === 0) {
palette.iridescentCyan[0] = 180;
palette.iridescentMagenta[0] = 300;
} else if (keyToggle === 1) {
palette.iridescentCyan[0] = 120;
palette.iridescentMagenta[0] = 60;
} else {
palette.iridescentCyan[0] = 240;
palette.iridescentMagenta[0] = 0;
}
renderBackground();
} else if (p.key === 'f' || p.key === 'F') {
// F: Cycle fold animation speed
foldDepth = (foldDepth + 0.1) % 1;
} else if (p.key === 'r' || p.key === 'R') {
// R: Reset all parameters
foldDepth = 0;
time = 0;
hyperRotate = 0;
renderBackground();
} else if (p.key === 'h' || p.key === 'H') {
// H: Toggle hyper-rotation intensity
hyperRotate *= 2;
}
};
p.windowResized = function() {
var container = document.getElementById('p5-wrapper');
p.resizeCanvas(container.offsetWidth, container.offsetHeight);
bgGfx = p.createGraphics(p.width, p.height);
mainGfx = p.createGraphics(p.width, p.height);
glowGfx = p.createGraphics(p.width, p.height);
overlayGfx = p.createGraphics(p.width, p.height);
depthGfx = p.createGraphics(p.width, p.height);
renderBackground();
};
}; // p5 init stripped
✨ AI 艺术解读
This piece manifests the philosophical paradox of non-orientability through recursive Klein bottle projections that fold through hyper-dimensional space. The iridescent surface reveals the impossibility of distinguishing inside from outside, creating a visual meditation on the limits of spatial reasoning. The psychedelic synesthesia aesthetic transforms mathematical abstraction into cosmic experience—each fold cycle represents a journey through impossible topology. The viewer becomes entangled with the surface, their mouse position distorting the very fabric of non-orientable space, experiencing ego-death through mathematical sublime.
📝 补充说明
- Klein bottle parametric equations use u in [0, 2π] for the longitude and v in [0, 2π] for the latitude, with different formulas for the main body (u < π) and the neck (u ≥ π)
- 4D rotation uses angle = hyperRotate * 0.3 + u * 0.5 with cosine/sine of this angle applied to z and x coordinates to achieve the recursive projection effect
- Background pixel rendering uses spiralAngle = atan2(dy, dx) + time * 0.1 and spiral = sin(spiralAngle * 4 + t * 10 - foldDepth * 5) * 0.5 + 0.5 for the volumetric void effect
- Non-orientable fold distortion applies foldFactor = sin(foldDepth * TWO_PI) * 0.5 to the x and z coordinates based on sin(u) * sin(v * 2) and cos(u) * cos(v * 3) terms
- Performance optimization: Klein bottle wireframe uses 48x64 grid (3072 lines) with projection computed once per point, and background renders at 3px step size