abouttreesummaryrefslogcommitdiff
path: root/Scripts/cloth.js
diff options
context:
space:
mode:
authorPatrick2021-03-18 17:05:15 +0100
committerPatrick2021-03-18 17:05:15 +0100
commiteac8eb4ec5115f16fc17b94fb194fdc1c005ddb5 (patch)
treefe9f148bd3473d08bdf2d8047c121cceae0a54de /Scripts/cloth.js
parent8e3324e4b7f7bc8b59df9ef477e0847165145b8c (diff)
downloadcloth_sim-refactoring.tar.gz
cloth_sim-refactoring.zip
commentsrefactoring
Diffstat (limited to 'Scripts/cloth.js')
-rw-r--r--Scripts/cloth.js46
1 files changed, 33 insertions, 13 deletions
diff --git a/Scripts/cloth.js b/Scripts/cloth.js
index 1f1c1e0..712ed63 100644
--- a/Scripts/cloth.js
+++ b/Scripts/cloth.js
@@ -5,10 +5,6 @@ const GRAVITY = new THREE.Vector3(0, -9.81 * MASS, 0);
const K = 1;
const MAX_STRETCH = 1.5;
-// Explosion am Anfang
-// Intersect mit Velocity?
-// Wind/Ziehen
-
const options = {
wind: true,
};
@@ -21,22 +17,23 @@ class Spring {
}
satisfy() {
+ /** calculate current spring length */
const diff = this.p2.position.clone().sub(this.p1.position);
const currentDist = diff.length();
if (currentDist == 0) return;
if (currentDist <= this.restDist) return;
//const correction = diff.multiplyScalar(1 - (this.restDist / currentDist));
+
+ /** calculate necessary correction length and direction */
const correction = diff.multiplyScalar((currentDist - this.restDist) / currentDist);
correction.multiplyScalar(K);
- if (currentDist >= this.restDist * MAX_STRETCH) {
-
- }
- //correction.clampLength(0, 1);
const correctionHalf = correction.multiplyScalar(0.5);
let p1movable = this.p1.movable && this.p1.movableTmp;
let p2movable = this.p2.movable && this.p2.movableTmp;
+ /** apply correction if masses aren't fixed */
+ /** divide correction if both are movable */
if (p1movable && p2movable) {
this.p1.position.add(correctionHalf);
this.p2.position.sub(correctionHalf);
@@ -67,8 +64,11 @@ class Mass {
// verlet algorithm
// next position = 2 * current Position - previous position + acceleration * (passed time)^2
// acceleration (dv/dt) = F(net)
+ /** calculate velocity */
const nextPosition = this.position.clone().sub(this.previous);
+ /** apply drag */
nextPosition.multiplyScalar(DRAG);
+ /** add to current position and add acceleration */
nextPosition.add(this.position);
nextPosition.add(this.acceleration.multiplyScalar(dt*dt));
@@ -77,6 +77,7 @@ class Mass {
this.position = nextPosition;
}
+ /** reset for next frame */
this.acceleration.set(0, 0, 0);
}
}
@@ -114,18 +115,16 @@ class Cloth {
}
}
- //this.masses[this.getVertexIndex(0, 0)].movable = false;
+ /** attach cloth to flag pole */
const n = 3;
for (let i = 0; i < numPointsHeight; i++)
this.masses[this.getVertexIndex(0, i)].movable = false;
- //this.masses[this.getVertexIndex(0, numPointsHeight-1)].movable = false;
- //this.masses[this.getVertexIndex(numPointsWidth-1, 0)].movable = false;
const REST_DIST_X = width / (numPointsWidth-1);
const REST_DIST_Y = height / (numPointsHeight-1);
/**
- * generate springs (springs)
+ * generate springs (constraints)
*/
this.springs = [];
for (let y = 0; y < numPointsHeight; y++) {
@@ -154,6 +153,7 @@ class Cloth {
const indices = [];
const uvs = [];
+ /** create one vertex and one uv coordinate per mass */
for (let i in this.masses) {
let particle = this.masses[i];
vertices.push(
@@ -185,6 +185,7 @@ class Cloth {
}
}
+ /** set up geometry */
geometry.setIndex(indices);
geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2));
@@ -194,6 +195,7 @@ class Cloth {
return geometry;
}
updateGeometry(geometry) {
+ /** update vertex positions in place */
const positions = geometry.attributes.position.array;
for (let i in this.masses) {
let p = this.masses[i];
@@ -201,6 +203,7 @@ class Cloth {
positions[i*3+1] = p.position.y;
positions[i*3+2] = p.position.z;
}
+ /** update internally and recalculate bounding volume */
geometry.attributes.position.needsUpdate = true;
geometry.computeBoundingSphere();
geometry.computeVertexNormals();
@@ -208,6 +211,10 @@ class Cloth {
simulate(dt) {
let now = performance.now();
for (let mass of this.masses) {
+ /** accumulate acceleration:
+ * - wind
+ * - gravity
+ */
let vertex = mass.position;
let fWind = new THREE.Vector3(
this.windFactor.x * (Math.sin(vertex.x * vertex.y * now)+1),
@@ -221,14 +228,16 @@ class Cloth {
mass.addForce(GRAVITY);
+ /** integrate motion */
mass.verlet(dt);
}
-
+ /** run satisfy step */
for (let constraint of this.springs) {
constraint.satisfy();
}
+ /** prevent self-intersections */
this.intersect();
}
@@ -241,15 +250,21 @@ class Cloth {
p1.movableTmp = true;
p2.movableTmp = true;
+ /** skip if i == j or if masses are adjacent */
if (i == j || (Math.abs(this.getX(i) - this.getX(j)) == 1 && Math.abs(this.getY(i) - this.getY(j)) == 1))
continue;
+ /** calculate distance of points */
let dist = p1.position.distanceTo(p2.position);
+ /** calculate minimal resting distance (largest distance that should not be fallen below) */
let collisionDistance = Math.min(this.width / this.numPointsWidth, this.height / this.numPointsHeight);
// collisionDistance /= 2;
+ /** calculate "sphere intersection" */
if (dist < collisionDistance) {
// p1.movableTmp = false;
// p2.movableTmp = false;
+
+ /** vectors from p1 to p2 and the other way round */
let diffP2P1 = p1.position.clone().sub(p2.position).normalize();
diffP2P1.multiplyScalar((collisionDistance - dist) * 1.001 / 2);
let diffP1P2 = diffP2P1.clone().multiplyScalar(-1);
@@ -260,6 +275,7 @@ class Cloth {
// let factor1 = (Math.PI - Math.acos(v1.dot(diffP2P1))) / Math.PI * 2;
// let factor2 = (Math.PI - Math.acos(v2.dot(diffP1P2))) / Math.PI * 2;
+ /** move masses apart */
if (p1.movable)
p1.position.add(diffP2P1);
//p1.position.add(diffP2P1.multiplyScalar(factor1));
@@ -272,13 +288,17 @@ class Cloth {
}
blow(camPos, intersects) {
let face = intersects[0].face;
+ /** vector from cam to intersection (wind) */
let dir = intersects[0].point.clone().sub(camPos).multiplyScalar(100);
+ /** apply to all vertices of affected face */
this.masses[face.a].addForce(dir);
this.masses[face.b].addForce(dir);
this.masses[face.c].addForce(dir);
}
drag(mousePosWorld, index) {
+ /** calculate vector from vertex to cursor */
let dir = mousePosWorld.clone().sub(this.masses[index].position).multiplyScalar(200);
+ /** apply to grabbed vertex */
this.masses[index].addForce(dir);
}