Adding Constraint and Friction
Author: Win Aung ChoPosition Verlet Algorithm
x(t+Δt)=2x(t)-x(t-Δt)+Δt²•F(x(t))/m + O[Δt⁴]
v(t)=1/(2Δt)•[x(t+Δt) - x(t-Δt)] + O[Δt²]
Adding damping such as retarding force by friction.
Velocity is modified by damping or friction facto β.
v(t) = (1 - β)*v(t)
where
v(t) = x(t) - x(t-Δt)
Particle model become as following.
x(t+Δt)=2x(t)-x(t-Δt)+Δt²•F(x(t))/m + O[Δt⁴]
v(t)=1/(2Δt)•[x(t+Δt) - x(t-Δt)] + O[Δt²]
Adding damping such as retarding force by friction.
Velocity is modified by damping or friction facto β.
v(t) = (1 - β)*v(t)
where
v(t) = x(t) - x(t-Δt)
Particle model become as following.
class Point { constructor(x, y, vx, vy, lock) { this.pos = new Vector(x, y); this.oldpos = new Vector(x + (vx || 0), y + (vy || 0)); // velocity x, y this.friction = 0.99; this.groundFriction = 0.99; this.radius = 15; this.color = "e62a4f"; this.mass = 1; this.fixed = lock || false; } update() { if(!this.fixed) { let vel = SUB(this.pos, this.oldpos); vel.mult(this.friction); this.oldpos.set(this.pos.x, this.pos.y); this.pos.add(vel); this.pos.add(MUL(Gravity, stepTime * stepTime)); } } checkborder() { if(this.fixed) return; let vel = SUB(this.pos, this.oldpos); vel.mult(this.friction); vel.mult(this.groundFriction); if(this.pos.x > CANVAS_WIDTH - this.radius) { this.pos.x = CANVAS_WIDTH - this.radius; this.oldpos.x = this.pos.x + vel.x; } if(this.pos.x < this.radius) { this.pos.x = this.radius; this.oldpos.x = this.pos.x + vel.x; } if(this.pos.y > CANVAS_HEIGHT - this.radius) { this.pos.y = CANVAS_HEIGHT - this.radius; this.oldpos.y = this.pos.y + vel.y; } if(this.pos.y < this.radius) { this.pos.y = this.radius; this.oldpos.y = this.pos.y + vel.y; } }; render(ctx) { ctx.beginPath(); ctx.fillStyle = this.color; ctx.arc(this.pos.x, this.pos.y, this.radius, 0, Math.PI * 2); ctx.fill(); ctx.closePath(); } }

Cloth and Truss Simulation
Particles are link with rigid arm and connected particle must move accordingly with the connected arm. Distance between particles must maintain to be equle with the rest length of arm. In this model arm has no strain.
class Link { constructor(p1, p2, length) { this.p1 = p1; this.p2 = p2; this.color = 'f5476a'; // if the length is not given then calculate the distance based on position if(!length) { this.length = this.p1.pos.dist(this.p2.pos); } else { this.length = length; } } update() { const dir = SUB(this.p1.pos, this.p2.pos); const dist = dir.mag(); const percent = (this.length - dist) / dist / 2; const offset = dir.mult(percent); if(!this.p1.fixed) { this.p1.pos.add(offset); } if(!this.p2.fixed) { this.p2.pos.sub(offset); } } render(ctx) { ctx.beginPath(); ctx.strokeStyle = this.color; ctx.moveTo(this.p1.pos.x, this.p1.pos.y); ctx.lineTo(this.p2.pos.x, this.p2.pos.y); ctx.stroke(); ctx.closePath(); } }
Process will run as following function.
function animate() { ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); for(let d of points) { d.update(); d.checkborder(); d.render(ctx); } for(let s of links) { s.update(); s.render(ctx); } requestAnimationFrame(animate); }
Author: Win Aung Cho
12-Jun-2022 08:58:11 PM*