From 598013a7d0a830353fef297bd1752a3204b64e6a Mon Sep 17 00:00:00 2001 From: Lobo Date: Sat, 21 Feb 2026 09:46:55 +0100 Subject: [PATCH] Rendeirng problems fixed Problem was broken uv coordinates in the fragment shader --- .../algorithms/pendulum/pendulum.component.ts | 56 ++++----- .../algorithms/pendulum/pendulum.shader.ts | 115 +++++++----------- 2 files changed, 70 insertions(+), 101 deletions(-) diff --git a/src/app/pages/algorithms/pendulum/pendulum.component.ts b/src/app/pages/algorithms/pendulum/pendulum.component.ts index 572474a..ebfb083 100644 --- a/src/app/pages/algorithms/pendulum/pendulum.component.ts +++ b/src/app/pages/algorithms/pendulum/pendulum.component.ts @@ -1,7 +1,7 @@ import {Component} from '@angular/core'; import {BabylonCanvas, RenderConfig, SceneReadyEvent} from '../../../shared/rendering/canvas/babylon-canvas.component'; import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from '@angular/material/card'; -import {ComputeShader, ShaderLanguage, StorageBuffer, UniformBuffer} from '@babylonjs/core'; +import {ComputeShader, ShaderLanguage, StorageBuffer} from '@babylonjs/core'; import {PENDULUM_FRAGMENT_SHADER_WGSL, PENDULUM_PHYSIC_COMPUTE_SHADER_WGSL, PENDULUM_RENDER_COMPUTE_SHADER_WGSL, PENDULUM_VERTEX_SHADER_WGSL} from './pendulum.shader'; @Component({ @@ -25,7 +25,7 @@ export class PendulumComponent { vertexShader: PENDULUM_VERTEX_SHADER_WGSL, fragmentShader: PENDULUM_FRAGMENT_SHADER_WGSL, uniformNames: [], - uniformBufferNames: ["params"] + uniformBufferNames: [] }; onSceneReady(event: SceneReadyEvent) { @@ -38,24 +38,17 @@ export class PendulumComponent { const height = engine.getRenderHeight(); const totalPixels = width * height; + // Buffer 1: Die Pixel (Bild) const pixelBuffer = new StorageBuffer(engine, totalPixels * 4); + // Buffer 2: Physik-Status const stateBuffer = new StorageBuffer(engine, 4 * 4); stateBuffer.update(new Float32Array([Math.PI / 4, Math.PI / 2, 0, 0])); - const ubo = new UniformBuffer(engine); - ubo.addUniform("resolution", 2); - ubo.addUniform("time", 1); - ubo.addUniform("dt", 1); - ubo.addUniform("g", 1); - ubo.addUniform("m1", 1); - ubo.addUniform("m2", 1); - ubo.addUniform("l1", 1); - ubo.addUniform("l2", 1); - ubo.addUniform("damping", 1); - ubo.addUniform("pad1", 1); - ubo.addUniform("pad2", 1); - ubo.update(); + // Buffer 3: Parameter (DER NEUE, ABSOLUT SICHERE WEG) + // Wir reservieren Platz für 10 Floats. + const paramsBuffer = new StorageBuffer(engine, 10 * 4); + const paramsData = new Float32Array(10); const csPhysics = new ComputeShader("physics", engine, { computeSource: PENDULUM_PHYSIC_COMPUTE_SHADER_WGSL @@ -66,7 +59,7 @@ export class PendulumComponent { } }); csPhysics.setStorageBuffer("state", stateBuffer); - csPhysics.setUniformBuffer("p", ubo); + csPhysics.setStorageBuffer("p", paramsBuffer); // Nutzen jetzt StorageBuffer const csRender = new ComputeShader("render", engine, { computeSource: PENDULUM_RENDER_COMPUTE_SHADER_WGSL @@ -78,40 +71,39 @@ export class PendulumComponent { } }); csRender.setStorageBuffer("pixelBuffer", pixelBuffer); - csRender.setUniformBuffer("p", ubo); + csRender.setStorageBuffer("p", paramsBuffer); csRender.setStorageBuffer("state", stateBuffer); + // Material Setup const plane = scene.getMeshByName("plane"); if (plane?.material) { const mat = plane.material as any; mat.setStorageBuffer("pixelBuffer", pixelBuffer); - mat.setUniformBuffer("params", ubo); + mat.setStorageBuffer("paramsBuffer", paramsBuffer); // Auch hier StorageBuffer } let time = 0; const dt = 0.015; - // Du hast die Physik wieder drin gelassen, das ist super: scene.onBeforeRenderObservable.add(() => { time += dt; const currentWidth = engine.getRenderWidth(); const currentHeight = engine.getRenderHeight(); - ubo.updateFloat2("resolution", currentWidth, currentHeight); - ubo.updateFloat("time", time); - ubo.updateFloat("dt", dt); - ubo.updateFloat("g", 9.81); - ubo.updateFloat("m1", 2.0); - ubo.updateFloat("m2", 1.0); - ubo.updateFloat("l1", 1.5); - ubo.updateFloat("l2", 1.2); - ubo.updateFloat("damping", 0.99); - ubo.updateFloat("pad1", 0); - ubo.updateFloat("pad2", 0); - ubo.update(); + paramsData[0] = currentWidth; + paramsData[1] = currentHeight; + paramsData[2] = time; + paramsData[3] = dt; + paramsData[4] = 9.81; // g + paramsData[5] = 2.0; // m1 + paramsData[6] = 1.0; // m2 + paramsData[7] = 1.5; // l1 + paramsData[8] = 1.2; // l2 + paramsData[9] = 0.99; // damping + + paramsBuffer.update(paramsData); - // Physik Dispatch an csPhysics.dispatch(1, 1, 1); const totalPixels = currentWidth * currentHeight; diff --git a/src/app/pages/algorithms/pendulum/pendulum.shader.ts b/src/app/pages/algorithms/pendulum/pendulum.shader.ts index a5fd52f..e974ded 100644 --- a/src/app/pages/algorithms/pendulum/pendulum.shader.ts +++ b/src/app/pages/algorithms/pendulum/pendulum.shader.ts @@ -13,35 +13,36 @@ `; export const PENDULUM_FRAGMENT_SHADER_WGSL = ` - varying vUV : vec2; + varying vUV : vec2; // Lassen wir stehen, damit der Vertex-Shader nicht meckert var pixelBuffer : array; - var params : Params; // Zurück zum bewährten Struct! - - struct Params { - resolution: vec2, - time: f32, - dt: f32, - g: f32, - m1: f32, - m2: f32, - l1: f32, - l2: f32, - damping: f32, - pad1: f32, - pad2: f32 - }; + var paramsBuffer : array; @fragment fn main(input : FragmentInputs) -> FragmentOutputs { - let width = u32(params.resolution.x); - let height = u32(params.resolution.y); + let width = u32(paramsBuffer[0]); + let height = u32(paramsBuffer[1]); - // clamp schützt uns vor Abstürzen durch Rundungsfehler am Bildschirmrand - let x = clamp(u32(input.vUV.x * params.resolution.x), 0u, width - 1u); - let y = clamp(u32(input.vUV.y * params.resolution.y), 0u, height - 1u); + if (width == 0u || height == 0u) { + fragmentOutputs.color = vec4(0.5, 0.0, 0.0, 1.0); + return fragmentOutputs; + } + + // ============================================================== + // DER MAGISCHE TRICK: Wir ignorieren die kaputten UV-Koordinaten! + // input.position enthält die exakten Bildschirm-Pixelkoordinaten + // (z.B. x geht von 0 bis 1000, y geht von 0 bis 1000). + // Damit lesen wir den Puffer 1:1 auf Pixel-Ebene aus! + // ============================================================== + let x = u32(input.position.x); + let y = u32(input.position.y); + + // Sicherheits-Check, damit wir nicht außerhalb des Buffers lesen + if (x >= width || y >= height) { + fragmentOutputs.color = vec4(0.0, 0.0, 0.0, 1.0); + return fragmentOutputs; + } let index = y * width + x; - let val = pixelBuffer[index]; var color = vec3(0.1, 0.1, 0.15); @@ -62,21 +63,7 @@ export const PENDULUM_PHYSIC_COMPUTE_SHADER_WGSL = ` }; @group(0) @binding(0) var state : State; - @group(0) @binding(1) var p : Params; - - struct Params { - resolution: vec2, - time: f32, - dt: f32, - g: f32, - m1: f32, - m2: f32, - l1: f32, - l2: f32, - damping: f32, - pad1: f32, // <-- Alignment - pad2: f32 // <-- Alignment - }; + @group(0) @binding(1) var p : array; @compute @workgroup_size(1) fn main() { @@ -85,11 +72,13 @@ export const PENDULUM_PHYSIC_COMPUTE_SHADER_WGSL = ` let v1 = state.v1; let v2 = state.v2; - let m1 = p.m1; - let m2 = p.m2; - let l1 = p.l1; - let l2 = p.l2; - let g = p.g; + let dt = p[3]; + let g = p[4]; + let m1 = p[5]; + let m2 = p[6]; + let l1 = p[7]; + let l2 = p[8]; + let damping = p[9]; let num1 = -g * (2.0 * m1 + m2) * sin(t1) - m2 * g * sin(t1 - 2.0 * t2) @@ -101,13 +90,13 @@ export const PENDULUM_PHYSIC_COMPUTE_SHADER_WGSL = ` let den2 = l2 * (2.0 * m1 + m2 - m2 * cos(2.0 * t1 - 2.0 * t2)); let a2 = num2 / den2; - let new_v1 = (v1 + a1 * p.dt) * p.damping; - let new_v2 = (v2 + a2 * p.dt) * p.damping; + let new_v1 = (v1 + a1 * dt) * damping; + let new_v2 = (v2 + a2 * dt) * damping; state.v1 = new_v1; state.v2 = new_v2; - state.theta1 = t1 + new_v1 * p.dt; - state.theta2 = t2 + new_v2 * p.dt; + state.theta1 = t1 + new_v1 * dt; + state.theta2 = t2 + new_v2 * dt; } `; @@ -120,23 +109,9 @@ export const PENDULUM_RENDER_COMPUTE_SHADER_WGSL = ` }; @group(0) @binding(0) var pixelBuffer : array; - @group(0) @binding(1) var p : Params; + @group(0) @binding(1) var p : array; @group(0) @binding(2) var state : State; - struct Params { - resolution: vec2, - time: f32, - dt: f32, - g: f32, - m1: f32, - m2: f32, - l1: f32, - l2: f32, - damping: f32, - pad1: f32, - pad2: f32 - }; - fn sdSegment(p: vec2, a: vec2, b: vec2) -> f32 { let pa = p - a; let ba = b - a; @@ -147,21 +122,23 @@ export const PENDULUM_RENDER_COMPUTE_SHADER_WGSL = ` @compute @workgroup_size(64) fn main(@builtin(global_invocation_id) global_id : vec3) { let index = global_id.x; - let width = u32(p.resolution.x); - let height = u32(p.resolution.y); + + let width = u32(p[0]); + let height = u32(p[1]); if (index >= width * height) { return; } let x = f32(index % width); let y = f32(index / width); - let uv = vec2(x / p.resolution.x, y / p.resolution.y); + let uv = vec2(x / p[0], y / p[1]); - let aspect = p.resolution.x / p.resolution.y; + let aspect = p[0] / p[1]; let uv_corr = vec2(uv.x * aspect, uv.y); var newVal = 0.0; - let origin = vec2(0.5 * aspect, 0.7); + // 1. FIX: Y = 0.3 setzt den Ursprung ins obere Drittel des Bildschirms + let origin = vec2(0.5 * aspect, 0.3); let s1 = sin(state.theta1); let c1 = cos(state.theta1); @@ -170,15 +147,15 @@ export const PENDULUM_RENDER_COMPUTE_SHADER_WGSL = ` let displayScale = 0.15; - let p1 = origin + vec2(s1, -c1) * p.l1 * displayScale; - let p2 = p1 + vec2(s2, -c2) * p.l2 * displayScale; + // 2. FIX: +c1 und +c2 genutzt, da Y in WebGPU nach unten wächst + let p1 = origin + vec2(s1, c1) * p[7] * displayScale; + let p2 = p1 + vec2(s2, c2) * p[8] * displayScale; let dLine1 = sdSegment(uv_corr, origin, p1); let dLine2 = sdSegment(uv_corr, p1, p2); let dMass1 = length(uv_corr - p1); let dMass2 = length(uv_corr - p2); - // Geometrie zeichnen let lineThick = 0.003; let m1Radius = 0.02; let m2Radius = 0.02;