diff --git a/src/app/pages/algorithms/cloth/cloth.component.html b/src/app/pages/algorithms/cloth/cloth.component.html index ccbe516..5bc709e 100644 --- a/src/app/pages/algorithms/cloth/cloth.component.html +++ b/src/app/pages/algorithms/cloth/cloth.component.html @@ -12,6 +12,15 @@ + + +
+ + + +
{ + // Type 1.0 = horizontal/diagonal (no elongation), Type 2.0 = vertical (elongation applies) + const addHorizontalConstraint = (arr: number[], a: number, b: number): void => { arr.push(a, b, config.spacing, 1.0); }; + const addVerticalConstraint = (arr: number[], a: number, b: number): void => { + arr.push(a, b, config.spacing, 2.0); + }; // Fill positions (Pin top row) for (let y = 0; y < config.gridHeight; y++) { @@ -186,14 +202,14 @@ export class ClothComponent { // Graph Coloring (4 Phases) for (let y = 0; y < config.gridHeight; y++) { - for (let x = 0; x < config.gridWidth - 1; x += 2) addConstraint(constraintsP0, y * config.gridWidth + x, y * config.gridWidth + x + 1); - for (let x = 1; x < config.gridWidth - 1; x += 2) addConstraint(constraintsP1, y * config.gridWidth + x, y * config.gridWidth + x + 1); + for (let x = 0; x < config.gridWidth - 1; x += 2) addHorizontalConstraint(constraintsP0, y * config.gridWidth + x, y * config.gridWidth + x + 1); + for (let x = 1; x < config.gridWidth - 1; x += 2) addHorizontalConstraint(constraintsP1, y * config.gridWidth + x, y * config.gridWidth + x + 1); } for (let y = 0; y < config.gridHeight - 1; y += 2) { - for (let x = 0; x < config.gridWidth; x++) addConstraint(constraintsP2, y * config.gridWidth + x, (y + 1) * config.gridWidth + x); + for (let x = 0; x < config.gridWidth; x++) addVerticalConstraint(constraintsP2, y * config.gridWidth + x, (y + 1) * config.gridWidth + x); } for (let y = 1; y < config.gridHeight - 1; y += 2) { - for (let x = 0; x < config.gridWidth; x++) addConstraint(constraintsP3, y * config.gridWidth + x, (y + 1) * config.gridWidth + x); + for (let x = 0; x < config.gridWidth; x++) addVerticalConstraint(constraintsP3, y * config.gridWidth + x, (y + 1) * config.gridWidth + x); } const constraintsP4: number[] = []; @@ -228,7 +244,7 @@ export class ClothComponent { constraintsP0, constraintsP1, constraintsP2, constraintsP3, constraintsP4, constraintsP5, constraintsP6, constraintsP7 ], - params: new Float32Array(8) + params: new Float32Array(9) }; } @@ -331,7 +347,7 @@ export class ClothComponent { // 6. RENDER LOOP // ======================================================================== private startRenderLoop(engine: WebGPUEngine, scene: Scene, config: ClothConfig, buffers: ClothBuffers, pipelines: ClothPipelines): void { - const paramsData = new Float32Array(8); + const paramsData = new Float32Array(9); // Pre-calculate constraint dispatch sizes for the 4 phases const constraintsLength = buffers.constraints.map(b => (b as any)._buffer.capacity / 4 / 4); // Elements / vec4 length @@ -347,16 +363,23 @@ export class ClothComponent { const windX = this.isWindActive ? 5.0 : 0.0; const windY = 0.0; const windZ = this.isWindActive ? 15.0 : 0.0; - const scaledCompliance = 0.00001 * config.particleInvMass * config.spacing; + + // Logarithmic compliance: stiffness=1 → very soft fabric, stiffness=100 → rigid metal sheet. + // alpha = compliance / dt² must be >> wSum (≈800) to be soft, << wSum to be rigid. + const softCompliance = 10.0; + const rigidCompliance = 0.00001; + const t = (this.stiffness - 1) / 99.0; + const compliance = softCompliance * Math.pow(rigidCompliance / softCompliance, t); paramsData[0] = 0.016; // dt paramsData[1] = -9.81; // gravity - paramsData[2] = scaledCompliance; + paramsData[2] = compliance; paramsData[3] = config.numVertices; paramsData[4] = windX; paramsData[5] = windY; paramsData[6] = windZ; paramsData[7] = this.simulationTime; + paramsData[8] = this.elongation; buffers.params.update(paramsData); diff --git a/src/app/pages/algorithms/cloth/cloth.shader.ts b/src/app/pages/algorithms/cloth/cloth.shader.ts index 94652d7..33cbe35 100644 --- a/src/app/pages/algorithms/cloth/cloth.shader.ts +++ b/src/app/pages/algorithms/cloth/cloth.shader.ts @@ -13,7 +13,8 @@ export const CLOTH_SHARED_STRUCTS = ` wind_x: f32, wind_y: f32, wind_z: f32, - time: f32 + time: f32, + elongation: f32 }; `; @@ -26,9 +27,8 @@ export const CLOTH_VERTEX_SHADER_WGSL = ` uniform viewProjection : mat4x4; - // Varyings, um Daten an den Fragment-Shader zu senden varying vUV : vec2; - varying vWorldPos : vec3; // NEU: Wir brauchen die 3D-Position für das Licht! + varying vWorldPos : vec3; @vertex fn main(input : VertexInputs) -> FragmentInputs { @@ -38,7 +38,7 @@ export const CLOTH_VERTEX_SHADER_WGSL = ` output.position = uniforms.viewProjection * vec4(worldPos, 1.0); output.vUV = input.uv; - output.vWorldPos = worldPos; // Position weitergeben + output.vWorldPos = worldPos; return output; } @@ -133,13 +133,15 @@ export const CLOTH_SOLVE_COMPUTE_WGSL = CLOTH_SHARED_STRUCTS + ` if (idx >= arrayLength(&constraints)) { return; } let constraint = constraints[idx]; - let isActive = constraint.w; - if (isActive < 0.5) { return; } + // constraint.w: 0.0 = inactive, 1.0 = horizontal/diagonal, 2.0 = vertical + if (constraint.w < 0.5) { return; } let idA = u32(constraint.x); let idB = u32(constraint.y); - let restLength = constraint.z; + + // constraint.w encodes type: 1.0 = horizontal/diagonal, 2.0 = vertical (elongation applies) + let restLength =constraint.z * p.elongation; var pA = positions[idA]; var pB = positions[idB];