-
+ [renderCallback]="onRender"
+ />
diff --git a/src/app/pages/algorithms/fractal3d/fractal3d.component.scss b/src/app/pages/algorithms/fractal3d/fractal3d.component.scss
index daadde6..e69de29 100644
--- a/src/app/pages/algorithms/fractal3d/fractal3d.component.scss
+++ b/src/app/pages/algorithms/fractal3d/fractal3d.component.scss
@@ -1,2 +0,0 @@
-.canvas-container { width: 100%; height: 1000px; }
-canvas { width: 100%; height: 100%; touch-action: none; border-width: 0; border-color: transparent; border-style: hidden; }
diff --git a/src/app/pages/algorithms/fractal3d/fractal3d.component.ts b/src/app/pages/algorithms/fractal3d/fractal3d.component.ts
index 3927dbe..b65351b 100644
--- a/src/app/pages/algorithms/fractal3d/fractal3d.component.ts
+++ b/src/app/pages/algorithms/fractal3d/fractal3d.component.ts
@@ -1,6 +1,6 @@
import {Component} from '@angular/core';
import {ArcRotateCamera, Camera, ShaderMaterial} from '@babylonjs/core';
-import {MANDELBULB_FRAGMENT, MANDELBULB_VERTEX} from './fractal.shader';
+import {MANDELBULB_FRAGMENT, MANDELBULB_VERTEX} from './fractal3d.shader';
import {Information} from '../information/information';
import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from '@angular/material/card';
import {TranslatePipe} from '@ngx-translate/core';
@@ -52,9 +52,10 @@ export class Fractal3dComponent {
fractalConfig: RenderConfig = {
mode: '3D',
+ initialViewSize: 4,
vertexShader: MANDELBULB_VERTEX,
fragmentShader: MANDELBULB_FRAGMENT,
- uniformNames: ["power", "fractalType"]
+ uniformNames: ["time", "power", "fractalType"]
};
private readonly fractalPower = 8;
diff --git a/src/app/pages/algorithms/fractal3d/fractal.shader.ts b/src/app/pages/algorithms/fractal3d/fractal3d.shader.ts
similarity index 100%
rename from src/app/pages/algorithms/fractal3d/fractal.shader.ts
rename to src/app/pages/algorithms/fractal3d/fractal3d.shader.ts
diff --git a/src/app/shared/rendering/canvas/babylon-canvas.component.ts b/src/app/shared/rendering/canvas/babylon-canvas.component.ts
index 92802bb..8eb1fc9 100644
--- a/src/app/shared/rendering/canvas/babylon-canvas.component.ts
+++ b/src/app/shared/rendering/canvas/babylon-canvas.component.ts
@@ -1,8 +1,9 @@
-import {AfterViewInit, Component, ElementRef, inject, Input, NgZone, OnDestroy, ViewChild} from '@angular/core';
+import {AfterViewInit, Component, ElementRef, EventEmitter, inject, Input, NgZone, OnDestroy, Output, ViewChild} from '@angular/core';
import {ArcRotateCamera, Camera, Engine, MeshBuilder, Scene, ShaderMaterial, Vector2, Vector3} from '@babylonjs/core';
export interface RenderConfig {
mode: '2D' | '3D';
+ initialViewSize: number;
vertexShader: string;
fragmentShader: string;
uniformNames: string[];
@@ -24,6 +25,8 @@ export class BabylonCanvas implements AfterViewInit, OnDestroy {
@Input({ required: true }) config!: RenderConfig;
@Input() renderCallback?: RenderCallback;
+ @Output() sceneReady = new EventEmitter();
+
private engine!: Engine;
private scene!: Scene;
private shaderMaterial!: ShaderMaterial;
@@ -57,6 +60,7 @@ export class BabylonCanvas implements AfterViewInit, OnDestroy {
canvas.addEventListener('wheel', (evt: WheelEvent) => evt.preventDefault(), { passive: false });
this.createShaderMaterial();
this.createFullScreenRect();
+ this.sceneReady.emit(this.scene);
this.addRenderLoop(canvas);
this.addResizeHandler();
}
@@ -75,13 +79,12 @@ export class BabylonCanvas implements AfterViewInit, OnDestroy {
cam.mode = Camera.ORTHOGRAPHIC_CAMERA;
const aspect = canvas.width / canvas.height;
- const viewSize = 10;
+ const viewSize = this.config?.initialViewSize ?? 10;
cam.orthoLeft = -viewSize * aspect / 2;
cam.orthoRight = viewSize * aspect / 2;
cam.orthoTop = viewSize / 2;
cam.orthoBottom = -viewSize / 2;
- cam.attachControl(canvas, true, false);
this.camera = cam;
}
@@ -92,12 +95,13 @@ export class BabylonCanvas implements AfterViewInit, OnDestroy {
cam.maxZ = 100;
cam.lowerRadiusLimit = 1.5;
cam.upperRadiusLimit = 20;
+ cam.radius = this.config?.initialViewSize ?? 1;
cam.attachControl(canvas, true);
this.camera = cam;
}
private createFullScreenRect() {
- const plane = MeshBuilder.CreatePlane("plane", {size: 100}, this.scene);
+ const plane = MeshBuilder.CreatePlane("plane", {size: 110}, this.scene);
if (this.config.mode === '3D') {
plane.parent = this.camera;
@@ -120,7 +124,7 @@ export class BabylonCanvas implements AfterViewInit, OnDestroy {
},
{
attributes: ["position", "uv"],
- uniforms: ["time", "resolution", "cameraPosition", "targetPosition", ...this.config.uniformNames]
+ uniforms: ["resolution", "cameraPosition", ...this.config.uniformNames]
}
);
this.shaderMaterial.disableDepthWrite = true;
diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json
index d013a9b..0fa1e57 100644
--- a/src/assets/i18n/de.json
+++ b/src/assets/i18n/de.json
@@ -380,6 +380,7 @@
"FRACTAL": {
"TITLE": "Fraktale",
"ALGORITHM": "Algorithmen",
+ "RESET": "Reset",
"COLOR_SCHEME": "Farbschema",
"MAX_ITERATION": "Maximale Auflösung",
"EXPLANATION": {
@@ -392,7 +393,8 @@
"DISCLAIMER_1": "Unendliche Tiefe: Egal wie weit du hineinzoomst, es erscheinen immer neue, komplexe Strukturen, die dem Ganzen oft ähneln (Selbstähnlichkeit).",
"DISCLAIMER_2": "Fluchtzeit-Algorithmus: Die Farben geben meist an, wie schnell eine Folge einen bestimmten Schwellenwert überschreitet – je schneller, desto 'heißer' oder heller die Farbe.",
"DISCLAIMER_3": "Komplexe Zahlen: Die Berechnung findet nicht in einem normalen Koordinatensystem statt, sondern in der komplexen Ebene mit realen und imaginären Anteilen.",
- "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)."
+ "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).",
+ "DISCLAIMER_BOTTOM": "Grafikkarten rechnen standardmäßig mit 32-Bit Fließkommazahlen (float). Diese haben nur etwa 7 Stellen Genauigkeit. Bei sehr hohem Zoom (> 100.000) ist der Unterschied zwischen zwei Pixeln so winzig, dass die Grafikkarte ihn nicht mehr darstellen kann. Sie berechnet für 10 Pixel nebeneinander exakt denselben Wert -> Du siehst Blöcke oder Treppenstufen."
}
},
"FRACTAL3D": {
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json
index 12df05b..f770896 100644
--- a/src/assets/i18n/en.json
+++ b/src/assets/i18n/en.json
@@ -379,6 +379,7 @@
"FRACTAL": {
"TITLE": "Fractals",
"ALGORITHM": "Algorithms",
+ "RESET": "Reset",
"COLOR_SCHEME": "Color Scheme",
"MAX_ITERATION": "Max. Resolution",
"EXPLANATION": {
@@ -391,9 +392,9 @@
"DISCLAIMER_1": "Infinite Depth: No matter how far you zoom in, new complex structures appear that often resemble the whole (self-similarity).",
"DISCLAIMER_2": "Escape-Time Algorithm: Colors usually represent how quickly a sequence exceeds a certain threshold—the faster it escapes, the 'hotter' or brighter the color.",
"DISCLAIMER_3": "Complex Numbers: Calculations don't happen in a standard coordinate system, but in the complex plane using real and imaginary components.",
- "DISCLAIMER_4": "Computational Load: Since hundreds of calculations are performed for every single pixel, fractals are a classic benchmark for GPU and processor performance."
+ "DISCLAIMER_4": "Computational Load: Since hundreds of calculations are performed for every single pixel, fractals are a classic benchmark for GPU and processor performance.",
+ "DISCLAIMER_BOTTOM": "Graphics cards calculate with 32-bit floating point numbers (float) by default. These only have about 7 digits of accuracy. At very high zoom levels (> 100,000), the difference between two pixels is so tiny that the graphics card can no longer display it. It calculates exactly the same value for 10 pixels next to each other -> you see blocks or stair steps."
}
-
},
"FRACTAL3D": {
"TITLE": "3D Fractals",