// Shared declarations, prepended to every kernel. struct Params { nx: u32, ny: u32, n: u32, histLen: u32, hx: f32, hy: f32, dt: f32, nu: f32, D: f32, // bending stiffness [N m] C: f32, // E h / (1 - nu^2) [N/m] G: f32, // E h / (2 (1 + nu)) [N/m] rhoh: f32, // mass per unit area [kg/m^2] pushX: f32, // center of the pushed patch [m] pushY: f32, pushR2: f32, // squared patch radius [m^2] mass: f32, // total mass [kg] Ix: f32, // sum m y^2 Iy: f32, // sum m x^2 Iz: f32, // sum m (x^2 + y^2) fs: f32, // audio sample rate [Hz] strikeX: f32, // drumstick contact point [m] strikeY: f32, strikeR2: f32, // squared contact radius [m^2] patchMass: f32, // mass of the contact patch [kg] strikeNode: u32, // node nearest the contact point K: f32, // Hertz contact stiffness [N/m^alpha] alpha: f32, // Hertz exponent stickMass: f32, // [kg] }; // Per-step parameters, addressed with a dynamic uniform offset. struct StepParams { step: u32, flags: u32, // bit 0: push constraint active; bit 1: record the constraint reaction; bit 2: apply the recorded reaction; bit 3: drumstick active audioSlot: i32, // ring-buffer slot to record acceleration into (-1: none) audioOut: i32, // output sample index within the batch pushW: f32, // prescribed patch displacement [m] pushV: f32, // prescribed patch velocity [m/s] sigma0: f32, sigma1: f32, releaseGain: f32, // fraction of the recorded reaction still applied (finger letting go) sigmaIn: f32, // additional frequency-independent loss of the in-plane motion parity: u32, // which of the two stick-state slots holds the current state pad2: f32, }; fn nodeX(i: i32) -> f32 { return (f32(i) - 0.5 * f32(P.nx - 1u)) * P.hx; } fn nodeY(j: i32) -> f32 { return (f32(j) - 0.5 * f32(P.ny - 1u)) * P.hy; } // Quadrature / lumped-mass weight of every node: the fraction of its four // cells that belong to the sheet (trapezoidal weights on a full rectangle), // zero for nodes outside the sheet. Written once by the host. @group(0) @binding(9) var nw: array; fn nodeWeight(i: i32, j: i32) -> f32 { if (i < 0 || i >= i32(P.nx) || j < 0 || j >= i32(P.ny)) { return 0.0; } return nw[u32(j) * P.nx + u32(i)]; }