Excluded the rendering in an own component

This commit is contained in:
2026-02-12 09:13:35 +01:00
parent ea15e66c50
commit cc6997e732
5 changed files with 187 additions and 93 deletions

View File

@@ -11,8 +11,9 @@
<button matButton="filled" (click)="onFractalTypeChange(2)">{{ 'FRACTAL3D.JULIA' | translate }}</button>
</div>
</div>
<div class="canvas-container">
<canvas #renderCanvas></canvas>
</div>
<app-babylon-canvas
[config]="fractalConfig"
[renderCallback]="onRender">
</app-babylon-canvas>
</mat-card-content>
</mat-card>

View File

@@ -1,5 +1,5 @@
import {AfterViewInit, Component, ElementRef, inject, NgZone, OnDestroy, ViewChild} from '@angular/core';
import {ArcRotateCamera, Engine, MeshBuilder, Scene, ShaderMaterial, Vector2, Vector3} from '@babylonjs/core';
import {Component} from '@angular/core';
import {ArcRotateCamera, Camera, ShaderMaterial} 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';
@@ -7,6 +7,7 @@ import {TranslatePipe} from '@ngx-translate/core';
import {AlgorithmInformation} from '../information/information.models';
import {UrlConstants} from '../../../constants/UrlConstants';
import {MatButton} from '@angular/material/button';
import {BabylonCanvas, RenderCallback, RenderConfig} from '../../../shared/rendering/canvas/babylon-canvas.component';
@Component({
selector: 'app-fractal3d',
@@ -17,15 +18,13 @@ import {MatButton} from '@angular/material/button';
MatCardHeader,
MatCardTitle,
TranslatePipe,
MatButton
MatButton,
BabylonCanvas
],
templateUrl: './fractal3d.component.html',
styleUrl: './fractal3d.component.scss',
})
export class Fractal3dComponent implements AfterViewInit, OnDestroy {
readonly ngZone = inject(NgZone);
@ViewChild('renderCanvas') canvasRef!: ElementRef<HTMLCanvasElement>;
export class Fractal3dComponent {
algoInformation: AlgorithmInformation = {
title: 'FRACTAL3D.EXPLANATION.TITLE',
@@ -51,100 +50,35 @@ export class Fractal3dComponent implements AfterViewInit, OnDestroy {
disclaimerListEntry: ['FRACTAL3D.EXPLANATION.DISCLAIMER_1', 'FRACTAL3D.EXPLANATION.DISCLAIMER_2', 'FRACTAL3D.EXPLANATION.DISCLAIMER_3', 'FRACTAL3D.EXPLANATION.DISCLAIMER_4']
};
fractalConfig: RenderConfig = {
mode: '3D',
vertexShader: MANDELBULB_VERTEX,
fragmentShader: MANDELBULB_FRAGMENT,
uniformNames: ["power", "fractalType"]
};
private readonly fractalPower = 8;
private engine!: Engine;
private scene!: Scene;
private shaderMaterial!: ShaderMaterial;
private time = 0;
private triggerCamUpdate = false;
private cameraPosition: number = 3.5;
private oldType = 0;
public currentFractalType = 0;
ngAfterViewInit(): void {
this.ngZone.runOutsideAngular(() => {
this.initBabylon();
});
}
onRender: RenderCallback = (material: ShaderMaterial, camera: Camera) => {
this.time += 0.005;
private initBabylon(): void {
const canvas = this.canvasRef.nativeElement;
this.engine = new Engine(canvas, true);
this.scene = new Scene(this.engine);
if (this.oldType != this.currentFractalType && camera instanceof ArcRotateCamera) {
this.oldType = this.currentFractalType;
camera.radius = this.currentFractalType == 1 ? 15 : 4;
}
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);
material.setFloat("time", this.time);
material.setFloat("power", this.fractalPower);
material.setInt("fractalType", this.currentFractalType);
};
canvas.addEventListener('wheel', (evt: WheelEvent) => {
evt.preventDefault();
}, { passive: false });
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();
}
}
}