diff --git a/images/simulation.png b/images/simulation.png index a423e85bac3e658a403a30a8d1e9df3b652bfaed..a60e96c9ce7d04a746f6799df47b419e57bf0555 100644 Binary files a/images/simulation.png and b/images/simulation.png differ diff --git a/src/03-simulation/Simulation.ts b/src/03-simulation/Simulation.ts index 4fafe54d74051d2fa01768bf31ca45eab62176af..ca4346b52becdf59a16ceb319e12b723a03dfe7d 100644 --- a/src/03-simulation/Simulation.ts +++ b/src/03-simulation/Simulation.ts @@ -16,7 +16,7 @@ export class Simulation implements PipelineObserver { update(_deltaTime: number): void { const h = _deltaTime / 100; for (let t = 0; t < _deltaTime; t += h) { - SimulationData.pList.forEach(pSub => { + SimulationData.pList?.forEach(pSub => { pSub.forEach(p => { if (p.usePhysics) { Simulation.current = p; @@ -46,6 +46,9 @@ export class Simulation implements PipelineObserver { // 3.1 accumulate forces let totalForce = new THREE.Vector3(0, 0, 0); totalForce.add(SimulationData.externalForce); + totalForce.divideScalar(Math.pow(SimulationData.resolution, 2)); + totalForce.divideScalar(Math.sqrt(Math.pow(x[0], 2) + Math.pow(x[1], 2) + Math.pow(x[2], 2))); + // totalForce.multiplyScalar(Math.sin(2 * Math.PI * Math.random()) + .5); // 3.2 accumulate spring forces Simulation.current.references.forEach(spring => { diff --git a/src/03-simulation/SimulationData.ts b/src/03-simulation/SimulationData.ts index f297342ce8494fd3e7207022e6fa29d6bd3805a8..efa529423f11cab8bdd686dc7de7f450e6ac2d2c 100644 --- a/src/03-simulation/SimulationData.ts +++ b/src/03-simulation/SimulationData.ts @@ -5,6 +5,13 @@ import { BendingSpring, ShearSpring, Spring, SpringConstants, StructuralSpring, import { Particle } from './physics/particle'; import { EulerIntegrator, Integrator, MidpointIntegrator, RungeKuttaIntegrator } from './physics/Integrators'; +document.addEventListener('keydown', (event: KeyboardEvent) => { + + if (event.key === 'e') { + SimulationData.switchParticlePhysics(); + } +}); + class SimulationData implements PipelineGUI, PipelineRenderable { public static container: THREE.Group = new THREE.Group(); @@ -30,7 +37,7 @@ class SimulationData implements PipelineGUI, PipelineRenderable { public static externalForce: THREE.Vector3 = new THREE.Vector3(0, 0, 0); // particls - public static pList = new Array<Array<Particle>>(); + public static pList? = new Array<Array<Particle>>(); public static pColorDefault: number = 0xffffff; public static pColorNoPhysix: number = 0xff00ff; @@ -38,7 +45,7 @@ class SimulationData implements PipelineGUI, PipelineRenderable { public static readonly MAX_CONSTANT = 10; public static readonly MIN_CONSTANT = 0.1; - public static sList = new Array<Spring>(); + public static sList? = new Array<Spring>(); public static sConstants: SpringConstants = { structural: 10, shear: 2, bend: 4 }; public static sColorStructural: number = 0xff0000; public static sColorShear: number = 0x00ff00; @@ -59,9 +66,15 @@ class SimulationData implements PipelineGUI, PipelineRenderable { public static setMidpoint = () => { SimulationData.integratorType = 1; } public static setRungeKutta = () => { SimulationData.integratorType = 2; } + public static resetExternalForce(): void { + SimulationData.externalForce.x = 0; + SimulationData.externalForce.y = 0; + SimulationData.externalForce.z = 0; + } public static generateTextile(): void { // 1. reset pList + delete SimulationData.pList; SimulationData.pList = new Array<Array<Particle>>(); // 2. generate particles @@ -103,6 +116,7 @@ class SimulationData implements PipelineGUI, PipelineRenderable { }); // 5. reset sList + delete SimulationData.sList; SimulationData.sList = new Array<Spring>(); // 6. generate springs @@ -228,7 +242,14 @@ class SimulationData implements PipelineGUI, PipelineRenderable { // 8. add particles and springs to container while (SimulationData.container.children.length > 0) { - SimulationData.container.children.pop(); + let rm = SimulationData.container.children.pop(); + if (rm instanceof THREE.Line) { + rm.geometry.dispose(); + rm.material.dispose(); + } else if (rm instanceof THREE.Mesh) { + rm.geometry.dispose(); + rm.material.dispose(); + } } SimulationData.container.add(...pLinList, ...sLinList); @@ -240,7 +261,7 @@ class SimulationData implements PipelineGUI, PipelineRenderable { const pMass = SimulationData.totalMass / pCount; // 1.1 update particle mass - SimulationData.pList.forEach(pSub => { + SimulationData.pList?.forEach(pSub => { pSub.forEach(p => { p.mass = pMass; }); @@ -257,10 +278,13 @@ class SimulationData implements PipelineGUI, PipelineRenderable { const pSize = maxSize * pMassNorm; // 5. set pSize - SimulationData.pList.forEach(pSub => { pSub.forEach(p => p.setRadius(pSize)) }); + SimulationData.pList?.forEach(pSub => { pSub.forEach(p => p.setRadius(pSize)) }); } public static changedDimensions(): void { + if (!SimulationData.pList) + return; + // 1. reset positions of particles for (let i = 0; i < SimulationData.resolution; i++) { for (let j = 0; j < SimulationData.resolution; j++) { @@ -277,7 +301,7 @@ class SimulationData implements PipelineGUI, PipelineRenderable { public static changedParticleColor(): void { // iterate over all particles and set color based on current internal state - SimulationData.pList.forEach(pSub => { + SimulationData.pList?.forEach(pSub => { pSub.forEach(p => { if (p.usePhysics) { p.setColor(SimulationData.pColorDefault); @@ -290,7 +314,7 @@ class SimulationData implements PipelineGUI, PipelineRenderable { public static changedSpringColor(): void { // iterate over all particles and set color based on current internal state - SimulationData.sList.forEach(s => { + SimulationData.sList?.forEach(s => { if (s instanceof StructuralSpring) { s.setColor(SimulationData.sColorStructural); } else if (s instanceof ShearSpring) { @@ -308,7 +332,7 @@ class SimulationData implements PipelineGUI, PipelineRenderable { } // 2. compare mesh to all particles => find particle and change usePhysics - SimulationData.pList.forEach(pSub => { + SimulationData.pList?.forEach(pSub => { pSub.forEach(p => { if (p.mesh === picked) { p.usePhysics = !p.usePhysics; @@ -353,7 +377,7 @@ class SimulationData implements PipelineGUI, PipelineRenderable { particles.open(); const springs = gui.addFolder('Springs'); - springs.add(SimulationData, 'damping', 0, 1, 0.001).name('Damping Factor'); + springs.add(SimulationData, 'damping', 0, 0.2, 0.0001).name('Damping Factor'); springs.add(SimulationData.sConstants, 'structural', SimulationData.MIN_CONSTANT, SimulationData.MAX_CONSTANT) .step(0.1).name('Structural'); springs.add(SimulationData.sConstants, 'shear', SimulationData.MIN_CONSTANT, SimulationData.MAX_CONSTANT) diff --git a/src/03-simulation/physics/Particle.ts b/src/03-simulation/physics/Particle.ts index acc081fc19d55d2382c9ecdab39a41adf5c72d62..8237d597c549f126e85ca2f2d0341636427d700a 100644 --- a/src/03-simulation/physics/Particle.ts +++ b/src/03-simulation/physics/Particle.ts @@ -59,6 +59,7 @@ export class Particle implements PipelineRenderable { } public setRadius(radius: number): void { + this.mesh.geometry.dispose(); this.mesh.geometry = new THREE.SphereGeometry(radius, 4, 2); } diff --git a/src/03-simulation/physics/Springs.ts b/src/03-simulation/physics/Springs.ts index 0b0d05e1b7a3e12c8b95bf4f00574d45ed27a460..a43c7cf7220678ca45c981dd4d49649eec76ff37 100644 --- a/src/03-simulation/physics/Springs.ts +++ b/src/03-simulation/physics/Springs.ts @@ -52,7 +52,9 @@ export abstract class Spring { } notify(): void { - this.line.geometry.setFromPoints([this.positionA, this.positionB]); + this.line.geometry.attributes.position.setXYZ(0, this.positionA.x, this.positionA.y, this.positionA.z); + this.line.geometry.attributes.position.setXYZ(1, this.positionB.x, this.positionB.y, this.positionB.z); + this.line.geometry.attributes.position.needsUpdate = true; } }