diff options
Diffstat (limited to 'Scripts/cloth.js')
| -rw-r--r-- | Scripts/cloth.js | 317 |
1 files changed, 0 insertions, 317 deletions
diff --git a/Scripts/cloth.js b/Scripts/cloth.js deleted file mode 100644 index 712ed63..0000000 --- a/Scripts/cloth.js +++ /dev/null @@ -1,317 +0,0 @@ -const DAMPING = 0.03;
-const DRAG = 1 - DAMPING;
-const MASS = 0.1;
-const GRAVITY = new THREE.Vector3(0, -9.81 * MASS, 0);
-const K = 1;
-const MAX_STRETCH = 1.5;
-
-const options = {
- wind: true,
-};
-
-class Spring {
- constructor(p1, p2, restDist) {
- this.p1 = p1;
- this.p2 = p2;
- this.restDist = restDist;
- }
-
- 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);
- 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);
- } else if (! p1movable && p2movable) {
- this.p2.position.sub(correction);
- } else if (p1movable && ! p2movable) {
- this.p1.position.add(correction);
- }
- }
-}
-
-class Mass {
- movableTmp = true;
- movable = true;
-
- constructor(x, y, z, mass) {
- this.position = new THREE.Vector3(x, y, z);
- this.previous = new THREE.Vector3(x, y, z);
- this.acceleration = new THREE.Vector3(0, 0, 0);
- this.mass = mass;
- }
- addForce(force) {
- this.acceleration.add(
- force.clone().multiplyScalar(1/this.mass)
- );
- }
- verlet(dt) {
- // 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));
-
- if (this.movable && this.movableTmp) {
- this.previous = this.position;
- this.position = nextPosition;
- }
-
- /** reset for next frame */
- this.acceleration.set(0, 0, 0);
- }
-}
-
-class Cloth {
- constructor(width, height, numPointsWidth, numPointsHeight) {
- this.width = width;
- this.height = height;
- this.numPointsWidth = numPointsWidth;
- this.numPointsHeight = numPointsHeight;
- this.windFactor = new THREE.Vector3(3, 2, 2);
-
- /**
- * distance between two vertices horizontally/vertically
- * divide by the number of points minus one
- * because there are (n - 1) lines between n vertices
- */
- let stepWidth = width / (numPointsWidth - 1);
- let stepHeight = height / (numPointsHeight - 1);
-
- /**
- * iterate over the number of vertices in x/y axis
- * and add a new Particle to "masses"
- */
- this.masses = [];
- for (let y = 0; y < numPointsHeight; y++) {
- for (let x = 0; x < numPointsWidth; x++) {
- this.masses.push(
- new Mass(
- (x - ((numPointsWidth-1)/2)) * stepWidth,
- height - (y + ((numPointsHeight-1)/2)) * stepHeight,
- 0,
- MASS)
- );
- }
- }
-
- /** attach cloth to flag pole */
- const n = 3;
- for (let i = 0; i < numPointsHeight; i++)
- this.masses[this.getVertexIndex(0, i)].movable = false;
-
- const REST_DIST_X = width / (numPointsWidth-1);
- const REST_DIST_Y = height / (numPointsHeight-1);
-
- /**
- * generate springs (constraints)
- */
- this.springs = [];
- for (let y = 0; y < numPointsHeight; y++) {
- for (let x = 0; x < numPointsWidth; x++) {
- if (x < numPointsWidth-1) {
- this.springs.push(new Spring(
- this.masses[this.getVertexIndex(x, y)],
- this.masses[this.getVertexIndex(x+1, y)],
- REST_DIST_X
- ));
- }
- if (y < numPointsHeight-1) {
- this.springs.push(new Spring(
- this.masses[this.getVertexIndex(x, y)],
- this.masses[this.getVertexIndex(x, y+1)],
- REST_DIST_Y
- ));
- }
- }
- }
- }
- generateGeometry() {
- const geometry = new THREE.BufferGeometry();
-
- const vertices = [];
- 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(
- particle.position.x,
- particle.position.y,
- particle.position.z);
- uvs.push(
- this.getX(i) / (this.numPointsWidth-1),
- 1 - (this.getY(i) / (this.numPointsHeight-1))
- );
- }
-
- /**
- * generate faces based on 4 vertices
- * and 6 springs each
- */
- for (let y = 0; y < this.numPointsHeight - 1; y++) {
- for (let x = 0; x < this.numPointsWidth - 1; x++) {
- indices.push(
- this.getVertexIndex(x, y),
- this.getVertexIndex(x+1, y),
- this.getVertexIndex(x+1, y+1)
- );
- indices.push(
- this.getVertexIndex(x, y),
- this.getVertexIndex(x+1, y+1),
- this.getVertexIndex(x, y+1)
- );
- }
- }
-
- /** set up geometry */
- geometry.setIndex(indices);
- geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
- geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2));
- geometry.computeBoundingSphere();
- geometry.computeVertexNormals();
-
- 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];
- positions[i*3+0] = p.position.x;
- 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();
- }
- 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),
- this.windFactor.y * Math.cos(vertex.z * now),
- this.windFactor.z * Math.sin(Math.cos(5 * vertex.x * vertex.y * vertex.z))
- );
- // normalize then multiply?
- if (options.wind)
- mass.addForce(fWind);
- // calculate wind with normal?
-
- mass.addForce(GRAVITY);
-
- /** integrate motion */
- mass.verlet(dt);
- }
-
- /** run satisfy step */
- for (let constraint of this.springs) {
- constraint.satisfy();
- }
-
- /** prevent self-intersections */
- this.intersect();
- }
-
- intersect() {
- for (let i in this.masses) {
- for (let j in this.masses) {
- let p1 = this.masses[i];
- let p2 = this.masses[j];
-
- 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);
-
- // let v1 = p1.position.clone().sub(p1.previous).normalize();
- // let v2 = p2.position.clone().sub(p2.previous).normalize();
-
- // 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));
- if (p2.movable)
- p2.position.add(diffP1P2);
- //p2.position.add(diffP1P2.multiplyScalar(factor2));
- }
- }
- }
- }
- 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);
- }
-
- /**
- * helper function to calculate index of vertex
- * in "vertices" array based on its x and y positions
- * in the mesh
- * @param {number} x - x index of vertex
- * @param {number} y - y index of vertex
- */
- getVertexIndex(x, y) {
- return y * this.numPointsWidth + x;
- }
- getX(i) { return i % this.numPointsWidth; }
- getY(i) { return Math.floor(i / this.numPointsWidth); }
-}
\ No newline at end of file |
