From a30256db1a628e1fd7f9a1537bebb9bdea8f3719 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Patrick=20Sch=C3=B6nberger?= Date: Mon, 18 Jan 2021 15:10:05 +0100 Subject: [PATCH 1/1] make vertices rigid, tune parameters --- Scripts/cloth.js | 77 +++++++++++++++++++++++++++++++++--------------- Scripts/main.js | 12 ++++---- 2 files changed, 60 insertions(+), 29 deletions(-) diff --git a/Scripts/cloth.js b/Scripts/cloth.js index 9389ef6..600ac8f 100644 --- a/Scripts/cloth.js +++ b/Scripts/cloth.js @@ -76,6 +76,11 @@ export class Spring { return direction; } + + update(vertices) { + let length = vectorLength(vertices[this.index1], vertices[this.index2]); + this.currentLength = length; + } } /** @@ -94,7 +99,7 @@ export class Cloth { vertexWeights = []; - + vertexRigidness = []; /** * creates a rectangular piece of cloth @@ -170,6 +175,12 @@ export class Cloth { * with generated vertices and faces */ this.createExplicit(vertices, faces); + + /** + * hand cloth from left and right upper corners + */ + this.vertexRigidness[0] = true; + this.vertexRigidness[numPointsWidth-1] = true; } /** @@ -189,6 +200,7 @@ export class Cloth { this.geometry.vertices.push(vertices[i]); this.previousPositions.push(vertices[i]); this.vertexWeights.push(0); + this.vertexRigidness.push(false); } /** * copy faces, @@ -306,22 +318,30 @@ export class Cloth { * @param {number} dt */ simulate(dt) { - - - for (let i in this.geometry.vertices) { let currentPosition; let acceleration = this.getAcceleration(i, dt); + + // TODO: decide on clamping + acceleration.clampLength(0, 100); - currentPosition = this.verlet(this.geometry.vertices[i], this.previousPositions[i], acceleration, dt/2000); + currentPosition = this.verlet(this.geometry.vertices[i], this.previousPositions[i], acceleration, dt/500); + //currentPosition = this.euler(this.geometry.vertices[i], acceleration, dt/10); this.previousPositions[i] = currentPosition; this.geometry.vertices[i] = currentPosition; - } - console.log(this.geometry.vertices[0]); + + //this.getAcceleration(1, dt, true); + this.time += dt; + for (let face of this.faces) { + for (let spring of face.springs) { + spring.update(this.geometry.vertices); + } + } + /** * let THREE JS compute bounding sphere around generated mesh * needed for View Frustum Culling internally @@ -341,22 +361,26 @@ export class Cloth { * @param {number} dt The time passed since last frame */ getAcceleration(vertexIndex, dt) { + if (this.vertexRigidness[vertexIndex]) + return new THREE.Vector3(0, 0, 0); let vertex = this.geometry.vertices[vertexIndex]; // Mass of vertex let M = this.vertexWeights[vertexIndex]; // constant gravity - let g = new THREE.Vector3(0, -1.8, 0); + let g = new THREE.Vector3(0, -9.8, 0); // stiffness - let k = 5; + let k = 300; // Wind vector + // TODO: include wind vector let fWind = new THREE.Vector3( Math.sin(vertex.x * vertex.y * this.time), Math.cos(vertex.z* this.time), Math.sin(Math.cos(5 * vertex.x * vertex.y * vertex.z)) ); + fWind = new THREE.Vector3(0, 0, 0); /** * constant determined by the properties of the surrounding fluids (air) @@ -365,17 +389,19 @@ getAcceleration(vertexIndex, dt) { let a = 1; let velocity = new THREE.Vector3( - (vertex.x - this.previousPositions[vertexIndex].x) / dt, - (vertex.y - this.previousPositions[vertexIndex].y) / dt, - (vertex.z - this.previousPositions[vertexIndex].z) / dt + (vertex.x - this.previousPositions[vertexIndex].x) * dt, + (vertex.y - this.previousPositions[vertexIndex].y) * dt, + (vertex.z - this.previousPositions[vertexIndex].z) * dt ); - - let fAirResistance = velocity.multiplyScalar(-a); + // TODO: include air resistance + let fAirResistance = velocity.multiply(velocity).multiplyScalar(-a); + fAirResistance = new THREE.Vector3(0, 0, 0); let springSum = new THREE.Vector3(0, 0, 0); // Get the bounding springs and add them to the needed springs + // TODO: optimize for (let i in this.faces) { if (this.faces[i].a == vertexIndex || this.faces[i].b == vertexIndex || this.faces[i].c == vertexIndex || this.faces[i].d == vertexIndex) { for (let j in this.faces[i].springs) { @@ -385,26 +411,20 @@ getAcceleration(vertexIndex, dt) { let springDirection = spring.getDirection(this.geometry.vertices); - if (this.faces[i].springs[j].index1 == vertexIndex) + if (this.faces[i].springs[j].index2 == vertexIndex) springDirection.multiplyScalar(-1); springSum.add(springDirection.multiplyScalar(k * (spring.currentLength - spring.restLength))); - } } } } - let result = new THREE.Vector3(1, 1, 1); - result.multiplyScalar(M).multiply(g).add(fWind).add(fAirResistance).sub(springSum); - return result; - - } /** @@ -422,14 +442,23 @@ verlet(currentPosition, previousPosition, acceleration, passedTime) { // Dependency for one vertex: gravity, fluids/air, springs let nextPosition = new THREE.Vector3( - 2 * currentPosition.x - previousPosition.x + acceleration.x * (passedTime * passedTime), - 2 * currentPosition.y - previousPosition.y + acceleration.y * (passedTime * passedTime), - 2 * currentPosition.z - previousPosition.z + acceleration.z * (passedTime * passedTime), + (2 * currentPosition.x) - previousPosition.x + acceleration.x * (passedTime * passedTime), + (2 * currentPosition.y) - previousPosition.y + acceleration.y * (passedTime * passedTime), + (2 * currentPosition.z) - previousPosition.z + acceleration.z * (passedTime * passedTime), ); return nextPosition; } +euler(currentPosition, acceleration, passedTime) { + let nextPosition = new THREE.Vector3( + currentPosition.x + acceleration.x * passedTime, + currentPosition.y + acceleration.y * passedTime, + currentPosition.z + acceleration.z * passedTime, + ); + + return nextPosition; +} } diff --git a/Scripts/main.js b/Scripts/main.js index 5ed1866..ececd6a 100644 --- a/Scripts/main.js +++ b/Scripts/main.js @@ -65,13 +65,16 @@ function init() { */ const canvasSpace = 200; + /** Constant Frame Time */ + const frameTime = 1000.0 / 60.0; + /** Setup scene */ let [scene, camera, renderer] = setup_scene(canvasSpace); /** setup cloth and generate debug mesh */ let cloth = new Cloth(); - cloth.createBasic(10, 10, 5, 5); - cloth.createDebugMesh(scene); + cloth.createBasic(10, 10, 10, 10); + //cloth.createDebugMesh(scene); const material = new THREE.MeshBasicMaterial({ color: 0x0000ff }); const mesh = new THREE.Mesh(cloth.geometry, material); @@ -87,12 +90,11 @@ function init() { * @param {number} dt - time passed since last frame */ function animate(dt) { - cloth.simulate(dt); setTimeout(() => { - animate(2000); - }, 2000); + animate(frameTime); + }, frameTime); renderer.render(scene, camera); } -- 2.50.1