Merge pull request 'festuare/fractal3d' (#19) from festuare/fractal3d into main
Some checks failed
Build, Test & Push Frontend / quality-check (push) Failing after 48s
Build, Test & Push Frontend / docker (push) Has been skipped

Reviewed-on: #19
This commit was merged in pull request #19.
This commit is contained in:
2026-02-11 11:09:45 +01:00
13 changed files with 448 additions and 122 deletions

15
package-lock.json generated
View File

@@ -17,9 +17,9 @@
"@angular/material": "~21.1.0",
"@angular/platform-browser": "~21.1.0",
"@angular/router": "~21.1.0",
"@babylonjs/core": "^8.50.5",
"@ngx-translate/core": "~17.0.0",
"@ngx-translate/http-loader": "~17.0.0",
"babylonjs": "^8.50.5",
"inquirer": "^13.2.2",
"rxjs": "~7.8.2",
"swiper": "~12.1.0",
@@ -1150,6 +1150,12 @@
"node": ">=6.9.0"
}
},
"node_modules/@babylonjs/core": {
"version": "8.50.5",
"resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-8.50.5.tgz",
"integrity": "sha512-rrHAYJmsZOuvC6wdNhGNgdn9JlMxBhk30YhBWGPSxYnnUD7/n/U9Pb3a8k0lpTHipbCfjJ+J5r6GdXtPEikhEg==",
"license": "Apache-2.0"
},
"node_modules/@emnapi/core": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz",
@@ -6449,13 +6455,6 @@
}
}
},
"node_modules/babylonjs": {
"version": "8.50.5",
"resolved": "https://registry.npmjs.org/babylonjs/-/babylonjs-8.50.5.tgz",
"integrity": "sha512-r4CvDBY798k0E8FqOrj2pg5If7MJhELACIpQw8r1TT4TXNWNXxlqrNmKtSzxauWFQgankwVbKhe41YA8k+tQMw==",
"hasInstallScript": true,
"license": "Apache-2.0"
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",

View File

@@ -20,9 +20,9 @@
"@angular/material": "~21.1.0",
"@angular/platform-browser": "~21.1.0",
"@angular/router": "~21.1.0",
"@babylonjs/core": "^8.50.5",
"@ngx-translate/core": "~17.0.0",
"@ngx-translate/http-loader": "~17.0.0",
"babylonjs": "^8.50.5",
"inquirer": "^13.2.2",
"rxjs": "~7.8.2",
"swiper": "~12.1.0",

View File

@@ -12,6 +12,7 @@ export const routes: Routes = [
{ path: RouterConstants.IMPRINT.PATH, component: RouterConstants.IMPRINT.COMPONENT},
{ path: RouterConstants.GOL.PATH, component: RouterConstants.GOL.COMPONENT},
{ path: RouterConstants.LABYRINTH.PATH, component: RouterConstants.LABYRINTH.COMPONENT},
{ path: RouterConstants.FRACTAL.PATH, component: RouterConstants.FRACTAL.COMPONENT}
{ path: RouterConstants.FRACTAL.PATH, component: RouterConstants.FRACTAL.COMPONENT},
{ path: RouterConstants.FRACTAL3d.PATH, component: RouterConstants.FRACTAL3d.COMPONENT}
];

View File

@@ -7,6 +7,7 @@ import {SortingComponent} from '../pages/algorithms/sorting/sorting.component';
import {ConwayGolComponent} from '../pages/algorithms/conway-gol/conway-gol.component';
import {LabyrinthComponent} from '../pages/algorithms/pathfinding/labyrinth/labyrinth.component';
import {FractalComponent} from '../pages/algorithms/fractal/fractal.component';
import {Fractal3dComponent} from '../pages/algorithms/fractal3d/fractal3d.component';
export class RouterConstants {
@@ -58,6 +59,12 @@ export class RouterConstants {
COMPONENT: FractalComponent
};
static readonly FRACTAL3d = {
PATH: 'algorithms/fractal3d',
LINK: '/algorithms/fractal3d',
COMPONENT: Fractal3dComponent
};
static readonly IMPRINT = {
PATH: 'imprint',
LINK: '/imprint',

View File

@@ -14,4 +14,7 @@
static readonly JULIA_WIKI = 'https://de.wikipedia.org/wiki/Julia-Menge'
static readonly NEWTON_FRACTAL_WIKI = 'https://de.wikipedia.org/wiki/Newtonfraktal'
static readonly BURNING_SHIP_WIKI = 'https://de.wikipedia.org/wiki/Burning_ship_(Fraktal)'
static readonly MANDELBULB_WIKI = 'https://de.wikipedia.org/wiki/Mandelknolle'
static readonly MANDELBOX_WIKI = 'https://de.wikipedia.org/wiki/Mandelbox'
static readonly JULIA3D_WIKI = 'https://de.wikipedia.org/wiki/Mandelknolle'
}

View File

@@ -0,0 +1,220 @@
export const MANDELBULB_VERTEX = /* glsl */`
precision highp float;
attribute vec3 position;
attribute vec2 uv;
varying vec2 vUV;
void main(void) {
gl_Position = vec4(position, 1.0);
vUV = uv;
}
`;
export const MANDELBULB_FRAGMENT = /* glsl */`
precision highp float;
uniform float time;
uniform vec2 resolution;
uniform vec3 cameraPosition;
uniform vec3 targetPosition;
uniform float power;
uniform int fractalType; // 0 = Bulb, 1 = Box, 2 = Julia
// --- Palettes ---
vec3 palette( in float t, in vec3 a, in vec3 b, in vec3 c, in vec3 d ) {
return a + b*cos( 6.28318*(c*t+d) );
}
// Global trap for coloring
float minTrap = 1000.0;
// --- Shape 1: Mandelbulb ---
float mapMandelbulb(vec3 pos, out float trap) {
vec3 z = pos;
float dr = 1.0;
float r = 0.0;
trap = 1000.0;
for (int i = 0; i < 8; i++) {
r = length(z);
if (r > 100.0) break;
trap = min(trap, r);
float theta = acos(z.y / r);
float phi = atan(z.z, z.x);
dr = pow(r, power - 1.0) * power * dr + 1.0;
float zr = pow(r, power);
theta = theta * power;
phi = phi * power;
z = zr * vec3(sin(theta) * cos(phi), cos(theta), sin(theta) * sin(phi));
z += pos;
}
return 0.5 * log(r) * r / dr;
}
// --- Shape 2: Mandelbox ---
float mapMandelbox(vec3 pos, out float trap) {
vec3 z = pos;
float dr = 1.0;
float scale = 2.8; // Fixed scale for good look
trap = 1000.0;
for (int i = 0; i < 15; i++) {
// Box fold
z = clamp(z, -1.0, 1.0) * 2.0 - z;
// Sphere fold
float r2 = dot(z, z);
trap = min(trap, r2); // Trap based on sphere fold
if (r2 < 0.25) {
z = z * 4.0;
dr = dr * 4.0;
} else if (r2 < 1.0) {
z = z / r2;
dr = dr / r2;
}
z = z * scale + pos;
dr = dr * abs(scale) + 1.0;
}
return (length(z) - abs(scale - 1.0)) / dr;
}
// --- Shape 3: Julia Bulb ---
float mapJulia(vec3 pos, out float trap) {
vec3 z = pos;
float dr = 1.0;
float r = 0.0;
trap = 1000.0;
// Constant C for Julia set (animating slightly makes it alive)
vec3 c = vec3(0.35, 0.45, -0.1) + vec3(sin(time*0.1)*0.2);
for (int i = 0; i < 8; i++) {
r = length(z);
if (r > 100.0) break; // Higher escape radius for Julia
trap = min(trap, r);
float theta = acos(z.y / r);
float phi = atan(z.z, z.x);
dr = pow(r, power - 1.0) * power * dr + 1.0;
float zr = pow(r, power);
theta = theta * power;
phi = phi * power;
z = zr * vec3(sin(theta) * cos(phi), cos(theta), sin(theta) * sin(phi));
z += c; // Add C instead of pos
}
return 0.5 * log(r) * r / dr;
}
// --- Main Map Dispatcher ---
float map(vec3 pos) {
float d = 0.0;
float currentTrap = 0.0;
if (fractalType == 1) {
d = mapMandelbox(pos, currentTrap);
} else if (fractalType == 2) {
d = mapJulia(pos, currentTrap);
} else {
d = mapMandelbulb(pos, currentTrap);
}
minTrap = currentTrap; // Update global
return d;
}
// --- Raymarching ---
bool intersectSphere(vec3 ro, vec3 rd, vec3 c, float r, out float t0, out float t1) {
vec3 oc = ro - c;
float b = dot(oc, rd);
float c2 = dot(oc, oc) - r * r;
float h = b*b - c2;
if (h < 0.0) return false;
h = sqrt(h);
t0 = -b - h;
t1 = -b + h;
return true;
}
float raymarch(vec3 ro, vec3 rd) {
// Bounding sphere around fractal center (here: origin)
vec3 center = vec3(0.0);
float radius = 6.0;
float tEnter, tExit;
if (!intersectSphere(ro, rd, center, radius, tEnter, tExit)) {
return -1.0;
}
float t = max(tEnter, 0.0);
float tMax = tExit;
for (int i = 0; i < 128; i++) {
vec3 pos = ro + t * rd;
float d = map(pos);
// distance-based epsilon is more stable for zoom-out
float eps = max(0.001, 0.0005 * t);
if (d < eps) return t;
t += d * 0.8; // safety factor against overshoot
if (t > tMax) break;
}
return -1.0;
}
vec3 getNormal(vec3 p) {
float d = map(p);
vec2 e = vec2(0.001, 0.0);
return normalize(vec3(
d - map(p - e.xyy),
d - map(p - e.yxy),
d - map(p - e.yyx)
));
}
void main(void) {
vec2 uv = (gl_FragCoord.xy - 0.5 * resolution.xy) / resolution.y;
vec3 ro = cameraPosition;
vec3 ta = targetPosition;
vec3 fwd = normalize(ta - ro);
vec3 right = normalize(cross(vec3(0.0, 1.0, 0.0), fwd));
vec3 up = normalize(cross(fwd, right));
vec3 rd = normalize(fwd + uv.x * right + uv.y * up);
vec3 color = vec3(0.1);
float t = raymarch(ro, rd);
if(t > 0.0) {
vec3 pos = ro + t * rd;
vec3 nor = getNormal(pos);
// Different colors for different shapes
vec3 colParamsA = vec3(0.5, 0.5, 0.5);
vec3 colParamsB = vec3(0.5, 0.5, 0.5);
vec3 colParamsC = vec3(1.0, 1.0, 1.0);
vec3 colParamsD = vec3(0.80, 0.90, 0.30);
if (fractalType == 1) { // Box: Sci-Fi Blue/Grey
colParamsD = vec3(0.0, 0.1, 0.2);
}
if (fractalType == 2) { // Julia: Alien Green/Purple
colParamsD = vec3(0.8, 0.0, 0.2);
}
vec3 materialColor = palette(minTrap, colParamsA, colParamsB, colParamsC, colParamsD);
float camLight = max(0.0, dot(nor, -rd));
float ambient = 0.4;
vec3 lighting = vec3(1.0) * (camLight * 0.7 + ambient);
color = materialColor * lighting;
}
color = pow(color, vec3(0.8));
gl_FragColor = vec4(color, 1.0);
}
`;

View File

@@ -1 +1,18 @@
<p>fractal3d works!</p>
<mat-card class="container">
<mat-card-header>
<mat-card-title>{{ 'FRACTAL3D.TITLE' | translate }}</mat-card-title>
</mat-card-header>
<mat-card-content>
<app-information [algorithmInformation]="algoInformation"/>
<div class="controls-container">
<div class="controls-panel">
<button matButton="filled" (click)="onFractalTypeChange(0)">{{ 'FRACTAL3D.MANDELBULB' | translate }}</button>
<button matButton="filled" (click)="onFractalTypeChange(1)">{{ 'FRACTAL3D.MANDELBOX' | translate }}</button>
<button matButton="filled" (click)="onFractalTypeChange(2)">{{ 'FRACTAL3D.JULIA' | translate }}</button>
</div>
</div>
<div class="canvas-container">
<canvas #renderCanvas></canvas>
</div>
</mat-card-content>
</mat-card>

View File

@@ -0,0 +1,2 @@
.canvas-container { width: 100%; height: 1000px; }
canvas { width: 100%; height: 100%; touch-action: none; border-width: 0; border-color: transparent; border-style: hidden; }

View File

@@ -1,11 +1,146 @@
import { Component } from '@angular/core';
import {AfterViewInit, Component, ElementRef, inject, NgZone, OnDestroy, ViewChild} from '@angular/core';
import {ArcRotateCamera, Engine, MeshBuilder, Scene, ShaderMaterial, Vector2, Vector3} from '@babylonjs/core';
import {MANDELBULB_FRAGMENT, MANDELBULB_VERTEX} from './fractal.shader';
import {Information} from '../information/information';
import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from '@angular/material/card';
import {TranslatePipe} from '@ngx-translate/core';
import {AlgorithmInformation} from '../information/information.models';
import {UrlConstants} from '../../../constants/UrlConstants';
import {MatButton} from '@angular/material/button';
@Component({
selector: 'app-fractal3d',
imports: [],
imports: [
Information,
MatCard,
MatCardContent,
MatCardHeader,
MatCardTitle,
TranslatePipe,
MatButton
],
templateUrl: './fractal3d.component.html',
styleUrl: './fractal3d.component.scss',
})
export class Fractal3dComponent {
export class Fractal3dComponent implements AfterViewInit, OnDestroy {
readonly ngZone = inject(NgZone);
@ViewChild('renderCanvas') canvasRef!: ElementRef<HTMLCanvasElement>;
algoInformation: AlgorithmInformation = {
title: 'FRACTAL3D.EXPLANATION.TITLE',
entries: [
{
name: 'Mandel-Bulb',
description: 'FRACTAL3D.EXPLANATION.MANDELBULB_EXPLANATION',
link: UrlConstants.MANDELBULB_WIKI
},
{
name: 'Mandelbox',
description: 'FRACTAL3D.EXPLANATION.MANDELBOX_EXPLANATION',
link: UrlConstants.MANDELBOX_WIKI
},
{
name: 'Julia-Bulb',
description: 'FRACTAL3D.EXPLANATION.JULIA_EXPLANATION',
link: UrlConstants.JULIA3D_WIKI
}
],
disclaimer: 'FRACTAL3D.EXPLANATION.DISCLAIMER',
disclaimerBottom: '',
disclaimerListEntry: ['FRACTAL3D.EXPLANATION.DISCLAIMER_1', 'FRACTAL3D.EXPLANATION.DISCLAIMER_2', 'FRACTAL3D.EXPLANATION.DISCLAIMER_3', 'FRACTAL3D.EXPLANATION.DISCLAIMER_4']
};
private readonly fractalPower = 8;
private engine!: Engine;
private scene!: Scene;
private shaderMaterial!: ShaderMaterial;
private time = 0;
private triggerCamUpdate = false;
private cameraPosition: number = 3.5;
public currentFractalType = 0;
ngAfterViewInit(): void {
this.ngZone.runOutsideAngular(() => {
this.initBabylon();
});
}
private initBabylon(): void {
const canvas = this.canvasRef.nativeElement;
this.engine = new Engine(canvas, true);
this.scene = new Scene(this.engine);
const camera = new ArcRotateCamera("Camera", 0, Math.PI / 2, 4, Vector3.Zero(), this.scene);
camera.wheelPrecision = 100;
camera.minZ = 0.1;
camera.maxZ = 100;
camera.lowerRadiusLimit = 1.5;
camera.upperRadiusLimit = 20;
camera.attachControl(this.canvasRef.nativeElement, true);
const plane = MeshBuilder.CreatePlane("plane", { size: 10 }, this.scene);
plane.parent = camera;
plane.position.z = 1;
plane.alwaysSelectAsActiveMesh = true;
this.shaderMaterial = new ShaderMaterial(
"mandelbulbShader",
this.scene,
{
vertexSource: MANDELBULB_VERTEX,
fragmentSource: MANDELBULB_FRAGMENT
},
{
attributes: ["position", "uv"],
uniforms: ["time", "resolution", "cameraPosition", "targetPosition", "power", "fractalType"]
}
);
this.shaderMaterial.disableDepthWrite = true;
this.shaderMaterial.backFaceCulling = false;
plane.material = this.shaderMaterial;
this.engine.runRenderLoop(() => {
this.time += 0.005;
if (this.triggerCamUpdate)
{
this.triggerCamUpdate = false;
camera.radius = this.cameraPosition;
}
if (this.shaderMaterial) {
this.shaderMaterial.setFloat("time", this.time);
this.shaderMaterial.setVector2("resolution", new Vector2(canvas.width, canvas.height));
this.shaderMaterial.setVector3("cameraPosition", camera.position);
this.shaderMaterial.setVector3("targetPosition", camera.target);
this.shaderMaterial.setFloat("power", this.fractalPower);
this.shaderMaterial.setInt("fractalType", this.currentFractalType);
}
this.scene.render();
});
window.addEventListener('resize', () => this.engine.resize());
}
onFractalTypeChange(type: number): void {
this.currentFractalType = type;
if (type === 0 ||type === 2)
{
this.cameraPosition = 4;
}
else {
this.cameraPosition = 15;
}
this.triggerCamUpdate = true;
}
ngOnDestroy(): void {
if (this.engine) {
this.engine.dispose();
}
}
}

View File

@@ -1,108 +0,0 @@
const mandelbulbFragmentShader = `
precision highp float;
// Uniforms (Werte von der CPU)
uniform float time;
uniform vec2 resolution;
uniform vec3 cameraPosition;
uniform vec3 targetPosition;
uniform float power; // Die "Potenz" des Fraktals (z.B. 8.0)
// Hilfsfunktion: Rotation
mat2 rot(float a) {
float s = sin(a), c = cos(a);
return mat2(c, -s, s, c);
}
// --- Distance Estimator (Mandelbulb) ---
float map(vec3 pos) {
vec3 z = pos;
float dr = 1.0;
float r = 0.0;
// Die Fraktal-Iteration
for (int i = 0; i < 8; i++) {
r = length(z);
if (r > 2.0) break;
// Konvertierung in Polarkoordinaten
float theta = acos(z.y / r);
float phi = atan(z.z, z.x);
dr = pow(r, power - 1.0) * power * dr + 1.0;
// Skalieren und Rotieren (Power)
float zr = pow(r, power);
theta = theta * power;
phi = phi * power;
// Zurück zu Kartesischen Koordinaten
z = zr * vec3(sin(theta) * cos(phi), cos(theta), sin(theta) * sin(phi));
// Den ursprünglichen Punkt addieren (wie beim Mandelbrot z = z^2 + c)
z += pos;
}
return 0.5 * log(r) * r / dr;
}
// --- Raymarching ---
float raymarch(vec3 ro, vec3 rd) {
float t = 0.0;
for(int i = 0; i < 100; i++) {
vec3 pos = ro + t * rd;
float d = map(pos);
if(d < 0.001) return t; // Getroffen!
if(t > 10.0) break; // Zu weit weg
t += d;
}
return -1.0; // Nichts getroffen
}
// --- Normalenberechnung für Licht ---
vec3 getNormal(vec3 p) {
float d = map(p);
vec2 e = vec2(0.001, 0.0);
return normalize(vec3(
d - map(p - e.xyy),
d - map(p - e.yxy),
d - map(p - e.yyx)
));
}
void main(void) {
// UV Koordinaten zentrieren (-1 bis 1) und Aspekt korrigieren
vec2 uv = (gl_FragCoord.xy - 0.5 * resolution.xy) / resolution.y;
// Kamera Setup (LookAt)
vec3 ro = cameraPosition; // Ray Origin
vec3 ta = targetPosition; // Target LookAt
vec3 fwd = normalize(ta - ro);
vec3 right = normalize(cross(vec3(0,1,0), fwd));
vec3 up = normalize(cross(fwd, right));
vec3 rd = normalize(fwd + uv.x * right + uv.y * up); // Ray Direction
// Rendern
float t = raymarch(ro, rd);
vec3 color = vec3(0.0); // Hintergrund Schwarz
if(t > 0.0) {
vec3 pos = ro + t * rd;
vec3 nor = getNormal(pos);
// Einfaches Licht (Phong)
vec3 lightDir = normalize(vec3(1.0, 1.0, -1.0));
float diff = max(dot(nor, lightDir), 0.0);
float amb = 0.2; // Ambient
// Farbe basierend auf Position (gibt diesen Alien-Look)
vec3 baseColor = vec3(0.5) + 0.5 * cos(vec3(0.0, 0.4, 0.8) + length(pos) * 2.0);
color = baseColor * (diff + amb);
}
gl_FragColor = vec4(color, 1.0);
}
`;

View File

@@ -38,6 +38,12 @@ export class AlgorithmsService {
title: 'ALGORITHM.FRACTAL.TITLE',
description: 'ALGORITHM.FRACTAL.DESCRIPTION',
routerLink: RouterConstants.FRACTAL.LINK
},
{
id: 'fractal3d',
title: 'ALGORITHM.FRACTAL3D.TITLE',
description: 'ALGORITHM.FRACTAL3D.DESCRIPTION',
routerLink: RouterConstants.FRACTAL3d.LINK
}
];

View File

@@ -395,6 +395,24 @@
"DISCLAIMER_4": "Rechenintensität: Da für jeden Pixel hunderte Berechnungen durchgeführt werden, sind Fraktale ein klassischer Benchmark für die Performance von Grafikprozessoren (GPUs)."
}
},
"FRACTAL3D": {
"TITLE": "3D Fraktale",
"ALGORITHM": "Algorithmen",
"MANDELBULB": "Mandelbulb",
"MANDELBOX": "Mandelbox",
"JULIA": "Julia",
"EXPLANATION": {
"TITLE": "3D Fraktale Welten",
"MANDELBULB_EXPLANATION": "gilt als der 'Heilige Gral' der 3D-Fraktale. Da komplexe Zahlen nur zweidimensional sind, nutzt dieses Fraktal sphärische Koordinaten und hohe Potenzen (meist v^8 + c), um die Mandelbrot-Menge in den Raum zu projizieren. Vorteil: Es entsteht eine organische, extrem detaillierte Struktur, die an Pflanzen, Korallen oder außerirdische Landschaften erinnert.",
"MANDELBOX_EXPLANATION": "basiert nicht auf glatten Kurven, sondern auf geometrischem 'Falten' und Skalieren (Box-Folding & Sphere-Folding). Der Raum wird wie Papier immer wieder gefaltet und gespiegelt. Vorteil: Erzeugt streng geometrische, mechanisch wirkende Strukturen, die wie endlose futuristische Städte, der Borg-Würfel oder komplexe Sci-Fi-Architektur aussehen.",
"JULIA_EXPLANATION": "ist das 3D-Pendant zur 2D-Julia-Menge. Während der Mandelbulb eine 'Karte' aller Fraktale ist, fixiert man hier den Parameter 'c' und variiert den Startpunkt zudem variiert es mit der Zeit. Vorteil: Anders als der massive Mandelbulb sind Julia-Bulbs oft hohle, komplexe Tunnelsysteme oder blasenartige Strukturen, die sich perfekt eignen, um mit der Kamera hindurchzufliegen.",
"DISCLAIMER": "Diese Visualisierung nutzt eine Technik namens 'Raymarching' (Sphere Tracing). Das bedeutet:",
"DISCLAIMER_1": "Keine Polygone: Es gibt keine Dreiecke oder Gitter. Die Form wird rein mathematisch für jeden Pixel in Echtzeit berechnet.",
"DISCLAIMER_2": "Distance Estimation: Der Algorithmus 'tastet' sich mit Lichtstrahlen voran, indem er berechnet, wie weit das nächste Objekt entfernt ist, ohne es sofort zu berühren.",
"DISCLAIMER_3": "Unendliche Details: Da die Oberfläche mathematisch definiert ist, verpixelt sie nicht beim Zoom es erscheinen immer neue Strukturen.",
"DISCLAIMER_4": "Licht & Schatten: Um die Tiefe sichtbar zu machen, werden Lichtreflexionen und Schatten (Ambient Occlusion) basierend auf der Krümmung der Formel simuliert."
}
},
"ALGORITHM": {
"TITLE": "Algorithmen",
"PATHFINDING": {
@@ -417,6 +435,10 @@
"TITLE": "Fraktale",
"DESCRIPTION": "Visualisierung von komplexe, geometrische Mustern, die sich selbst in immer kleineren Maßstäben ähneln (Selbstähnlichkeit)."
},
"FRACTAL3D": {
"TITLE": "Fraktale 3D",
"DESCRIPTION": "3D-Visualisierung von komplexe, geometrische Mustern, die sich selbst in immer kleineren Maßstäben ähneln (Selbstähnlichkeit)."
},
"NOTE": "HINWEIS",
"GRID_HEIGHT": "Höhe",
"GRID_WIDTH": "Beite"

View File

@@ -395,6 +395,24 @@
}
},
"FRACTAL3D": {
"TITLE": "3D Fractals",
"ALGORITHM": "Algorithms",
"MANDELBULB": "Mandelbulb",
"MANDELBOX": "Mandelbox",
"JULIA": "Julia",
"EXPLANATION": {
"TITLE": "3D Fractal Worlds",
"MANDELBULB_EXPLANATION": "is considered the 'Holy Grail' of 3D fractals. Since complex numbers are only two-dimensional, this fractal uses spherical coordinates and high powers (usually v^8 + c) to project the Mandelbrot set into 3D space. Benefit: Creates an organic, extremely detailed structure reminiscent of plants, coral reefs, or alien landscapes.",
"MANDELBOX_EXPLANATION": "is based not on smooth curves, but on geometric 'folding' and scaling (Box-Folding & Sphere-Folding). Space is repeatedly folded and mirrored like origami. Benefit: Produces strictly geometric, mechanical-looking structures that resemble endless futuristic cities, the Borg cube, or complex sci-fi architecture.",
"JULIA_EXPLANATION": "is the 3D counterpart to the 2D Julia set. While the Mandelbulb is a 'map' of all fractals, here we fix the parameter 'c' and vary the starting point and it changes over time. Benefit: Unlike the solid Mandelbulb, Julia Bulbs are often hollow, forming complex tunnel systems or bubble-like structures perfect for flying through with the camera.",
"DISCLAIMER": "This visualization uses a technique called 'Raymarching' (Sphere Tracing). This means:",
"DISCLAIMER_1": "No Polygons: There are no triangles or meshes. The shape is calculated mathematically for every pixel in real-time.",
"DISCLAIMER_2": "Distance Estimation: The algorithm 'marches' light rays forward by calculating the safe distance to the nearest object without hitting it immediately.",
"DISCLAIMER_3": "Infinite Detail: Since the surface is mathematically defined, it never pixelates when zooming in new structures always emerge.",
"DISCLAIMER_4": "Light & Shadow: To visualize depth, light reflections and shadows (Ambient Occlusion) are simulated based on the curvature of the formula."
}
},
"ALGORITHM": {
"TITLE": "Algorithms",
"PATHFINDING": {
@@ -417,6 +435,10 @@
"TITLE": "Fractals",
"DESCRIPTION": "Visualisation of complex geometric patterns that resemble each other on increasingly smaller scales (self-similarity)."
},
"FRACTAL3D": {
"TITLE": "Fractals 3D",
"DESCRIPTION": "3D Visualisation of complex geometric patterns that resemble each other on increasingly smaller scales (self-similarity)."
},
"NOTE": "Note",
"GRID_HEIGHT": "Height",
"GRID_WIDTH": "Width"