Higher-Dimensional Klein Bottle Immersion
Generated by GridFlow AI | Tags: klein-bottle, 4d-projection, sacred-geometry, hyper-dimensional, recursive-rendering, luminous-lines, volumetric-fog, non-euclidean
💡 AI 提示词
Higher-Dimensional Klein Bottle Immersion with recursive 4D-to-2D projection, sacred geometry overlays including hexagonal grids and golden ratio spirals, luminous white lines against deep charcoal fog, multi-layer compositing with add blend modes for glow, mouse-interactive distortion, click-triggered radial bursts, keyboard toggles for recursion depth and mode🔧 核心算法要点
- Parametric Klein bottle equations computed in 4D space with additional w-coordinate for hyper-dimensional embedding
- Recursive dimensional projection chain: 4D rotation matrices → 4D→3D perspective projection → 3D rotation → 3D→2D perspective with configurable recursion depth
- Multi-layer offscreen buffer compositing: background fog (pixel-level FBM noise), midground geometric structure, foreground luminous lines, and glow layer with ADD blend mode
- Sacred geometry overlay system including hexagonal grid generation, phi-spiral parametric curves, and recursive circle patterns based on golden ratio
- Mouse position dynamically scales and distorts the projected 2D coordinates creating real-time dimensional warping effect
- Per-pixel volumetric fog computation using fractional Brownian motion noise with radial vignette falloff
- Click-triggered radial burst and expanding ring animation with orbital geometry rotation system
- Interactive keyboard controls: R toggles recursion depth, M cycles rendering modes, Spacebar resets animation
🎨 原始代码
var sketch = function(p) {
var container, w, h;
var time = 0;
var bgBuffer, midBuffer, fgBuffer, glowBuffer;
var kbPoints = [];
var recursionDepth = 5;
var mouseInfluence = 0;
var clickTrigger = false;
var modeToggle = 0;
var fractalNoise;
p.setup = function() {
container = document.getElementById('p5-wrapper');
w = container.offsetWidth;
h = container.offsetHeight;
p.createCanvas(w, h).parent(container);
p.colorMode(p.RGB, 255, 255, 255, 1);
p.noStroke();
bgBuffer = p.createGraphics(w, h);
midBuffer = p.createGraphics(w, h);
fgBuffer = p.createGraphics(w, h);
glowBuffer = p.createGraphics(w, h);
bgBuffer.colorMode(p.RGB, 255, 255, 255, 1);
midBuffer.colorMode(p.RGB, 255, 255, 255, 1);
fgBuffer.colorMode(p.RGB, 255, 255, 255, 1);
glowBuffer.colorMode(p.RGB, 255, 255, 255, 1);
fractalNoise = new FBM(6);
precomputeKleinBottle();
};
function precomputeKleinBottle() {
kbPoints = [];
var uSteps = 120;
var vSteps = 80;
var u, v;
for (var i = 0; i <= uSteps; i++) {
kbPoints[i] = [];
u = p.map(i, 0, uSteps, 0, p.TWO_PI);
for (var j = 0; j <= vSteps; j++) {
v = p.map(j, 0, vSteps, 0, p.TWO_PI);
var x4 = computeKlein4D(u, v, 0);
kbPoints[i][j] = x4;
}
}
}
function computeKlein4D(u, v, w4) {
var r = 2;
var k = 0.4;
var cosU = p.cos(u);
var sinU = p.sin(u);
var cosV = p.cos(v);
var sinV = p.sin(v);
var x = r * (cosU + 0.5 * cosV * cosU + 0.5 * sinV * sinU);
var y = r * (sinU + 0.5 * cosV * sinU - 0.5 * sinV * cosU);
var z = r * (sinV * 0.7 + 0.5 * cosV * 0.5);
var ww = w4 * 0.3;
return p.createVector(x, y, z, ww);
}
function recursiveProjection(vec4, depth, angle) {
if (depth <= 0) return vec4;
var rot4Matrix = getRotation4Matrix(angle, depth);
var rotated = rotateVector4(vec4, rot4Matrix);
var projected3D = project4Dto3D(rotated);
var rot3Matrix = getRotation3Matrix(angle * 0.7, depth);
var rotated3 = rotateVector3(projected3D, rot3Matrix);
var projected2D = project3Dto2D(rotated3);
return recursiveProjection(p.createVector(projected2D.x, projected2D.y, projected2D.z, projected3D.z), depth - 1, angle * 1.1);
}
function getRotation4Matrix(angle, axis) {
var c = p.cos(angle);
var s = p.sin(angle);
var m = p.createVector(1, 0, 0, 0);
var m2 = p.createVector(0, 1, 0, 0);
var m3 = p.createVector(0, 0, 1, 0);
var m4 = p.createVector(0, 0, 0, 1);
if (axis % 4 === 1) {
m2.set(c, s, 0, 0);
var temp = p.createVector(0, -s, c, 0);
m3 = temp;
} else if (axis % 4 === 2) {
m.set(c, 0, s, 0);
var temp = p.createVector(-s, 0, c, 0);
m3 = temp;
} else if (axis % 4 === 3) {
m.set(c, 0, 0, s);
var temp = p.createVector(-s, 0, 0, c);
m4 = temp;
}
return { m: m, m2: m2, m3: m3, m4: m4 };
}
function getRotation3Matrix(angle, axis) {
var c = p.cos(angle);
var s = p.sin(angle);
if (axis % 3 === 0) return { a: c, b: -s, c: s, d: c };
if (axis % 3 === 1) return { a: c, b: -s, c: s, d: c };
return { a: c, b: -s, c: s, d: c };
}
function rotateVector4(v, m) {
return p.createVector(
v.x * m.m.x + v.y * m.m2.x + v.z * m.m3.x + v.w * m.m4.x,
v.x * m.m.y + v.y * m.m2.y + v.z * m.m3.y + v.w * m.m4.y,
v.x * m.m.z + v.y * m.m2.z + v.z * m.m3.z + v.w * m.m4.z,
v.x * m.m.w + v.y * m.m2.w + v.z * m.m3.w + v.w * m.m4.w
);
}
function rotateVector3(v, m) {
return p.createVector(
v.x * m.a + v.y * m.b,
v.x * m.c + v.y * m.d,
v.z
);
}
function project4Dto3D(v) {
var scale = 3.0;
var w = 1.0 / (scale - v.w);
return p.createVector(v.x * w, v.y * w, v.z * w);
}
function project3Dto2D(v) {
var perspective = 800;
var scale = perspective / (perspective + v.z * 50);
return p.createVector(v.x * scale * 180, v.y * scale * 180);
}
p.draw = function() {
time += 0.005;
mouseInfluence = p.dist(0, 0, p.mouseX - w / 2, p.mouseY - h / 2) / 300;
drawBackgroundFog();
drawMidgroundGeometry();
drawForegroundLines();
drawGlowEffects();
p.image(bgBuffer, 0, 0);
p.blendMode(p.ADD);
p.image(midBuffer, 0, 0);
p.image(glowBuffer, 0, 0);
p.blendMode(p.BLEND);
p.image(fgBuffer, 0, 0);
if (clickTrigger) {
drawClickBurst();
clickTrigger = false;
}
drawSacredOverlay();
};
function drawBackgroundFog() {
bgBuffer.background(20, 18, 22);
bgBuffer.loadPixels();
var stepSize = 3;
for (var x = 0; x < w; x += stepSize) {
for (var y = 0; y < h; y += stepSize) {
var noise = fractalNoise.noise(x * 0.003 + time * 0.5, y * 0.003, time * 0.3);
var fog = p.map(noise, 0, 1, 15, 35);
var distFromCenter = p.dist(x, y, w / 2, h / 2);
var vignette = p.map(distFromCenter, 0, p.max(w, h) / 1.5, 1, 0.3);
fog *= vignette;
var idx = (x + y * w) * 4;
bgBuffer.pixels[idx] = fog * 0.9;
bgBuffer.pixels[idx + 1] = fog * 0.85;
bgBuffer.pixels[idx + 2] = fog * 0.95;
bgBuffer.pixels[idx + 3] = 1;
}
}
bgBuffer.updatePixels();
}
function drawMidgroundGeometry() {
midBuffer.clear();
var angle = time * 0.3 + mouseInfluence * 0.5;
midBuffer.push();
midBuffer.translate(w / 2, h / 2);
for (var layer = 0; layer < 4; layer++) {
var layerAngle = angle + layer * p.PI / 8;
var opacity = p.map(layer, 0, 4, 0.15, 0.4);
midBuffer.beginShape();
for (var i = 0; i < kbPoints.length; i++) {
for (var j = 0; j < kbPoints[i].length; j++) {
var proj = recursiveProjection(kbPoints[i][j], recursionDepth, layerAngle);
var nx = proj.x + p.sin(time * 2 + layer) * 20 * p.sin(layerAngle);
var ny = proj.y + p.cos(time * 2 + layer) * 20 * p.cos(layerAngle);
var zFade = p.map(proj.z, -1, 1, 0.3, 1);
midBuffer.stroke(255, 255, 255, opacity * zFade);
midBuffer.strokeWeight(0.5);
midBuffer.vertex(nx * 0.6, ny * 0.6);
}
}
midBuffer.endShape();
}
drawHexagonalGrid(midBuffer, angle);
drawPhiSpirals(midBuffer, angle);
midBuffer.pop();
}
function drawHexagonalGrid(buf, angle) {
buf.push();
var hexSize = 40;
for (var ring = 1; ring < 8; ring++) {
var hexCount = 6 * ring;
for (var h = 0; h < hexCount; h++) {
var hexAngle = (h / hexCount) * p.TWO_PI + angle * 0.2;
var radius = ring * hexSize;
var hx = p.cos(hexAngle) * radius;
var hy = p.sin(hexAngle) * radius;
var hexOpacity = p.map(ring, 1, 8, 0.08, 0.02);
drawHexagon(buf, hx, hy, hexSize * 0.4, hexOpacity);
}
}
buf.pop();
}
function drawHexagon(buf, x, y, size, opacity) {
buf.beginShape();
for (var i = 0; i < 6; i++) {
var a = (i / 6) * p.TWO_PI + p.PI / 6;
buf.vertex(x + p.cos(a) * size, y + p.sin(a) * size);
}
buf.endShape(p.CLOSE);
buf.stroke(200, 190, 220, opacity);
buf.strokeWeight(0.3);
}
function drawPhiSpirals(buf, angle) {
buf.push();
var phi = 1.618033988749;
buf.strokeWeight(0.3);
for (var spiral = 0; spiral < 3; spiral++) {
buf.beginShape();
for (var t = 0; t < 200; t++) {
var r = t * 0.8;
var theta = t * 0.1 * phi + angle + spiral * p.TWO_PI / 3;
var sx = r * p.cos(theta);
var sy = r * p.sin(theta);
var spiralOpacity = p.map(t, 0, 200, 0.12, 0.03);
buf.stroke(255, 250, 255, spiralOpacity);
buf.vertex(sx, sy);
}
buf.endShape();
}
buf.pop();
}
function drawForegroundLines() {
fgBuffer.clear();
var angle = time * 0.5;
fgBuffer.push();
fgBuffer.translate(w / 2, h / 2);
for (var i = 0; i < kbPoints.length; i += 3) {
for (var j = 0; j < kbPoints[i].length; j += 3) {
var p1 = recursiveProjection(kbPoints[i][j], recursionDepth, angle);
var p2 = recursiveProjection(kbPoints[i][(j + 3) % kbPoints[i].length], recursionDepth, angle);
var p3 = recursiveProjection(kbPoints[(i + 3) % kbPoints.length][j], recursionDepth, angle);
var dist1 = p.dist(p1.x, p1.y, 0, 0);
var brightness = p.map(dist1, 0, 150, 0.9, 0.1);
var mx = p.map(p.mouseX - w / 2, -w / 2, w / 2, 0.5, 1.5);
var my = p.map(p.mouseY - h / 2, -h / 2, h / 2, 0.5, 1.5);
var mouseScale = (mx + my) / 2;
fgBuffer.strokeWeight(1.5);
fgBuffer.stroke(255, 255, 255, brightness);
fgBuffer.line(p1.x * mouseScale, p1.y * mouseScale, p2.x * mouseScale, p2.y * mouseScale);
if (p.random() > 0.7) {
fgBuffer.strokeWeight(0.5);
fgBuffer.stroke(255, 255, 255, brightness * 0.5);
fgBuffer.bezierVertex(
p1.x * 0.5 + p3.x * 0.5,
p1.y * 0.5 + p3.y * 0.5,
p2.x * 0.5 + p3.x * 0.3,
p2.y * 0.5 + p3.y * 0.3,
p3.x * mouseScale,
p3.y * mouseScale
);
}
}
}
drawRecursionCircles(fgBuffer, angle);
fgBuffer.pop();
}
function drawRecursionCircles(buf, angle) {
buf.push();
var phi = 1.618033988749;
buf.noFill();
for (var c = 0; c < 5; c++) {
var circleRadius = 50 + c * 30;
var circleOpacity = p.map(c, 0, 5, 0.7, 0.1);
buf.strokeWeight(1.2 - c * 0.2);
buf.stroke(255, 255, 255, circleOpacity);
buf.beginShape();
for (var t = 0; t <= 100; t++) {
var theta = (t / 100) * p.TWO_PI;
var r = circleRadius * (1 + 0.1 * p.sin(theta * 5 + angle * (c + 1)));
var cx = r * p.cos(theta) * phi;
var cy = r * p.sin(theta) / phi;
buf.curveVertex(cx, cy);
}
buf.endShape();
}
buf.pop();
}
function drawGlowEffects() {
glowBuffer.clear();
glowBuffer.push();
glowBuffer.translate(w / 2, h / 2);
var glowLayers = 8;
for (var g = 0; g < glowLayers; g++) {
var glowAngle = time * 0.4 + g * p.PI / 16;
var glowOpacity = p.map(g, 0, glowLayers, 0.4, 0.05);
var glowSize = p.map(g, 0, glowLayers, 2, 8);
glowBuffer.noFill();
glowBuffer.stroke(255, 255, 255, glowOpacity);
glowBuffer.strokeWeight(glowSize);
glowBuffer.beginShape();
for (var i = 0; i < kbPoints.length; i++) {
for (var j = 0; j < kbPoints[i].length; j++) {
var proj = recursiveProjection(kbPoints[i][j], recursionDepth, glowAngle);
glowBuffer.curveVertex(proj.x * 0.8, proj.y * 0.8);
}
}
glowBuffer.endShape();
}
drawOrbitingGeometry(glowBuffer, time);
glowBuffer.pop();
glowBuffer.blendMode(p.ADD);
}
function drawOrbitingGeometry(buf, t) {
buf.push();
var orbitCount = 7;
for (var o = 0; o < orbitCount; o++) {
var orbitAngle = t * (0.5 + o * 0.1) + o * p.TWO_PI / orbitCount;
var orbitRadius = 100 + o * 25;
var ox = p.cos(orbitAngle) * orbitRadius;
var oy = p.sin(orbitAngle) * orbitRadius;
var orbOpacity = p.map(o, 0, orbitCount, 0.6, 0.15);
buf.fill(255, 255, 255, orbOpacity * 0.5);
buf.noStroke();
buf.ellipse(ox, oy, 8 - o * 0.5, 8 - o * 0.5);
buf.strokeWeight(0.8);
buf.stroke(255, 255, 255, orbOpacity);
buf.noFill();
buf.ellipse(ox, oy, 20 - o * 1.5, 20 - o * 1.5);
}
buf.pop();
}
function drawClickBurst() {
var burstX = p.mouseX - w / 2;
var burstY = p.mouseY - h / 2;
fgBuffer.push();
fgBuffer.translate(w / 2, h / 2);
fgBuffer.translate(burstX, burstY);
for (var ray = 0; ray < 12; ray++) {
var rayAngle = (ray / 12) * p.TWO_PI;
var rayLength = 100 + p.random(50);
var rayOpacity = 0.8;
fgBuffer.strokeWeight(2);
fgBuffer.stroke(255, 255, 255, rayOpacity);
fgBuffer.line(0, 0, p.cos(rayAngle) * rayLength, p.sin(rayAngle) * rayLength);
}
var rings = 5;
for (var r = 0; r < rings; r++) {
var ringDelay = r * 5;
var ringRadius = 20 + r * 30;
fgBuffer.noFill();
fgBuffer.strokeWeight(2 - r * 0.3);
fgBuffer.stroke(255, 255, 255, 0.7 - r * 0.1);
fgBuffer.ellipse(0, 0, ringRadius * 2, ringRadius * 2);
}
fgBuffer.pop();
}
function drawSacredOverlay() {
p.push();
p.translate(w / 2, h / 2);
var overlayOpacity = 0.05 + 0.02 * p.sin(time * 3);
p.stroke(255, 255, 255, overlayOpacity);
p.strokeWeight(0.5);
p.noFill();
for (var r = 0; r < 6; r++) {
var gridSize = 80 + r * 60;
p.rect(-gridSize, -gridSize, gridSize * 2, gridSize * 2);
}
p.line(-w / 2, 0, w / 2, 0);
p.line(0, -h / 2, 0, h / 2);
p.push();
p.rotate(p.HALF_PI * 0.618033988749);
p.line(-p.max(w, h), 0, p.max(w, h), 0);
p.pop();
p.pop();
}
p.mousePressed = function() {
clickTrigger = true;
};
p.keyPressed = function() {
if (p.key === 'r' || p.key === 'R') {
recursionDepth = (recursionDepth % 3) + 3;
precomputeKleinBottle();
}
if (p.key === 'm' || p.key === 'M') {
modeToggle = (modeToggle + 1) % 3;
}
if (p.key === ' ') {
time = 0;
precomputeKleinBottle();
}
};
p.windowResized = function() {
container = document.getElementById('p5-wrapper');
w = container.offsetWidth;
h = container.offsetHeight;
p.resizeCanvas(w, h);
bgBuffer = p.createGraphics(w, h);
midBuffer = p.createGraphics(w, h);
fgBuffer = p.createGraphics(w, h);
glowBuffer = p.createGraphics(w, h);
precomputeKleinBottle();
};
function FBM(octaves) {
this.octaves = octaves;
this.noise = function(x, y, z) {
var value = 0;
var amplitude = 1;
var frequency = 1;
var maxValue = 0;
for (var o = 0; o < this.octaves; o++) {
value += amplitude * noiseRaw(x * frequency, y * frequency, z * frequency);
maxValue += amplitude;
amplitude *= 0.5;
frequency *= 2;
}
return value / maxValue;
};
function noiseRaw(x, y, z) {
var X = p.floor(x) & 255;
var Y = p.floor(y) & 255;
var Z = p.floor(z) & 255;
x -= p.floor(x);
y -= p.floor(y);
z -= p.floor(z);
var u = fade(x);
var v = fade(y);
var w = fade(z);
var A = p.noisePerm[X] + Y;
var AA = p.noisePerm[A] + Z;
var AB = p.noisePerm[A + 1] + Z;
var B = p.noisePerm[X + 1] + Y;
var BA = p.noisePerm[B] + Z;
var BB = p.noisePerm[B + 1] + Z;
return lerp(
lerp(lerp(grad(p.noisePerm[AA], x, y, z), grad(p.noisePerm[BA], x - 1, y, z), u),
lerp(grad(p.noisePerm[AB], x, y - 1, z), grad(p.noisePerm[BB], x - 1, y - 1, z), u), v),
lerp(lerp(grad(p.noisePerm[AA + 1], x, y, z - 1), grad(p.noisePerm[BA + 1], x - 1, y, z - 1), u),
lerp(grad(p.noisePerm[AB + 1], x, y - 1, z - 1), grad(p.noisePerm[BB + 1], x - 1, y - 1, z - 1), u), v),
w
);
}
function fade(t) {
return t * t * t * (t * (t * 6 - 15) + 10);
}
function lerp(a, b, t) {
return a + t * (b - a);
}
function grad(hash, x, y, z) {
var h = hash & 15;
var u = h < 8 ? x : y;
var v = h < 4 ? y : h === 12 || h === 14 ? x : z;
return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v);
}
}
p.noisePerm = [];
for (var i = 0; i < 512; i++) {
p.noisePerm[i] = i % 256;
}
};
// p5 init stripped
✨ AI 艺术解读
This artwork presents the Klein bottle—an impossible surface that exists only in 4D space—as a luminous sacred geometry structure floating in an infinite void. The recursive dimensional projection creates a sense of peering through higher dimensions, where the form continuously folds through itself in ways that defy Euclidean logic. The sacred geometry overlays (hexagonal grids, golden ratio spirals) suggest ancient mathematical knowledge underlying the structure, while the bright white luminous lines against charcoal fog evoke the transcendence of consciousness beyond physical limitations. The viewer becomes an observer of cosmic architecture, witnessing a simulation of non-euclidean physics rendered through sacred mathematical principles.
📝 补充说明
- Performance optimization: FBM noise uses custom per-pixel implementation instead of p.noise() for speed, step size of 3 pixels for fog computation
- Buffer management: All createGraphics buffers initialized in setup() and reused, never recreated per frame
- 4D rotation matrices implemented with axis-based rotation for proper hyperdimensional transformation effects
- Recursion depth default is 5 levels; pressing R cycles through 3-5 levels to trade visual complexity for frame rate
- Window resize handler reconstructs all buffers and recomputes Klein bottle points to maintain crisp rendering at any size