feature/webGPU #25
@@ -38,7 +38,8 @@ export class PendulumComponent {
|
||||
m2: 1.0,
|
||||
l1: 1.5,
|
||||
l2: 1.2,
|
||||
damping: 0.999 // Less damping for longer swinging
|
||||
damping: 0.999,
|
||||
trailDecay: 0.98
|
||||
};
|
||||
|
||||
onSceneReady(event: SceneReadyEvent) {
|
||||
@@ -55,8 +56,8 @@ export class PendulumComponent {
|
||||
const stateBuffer = new StorageBuffer(engine, 4 * 4);
|
||||
stateBuffer.update(new Float32Array([Math.PI / 4, Math.PI / 2, 0, 0])); // Initial angles
|
||||
|
||||
const paramsBuffer = new StorageBuffer(engine, 10 * 4);
|
||||
const paramsData = new Float32Array(10);
|
||||
const paramsBuffer = new StorageBuffer(engine, 12 * 4);
|
||||
const paramsData = new Float32Array(12);
|
||||
|
||||
// --- 2. SHADERS ---
|
||||
const csPhysics = new ComputeShader("physics", engine,
|
||||
@@ -100,6 +101,8 @@ export class PendulumComponent {
|
||||
paramsData[7] = this.simParams.l1;
|
||||
paramsData[8] = this.simParams.l2;
|
||||
paramsData[9] = this.simParams.damping;
|
||||
paramsData[10] = this.simParams.trailDecay;
|
||||
paramsData[11] = 0; // Pad
|
||||
|
||||
paramsBuffer.update(paramsData);
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@ const SHARED_STRUCTS = `
|
||||
m2: f32,
|
||||
l1: f32,
|
||||
l2: f32,
|
||||
damping: f32
|
||||
damping: f32,
|
||||
trailDecay: f32,
|
||||
pad: f32 // <-- Padding for safe 16-byte memory alignment
|
||||
};
|
||||
|
||||
struct State {
|
||||
@@ -44,30 +46,45 @@ export const PENDULUM_FRAGMENT_SHADER_WGSL = SHARED_STRUCTS + `
|
||||
let width = u32(p.width);
|
||||
let height = u32(p.height);
|
||||
|
||||
// Fallback if buffer is not loaded yet
|
||||
if (width == 0u || height == 0u) {
|
||||
fragmentOutputs.color = vec4<f32>(0.5, 0.0, 0.0, 1.0);
|
||||
return fragmentOutputs;
|
||||
}
|
||||
|
||||
// Direct access to the pixel via screen coordinates
|
||||
let x = u32(input.position.x);
|
||||
let y = u32(input.position.y);
|
||||
|
||||
// Boundary check to prevent reading outside the buffer
|
||||
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 val = pixelBuffer[index];
|
||||
|
||||
var color = vec3<f32>(0.1, 0.1, 0.15); // Background
|
||||
if (val > 0.1) { color = vec3<f32>(0.5, 0.5, 0.5); } // Line
|
||||
if (val > 0.8) { color = vec3<f32>(1.0, 1.0, 1.0); } // Mass
|
||||
// --- THE MAGIC DECODING ---
|
||||
let rawVal = pixelBuffer[index];
|
||||
var trailVal = rawVal;
|
||||
var isLine = false;
|
||||
|
||||
fragmentOutputs.color = vec4<f32>(color, 1.0);
|
||||
// Check if the +10.0 flag is present (meaning this pixel is currently a line)
|
||||
if (trailVal >= 10.0) {
|
||||
isLine = true;
|
||||
trailVal = trailVal - 10.0; // Remove flag to get the true trail value underneath
|
||||
}
|
||||
|
||||
let bgColor = vec3<f32>(0.1, 0.1, 0.15);
|
||||
let massColor = vec3<f32>(1.0, 1.0, 1.0);
|
||||
let lineColor = vec3<f32>(0.5, 0.5, 0.5);
|
||||
|
||||
// Calculate background blending with the trail
|
||||
var finalColor = mix(bgColor, massColor, clamp(trailVal, 0.0, 1.0));
|
||||
|
||||
// Overwrite with the grey line if necessary
|
||||
if (isLine) {
|
||||
finalColor = lineColor;
|
||||
}
|
||||
|
||||
fragmentOutputs.color = vec4<f32>(finalColor, 1.0);
|
||||
return fragmentOutputs;
|
||||
}
|
||||
`;
|
||||
@@ -87,7 +104,6 @@ export const PENDULUM_PHYSIC_COMPUTE_SHADER_WGSL = SHARED_STRUCTS + `
|
||||
|
||||
let delta_t = t1 - t2;
|
||||
|
||||
// Equations split for better readability
|
||||
let num1 = -p.g * (2.0 * p.m1 + p.m2) * sin(t1)
|
||||
- p.m2 * p.g * sin(t1 - 2.0 * t2)
|
||||
- 2.0 * sin(delta_t) * p.m2 * (v2 * v2 * p.l2 + v1 * v1 * p.l1 * cos(delta_t));
|
||||
@@ -98,7 +114,6 @@ export const PENDULUM_PHYSIC_COMPUTE_SHADER_WGSL = SHARED_STRUCTS + `
|
||||
let den2 = p.l2 * (2.0 * p.m1 + p.m2 - p.m2 * cos(2.0 * delta_t));
|
||||
let a2 = num2 / den2;
|
||||
|
||||
// Integration (Semi-Implicit Euler)
|
||||
let new_v1 = (v1 + a1 * p.dt) * p.damping;
|
||||
let new_v2 = (v2 + a2 * p.dt) * p.damping;
|
||||
|
||||
@@ -137,25 +152,39 @@ export const PENDULUM_RENDER_COMPUTE_SHADER_WGSL = SHARED_STRUCTS + `
|
||||
let aspect = p.width / p.height;
|
||||
let uv_corr = vec2<f32>(uv.x * aspect, uv.y);
|
||||
|
||||
var newVal = 0.0; // Clear background
|
||||
// --- TRAIL EXTRACT & DECAY ---
|
||||
let oldRaw = pixelBuffer[index];
|
||||
var oldTrail = oldRaw;
|
||||
|
||||
// If the pixel was a line last frame, remove the +10 flag to get the trail memory
|
||||
if (oldTrail >= 10.0) {
|
||||
oldTrail = oldTrail - 10.0;
|
||||
}
|
||||
var newVal = oldTrail * p.trailDecay;
|
||||
|
||||
// Pendulum geometry
|
||||
let origin = vec2<f32>(0.5 * aspect, 0.3);
|
||||
let displayScale = 0.15;
|
||||
|
||||
// Calculate positions
|
||||
let p1 = origin + vec2<f32>(sin(state.theta1), cos(state.theta1)) * p.l1 * displayScale;
|
||||
let p2 = p1 + vec2<f32>(sin(state.theta2), cos(state.theta2)) * p.l2 * displayScale;
|
||||
|
||||
// Distances
|
||||
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);
|
||||
|
||||
// Draw
|
||||
if (dLine1 < 0.003 || dLine2 < 0.003) { newVal = 0.5; }
|
||||
if (dMass1 < 0.02 || dMass2 < 0.02) { newVal = 1.0; }
|
||||
let isLine = (dLine1 < 0.002 || dLine2 < 0.002);
|
||||
let isMass = (dMass1 < 0.01 || dMass2 < 0.01);
|
||||
|
||||
// --- SMART LAYERING ---
|
||||
if (isMass) {
|
||||
newVal = 1.0;
|
||||
} else if (isLine) {
|
||||
// Lines are marked with +10.0 to tell the fragment shader to paint them grey,
|
||||
// WITHOUT overwriting the fading trail memory underneath!
|
||||
newVal = newVal + 10.0;
|
||||
}
|
||||
|
||||
pixelBuffer[index] = newVal;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"APP": {
|
||||
"TITLE": "Playground",
|
||||
"COPYRIGHT": "Bilder urheberrechtlich geschützt, keine Nutzung ohne Zustimmung!"
|
||||
"COPYRIGHT": "Bilder und Sourcecode sind urheberrechtlich geschützt, keine Nutzung ohne Zustimmung!"
|
||||
},
|
||||
"TOPBAR": {
|
||||
"ABOUT": "Über mich",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"APP": {
|
||||
"TITLE": "Playground",
|
||||
"COPYRIGHT": "Images protected by copyright, no use without permission!"
|
||||
"COPYRIGHT": "Images and code protected by copyright, no use without permission!"
|
||||
},
|
||||
"TOPBAR": {
|
||||
"ABOUT": "About me",
|
||||
|
||||
Reference in New Issue
Block a user