Rendeirng problems fixed
Problem was broken uv coordinates in the fragment shader
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
import {BabylonCanvas, RenderConfig, SceneReadyEvent} from '../../../shared/rendering/canvas/babylon-canvas.component';
|
import {BabylonCanvas, RenderConfig, SceneReadyEvent} from '../../../shared/rendering/canvas/babylon-canvas.component';
|
||||||
import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from '@angular/material/card';
|
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';
|
import {PENDULUM_FRAGMENT_SHADER_WGSL, PENDULUM_PHYSIC_COMPUTE_SHADER_WGSL, PENDULUM_RENDER_COMPUTE_SHADER_WGSL, PENDULUM_VERTEX_SHADER_WGSL} from './pendulum.shader';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -25,7 +25,7 @@ export class PendulumComponent {
|
|||||||
vertexShader: PENDULUM_VERTEX_SHADER_WGSL,
|
vertexShader: PENDULUM_VERTEX_SHADER_WGSL,
|
||||||
fragmentShader: PENDULUM_FRAGMENT_SHADER_WGSL,
|
fragmentShader: PENDULUM_FRAGMENT_SHADER_WGSL,
|
||||||
uniformNames: [],
|
uniformNames: [],
|
||||||
uniformBufferNames: ["params"]
|
uniformBufferNames: []
|
||||||
};
|
};
|
||||||
|
|
||||||
onSceneReady(event: SceneReadyEvent) {
|
onSceneReady(event: SceneReadyEvent) {
|
||||||
@@ -38,24 +38,17 @@ export class PendulumComponent {
|
|||||||
const height = engine.getRenderHeight();
|
const height = engine.getRenderHeight();
|
||||||
const totalPixels = width * height;
|
const totalPixels = width * height;
|
||||||
|
|
||||||
|
// Buffer 1: Die Pixel (Bild)
|
||||||
const pixelBuffer = new StorageBuffer(engine, totalPixels * 4);
|
const pixelBuffer = new StorageBuffer(engine, totalPixels * 4);
|
||||||
|
|
||||||
|
// Buffer 2: Physik-Status
|
||||||
const stateBuffer = new StorageBuffer(engine, 4 * 4);
|
const stateBuffer = new StorageBuffer(engine, 4 * 4);
|
||||||
stateBuffer.update(new Float32Array([Math.PI / 4, Math.PI / 2, 0, 0]));
|
stateBuffer.update(new Float32Array([Math.PI / 4, Math.PI / 2, 0, 0]));
|
||||||
|
|
||||||
const ubo = new UniformBuffer(engine);
|
// Buffer 3: Parameter (DER NEUE, ABSOLUT SICHERE WEG)
|
||||||
ubo.addUniform("resolution", 2);
|
// Wir reservieren Platz für 10 Floats.
|
||||||
ubo.addUniform("time", 1);
|
const paramsBuffer = new StorageBuffer(engine, 10 * 4);
|
||||||
ubo.addUniform("dt", 1);
|
const paramsData = new Float32Array(10);
|
||||||
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();
|
|
||||||
|
|
||||||
const csPhysics = new ComputeShader("physics", engine, {
|
const csPhysics = new ComputeShader("physics", engine, {
|
||||||
computeSource: PENDULUM_PHYSIC_COMPUTE_SHADER_WGSL
|
computeSource: PENDULUM_PHYSIC_COMPUTE_SHADER_WGSL
|
||||||
@@ -66,7 +59,7 @@ export class PendulumComponent {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
csPhysics.setStorageBuffer("state", stateBuffer);
|
csPhysics.setStorageBuffer("state", stateBuffer);
|
||||||
csPhysics.setUniformBuffer("p", ubo);
|
csPhysics.setStorageBuffer("p", paramsBuffer); // Nutzen jetzt StorageBuffer
|
||||||
|
|
||||||
const csRender = new ComputeShader("render", engine, {
|
const csRender = new ComputeShader("render", engine, {
|
||||||
computeSource: PENDULUM_RENDER_COMPUTE_SHADER_WGSL
|
computeSource: PENDULUM_RENDER_COMPUTE_SHADER_WGSL
|
||||||
@@ -78,40 +71,39 @@ export class PendulumComponent {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
csRender.setStorageBuffer("pixelBuffer", pixelBuffer);
|
csRender.setStorageBuffer("pixelBuffer", pixelBuffer);
|
||||||
csRender.setUniformBuffer("p", ubo);
|
csRender.setStorageBuffer("p", paramsBuffer);
|
||||||
csRender.setStorageBuffer("state", stateBuffer);
|
csRender.setStorageBuffer("state", stateBuffer);
|
||||||
|
|
||||||
|
// Material Setup
|
||||||
const plane = scene.getMeshByName("plane");
|
const plane = scene.getMeshByName("plane");
|
||||||
if (plane?.material) {
|
if (plane?.material) {
|
||||||
const mat = plane.material as any;
|
const mat = plane.material as any;
|
||||||
mat.setStorageBuffer("pixelBuffer", pixelBuffer);
|
mat.setStorageBuffer("pixelBuffer", pixelBuffer);
|
||||||
mat.setUniformBuffer("params", ubo);
|
mat.setStorageBuffer("paramsBuffer", paramsBuffer); // Auch hier StorageBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
let time = 0;
|
let time = 0;
|
||||||
const dt = 0.015;
|
const dt = 0.015;
|
||||||
|
|
||||||
// Du hast die Physik wieder drin gelassen, das ist super:
|
|
||||||
scene.onBeforeRenderObservable.add(() => {
|
scene.onBeforeRenderObservable.add(() => {
|
||||||
time += dt;
|
time += dt;
|
||||||
|
|
||||||
const currentWidth = engine.getRenderWidth();
|
const currentWidth = engine.getRenderWidth();
|
||||||
const currentHeight = engine.getRenderHeight();
|
const currentHeight = engine.getRenderHeight();
|
||||||
|
|
||||||
ubo.updateFloat2("resolution", currentWidth, currentHeight);
|
paramsData[0] = currentWidth;
|
||||||
ubo.updateFloat("time", time);
|
paramsData[1] = currentHeight;
|
||||||
ubo.updateFloat("dt", dt);
|
paramsData[2] = time;
|
||||||
ubo.updateFloat("g", 9.81);
|
paramsData[3] = dt;
|
||||||
ubo.updateFloat("m1", 2.0);
|
paramsData[4] = 9.81; // g
|
||||||
ubo.updateFloat("m2", 1.0);
|
paramsData[5] = 2.0; // m1
|
||||||
ubo.updateFloat("l1", 1.5);
|
paramsData[6] = 1.0; // m2
|
||||||
ubo.updateFloat("l2", 1.2);
|
paramsData[7] = 1.5; // l1
|
||||||
ubo.updateFloat("damping", 0.99);
|
paramsData[8] = 1.2; // l2
|
||||||
ubo.updateFloat("pad1", 0);
|
paramsData[9] = 0.99; // damping
|
||||||
ubo.updateFloat("pad2", 0);
|
|
||||||
ubo.update();
|
paramsBuffer.update(paramsData);
|
||||||
|
|
||||||
// Physik Dispatch an
|
|
||||||
csPhysics.dispatch(1, 1, 1);
|
csPhysics.dispatch(1, 1, 1);
|
||||||
|
|
||||||
const totalPixels = currentWidth * currentHeight;
|
const totalPixels = currentWidth * currentHeight;
|
||||||
|
|||||||
@@ -13,35 +13,36 @@
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const PENDULUM_FRAGMENT_SHADER_WGSL = `
|
export const PENDULUM_FRAGMENT_SHADER_WGSL = `
|
||||||
varying vUV : vec2<f32>;
|
varying vUV : vec2<f32>; // Lassen wir stehen, damit der Vertex-Shader nicht meckert
|
||||||
var<storage, read> pixelBuffer : array<f32>;
|
var<storage, read> pixelBuffer : array<f32>;
|
||||||
var<uniform> params : Params; // Zurück zum bewährten Struct!
|
var<storage, read> paramsBuffer : array<f32>;
|
||||||
|
|
||||||
struct Params {
|
|
||||||
resolution: vec2<f32>,
|
|
||||||
time: f32,
|
|
||||||
dt: f32,
|
|
||||||
g: f32,
|
|
||||||
m1: f32,
|
|
||||||
m2: f32,
|
|
||||||
l1: f32,
|
|
||||||
l2: f32,
|
|
||||||
damping: f32,
|
|
||||||
pad1: f32,
|
|
||||||
pad2: f32
|
|
||||||
};
|
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn main(input : FragmentInputs) -> FragmentOutputs {
|
fn main(input : FragmentInputs) -> FragmentOutputs {
|
||||||
let width = u32(params.resolution.x);
|
let width = u32(paramsBuffer[0]);
|
||||||
let height = u32(params.resolution.y);
|
let height = u32(paramsBuffer[1]);
|
||||||
|
|
||||||
// clamp schützt uns vor Abstürzen durch Rundungsfehler am Bildschirmrand
|
if (width == 0u || height == 0u) {
|
||||||
let x = clamp(u32(input.vUV.x * params.resolution.x), 0u, width - 1u);
|
fragmentOutputs.color = vec4<f32>(0.5, 0.0, 0.0, 1.0);
|
||||||
let y = clamp(u32(input.vUV.y * params.resolution.y), 0u, height - 1u);
|
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<f32>(0.0, 0.0, 0.0, 1.0);
|
||||||
|
return fragmentOutputs;
|
||||||
|
}
|
||||||
|
|
||||||
let index = y * width + x;
|
let index = y * width + x;
|
||||||
|
|
||||||
let val = pixelBuffer[index];
|
let val = pixelBuffer[index];
|
||||||
|
|
||||||
var color = vec3<f32>(0.1, 0.1, 0.15);
|
var color = vec3<f32>(0.1, 0.1, 0.15);
|
||||||
@@ -62,21 +63,7 @@ export const PENDULUM_PHYSIC_COMPUTE_SHADER_WGSL = `
|
|||||||
};
|
};
|
||||||
|
|
||||||
@group(0) @binding(0) var<storage, read_write> state : State;
|
@group(0) @binding(0) var<storage, read_write> state : State;
|
||||||
@group(0) @binding(1) var<uniform> p : Params;
|
@group(0) @binding(1) var<storage, read> p : array<f32>;
|
||||||
|
|
||||||
struct Params {
|
|
||||||
resolution: vec2<f32>,
|
|
||||||
time: f32,
|
|
||||||
dt: f32,
|
|
||||||
g: f32,
|
|
||||||
m1: f32,
|
|
||||||
m2: f32,
|
|
||||||
l1: f32,
|
|
||||||
l2: f32,
|
|
||||||
damping: f32,
|
|
||||||
pad1: f32, // <-- Alignment
|
|
||||||
pad2: f32 // <-- Alignment
|
|
||||||
};
|
|
||||||
|
|
||||||
@compute @workgroup_size(1)
|
@compute @workgroup_size(1)
|
||||||
fn main() {
|
fn main() {
|
||||||
@@ -85,11 +72,13 @@ export const PENDULUM_PHYSIC_COMPUTE_SHADER_WGSL = `
|
|||||||
let v1 = state.v1;
|
let v1 = state.v1;
|
||||||
let v2 = state.v2;
|
let v2 = state.v2;
|
||||||
|
|
||||||
let m1 = p.m1;
|
let dt = p[3];
|
||||||
let m2 = p.m2;
|
let g = p[4];
|
||||||
let l1 = p.l1;
|
let m1 = p[5];
|
||||||
let l2 = p.l2;
|
let m2 = p[6];
|
||||||
let g = p.g;
|
let l1 = p[7];
|
||||||
|
let l2 = p[8];
|
||||||
|
let damping = p[9];
|
||||||
|
|
||||||
let num1 = -g * (2.0 * m1 + m2) * sin(t1)
|
let num1 = -g * (2.0 * m1 + m2) * sin(t1)
|
||||||
- m2 * g * sin(t1 - 2.0 * t2)
|
- 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 den2 = l2 * (2.0 * m1 + m2 - m2 * cos(2.0 * t1 - 2.0 * t2));
|
||||||
let a2 = num2 / den2;
|
let a2 = num2 / den2;
|
||||||
|
|
||||||
let new_v1 = (v1 + a1 * p.dt) * p.damping;
|
let new_v1 = (v1 + a1 * dt) * damping;
|
||||||
let new_v2 = (v2 + a2 * p.dt) * p.damping;
|
let new_v2 = (v2 + a2 * dt) * damping;
|
||||||
|
|
||||||
state.v1 = new_v1;
|
state.v1 = new_v1;
|
||||||
state.v2 = new_v2;
|
state.v2 = new_v2;
|
||||||
state.theta1 = t1 + new_v1 * p.dt;
|
state.theta1 = t1 + new_v1 * dt;
|
||||||
state.theta2 = t2 + new_v2 * p.dt;
|
state.theta2 = t2 + new_v2 * dt;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -120,23 +109,9 @@ export const PENDULUM_RENDER_COMPUTE_SHADER_WGSL = `
|
|||||||
};
|
};
|
||||||
|
|
||||||
@group(0) @binding(0) var<storage, read_write> pixelBuffer : array<f32>;
|
@group(0) @binding(0) var<storage, read_write> pixelBuffer : array<f32>;
|
||||||
@group(0) @binding(1) var<uniform> p : Params;
|
@group(0) @binding(1) var<storage, read> p : array<f32>;
|
||||||
@group(0) @binding(2) var<storage, read> state : State;
|
@group(0) @binding(2) var<storage, read> state : State;
|
||||||
|
|
||||||
struct Params {
|
|
||||||
resolution: vec2<f32>,
|
|
||||||
time: f32,
|
|
||||||
dt: f32,
|
|
||||||
g: f32,
|
|
||||||
m1: f32,
|
|
||||||
m2: f32,
|
|
||||||
l1: f32,
|
|
||||||
l2: f32,
|
|
||||||
damping: f32,
|
|
||||||
pad1: f32,
|
|
||||||
pad2: f32
|
|
||||||
};
|
|
||||||
|
|
||||||
fn sdSegment(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {
|
fn sdSegment(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {
|
||||||
let pa = p - a;
|
let pa = p - a;
|
||||||
let ba = b - a;
|
let ba = b - a;
|
||||||
@@ -147,21 +122,23 @@ export const PENDULUM_RENDER_COMPUTE_SHADER_WGSL = `
|
|||||||
@compute @workgroup_size(64)
|
@compute @workgroup_size(64)
|
||||||
fn main(@builtin(global_invocation_id) global_id : vec3<u32>) {
|
fn main(@builtin(global_invocation_id) global_id : vec3<u32>) {
|
||||||
let index = global_id.x;
|
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; }
|
if (index >= width * height) { return; }
|
||||||
|
|
||||||
let x = f32(index % width);
|
let x = f32(index % width);
|
||||||
let y = f32(index / width);
|
let y = f32(index / width);
|
||||||
let uv = vec2<f32>(x / p.resolution.x, y / p.resolution.y);
|
let uv = vec2<f32>(x / p[0], y / p[1]);
|
||||||
|
|
||||||
let aspect = p.resolution.x / p.resolution.y;
|
let aspect = p[0] / p[1];
|
||||||
let uv_corr = vec2<f32>(uv.x * aspect, uv.y);
|
let uv_corr = vec2<f32>(uv.x * aspect, uv.y);
|
||||||
|
|
||||||
var newVal = 0.0;
|
var newVal = 0.0;
|
||||||
|
|
||||||
let origin = vec2<f32>(0.5 * aspect, 0.7);
|
// 1. FIX: Y = 0.3 setzt den Ursprung ins obere Drittel des Bildschirms
|
||||||
|
let origin = vec2<f32>(0.5 * aspect, 0.3);
|
||||||
|
|
||||||
let s1 = sin(state.theta1);
|
let s1 = sin(state.theta1);
|
||||||
let c1 = cos(state.theta1);
|
let c1 = cos(state.theta1);
|
||||||
@@ -170,15 +147,15 @@ export const PENDULUM_RENDER_COMPUTE_SHADER_WGSL = `
|
|||||||
|
|
||||||
let displayScale = 0.15;
|
let displayScale = 0.15;
|
||||||
|
|
||||||
let p1 = origin + vec2<f32>(s1, -c1) * p.l1 * displayScale;
|
// 2. FIX: +c1 und +c2 genutzt, da Y in WebGPU nach unten wächst
|
||||||
let p2 = p1 + vec2<f32>(s2, -c2) * p.l2 * displayScale;
|
let p1 = origin + vec2<f32>(s1, c1) * p[7] * displayScale;
|
||||||
|
let p2 = p1 + vec2<f32>(s2, c2) * p[8] * displayScale;
|
||||||
|
|
||||||
let dLine1 = sdSegment(uv_corr, origin, p1);
|
let dLine1 = sdSegment(uv_corr, origin, p1);
|
||||||
let dLine2 = sdSegment(uv_corr, p1, p2);
|
let dLine2 = sdSegment(uv_corr, p1, p2);
|
||||||
let dMass1 = length(uv_corr - p1);
|
let dMass1 = length(uv_corr - p1);
|
||||||
let dMass2 = length(uv_corr - p2);
|
let dMass2 = length(uv_corr - p2);
|
||||||
|
|
||||||
// Geometrie zeichnen
|
|
||||||
let lineThick = 0.003;
|
let lineThick = 0.003;
|
||||||
let m1Radius = 0.02;
|
let m1Radius = 0.02;
|
||||||
let m2Radius = 0.02;
|
let m2Radius = 0.02;
|
||||||
|
|||||||
Reference in New Issue
Block a user