]> gitweb.ps.run Git - cloth_sim/blobdiff - Scripts/cloth.js
tweaking parameters
[cloth_sim] / Scripts / cloth.js
index 14975839294f6f45356f3e2e2802d94c3c7cb456..aaa9d249a25a9702d3abd95d46a1d317f5a95f76 100644 (file)
-/**\r
- *  Convenience Function for calculating the distance between two vectors\r
- *  because THREE JS Vector functions mutate variables\r
- * @param {Vector3} a - Vector A\r
- * @param {Vector3} b - Vector B\r
- */\r
-function vectorLength(a, b) {\r
-  let v1 = new THREE.Vector3();\r
-  v1.copy(a);\r
-  let v2 = new THREE.Vector3();\r
-  v2.copy(b);\r
-\r
-  return v1.sub(v2).length();\r
-}\r
-\r
-/**\r
- * Class representing a quad face\r
- * Each face consists of two triangular mesh faces\r
- * containts four indices for determining vertices\r
- * and six springs, one between each of the vertices\r
- */\r
-export class Face {\r
-  a;\r
-  b;\r
-  c;\r
-  d;\r
-\r
-  springs = [];\r
+const DAMPING = 0.03;\r
+const DRAG = 1 - DAMPING;\r
+const MASS = 0.35;\r
+const GRAVITY = new THREE.Vector3(0, -9.81 * MASS, 0);\r
+const K = 1;\r
+\r
+const options = {\r
+  wind: true,\r
+};\r
+\r
+class Constraint {\r
+  constructor(p1, p2, restDist) {\r
+    this.p1 = p1;\r
+    this.p2 = p2;\r
+    this.restDist = restDist;\r
+  }\r
 \r
-  constructor(a, b, c, d) {\r
-    this.a = a;\r
-    this.b = b;\r
-    this.c = c;\r
-    this.d = d;\r
+  satisfy() {\r
+    const diff = this.p2.position.clone().sub(this.p1.position);\r
+    const currentDist = diff.length();\r
+    if (currentDist == 0) return;\r
+    if (currentDist <= this.restDist) return;\r
+    //const correction = diff.multiplyScalar(1 - (this.restDist / currentDist));\r
+    const correction = diff.multiplyScalar((currentDist - this.restDist) / currentDist);\r
+    correction.multiplyScalar(K);\r
+    correction.clampLength(0, 1);\r
+    const correctionHalf = correction.multiplyScalar(0.5);\r
+    if (this.p1.movable && this.p2.movable) {\r
+      this.p1.position.add(correctionHalf);\r
+      this.p2.position.sub(correctionHalf);\r
+    } else if (! this.p1.movable && this.p2.movable) {\r
+      this.p2.position.sub(correction);\r
+    } else if (this.p1.movable && ! this.p2.movable) {\r
+      this.p1.position.add(correction);\r
+    }\r
   }\r
 }\r
 \r
-/**\r
- * Class representing a single spring\r
- * has a current and resting length\r
- * and indices to the two connected vertices\r
- */\r
-export class Spring {\r
-  restLength;\r
-  currentLength;\r
-  index1;\r
-  index2;\r
+class Particle {\r
+  movable = true;\r
 \r
-\r
-  /**\r
-   * set vertex indices\r
-   * and calculate inital length based on the\r
-   * vertex positions\r
-   * @param {Array<Vector3>} vertices \r
-   * @param {number} index1 \r
-   * @param {number} index2 \r
-   */\r
-  constructor(vertices, index1, index2) {\r
-    this.index1 = index1;\r
-    this.index2 = index2;\r
-\r
-    let length = vectorLength(vertices[index1], vertices[index2]);\r
-    this.restLength = length;\r
-    this.currentLength = length;\r
+  constructor(x, y, z, mass) {\r
+    this.position = new THREE.Vector3(x, y, z);\r
+    this.previous = new THREE.Vector3(x, y, z);\r
+    this.acceleration = new THREE.Vector3(0, 0, 0);\r
+    this.mass = mass;\r
   }\r
-\r
-  getDirection(vertices) {\r
-    let direction = new THREE.Vector3();\r
-    direction.copy(vertices[this.index1]);\r
-\r
-    direction.sub(vertices[this.index2]);\r
-    direction.divideScalar(vectorLength(vertices[this.index1], vertices[this.index2]));\r
-\r
-    return direction;\r
+  addForce(force) {\r
+    this.acceleration.add(\r
+      force.clone().multiplyScalar(1/this.mass)\r
+    );\r
   }\r
+  verlet(dt) {\r
+    // verlet algorithm\r
+    // next position = 2 * current Position - previous position + acceleration * (passed time)^2\r
+    // acceleration (dv/dt) = F(net)\r
+    const nextPosition = this.position.clone().sub(this.previous);\r
+    nextPosition.multiplyScalar(DRAG);\r
+    nextPosition.add(this.position);\r
+    nextPosition.add(this.acceleration.multiplyScalar(dt*dt));\r
+\r
+    if (this.movable) {\r
+      this.previous = this.position;\r
+      this.position = nextPosition;\r
+    }\r
 \r
-  update(vertices) {\r
-    let length = vectorLength(vertices[this.index1], vertices[this.index2]);\r
-    this.currentLength = length;\r
+    this.acceleration.set(0, 0, 0);\r
   }\r
 }\r
 \r
-/**\r
- * Class representing a single piece of cloth\r
- * contains THREE JS geometry,\r
- * logically represented by an array of adjacent faces\r
- * and vertex weights which are accessed by the same\r
- * indices as the vertices in the Mesh\r
- */\r
-export class Cloth {\r
-  VertexWeight = 1;\r
-\r
-  geometry = new THREE.Geometry();\r
-\r
-  faces = [];\r
-\r
-  vertexWeights = [];\r
-\r
-  vertexRigidness = [];\r
-\r
-  /**\r
-   * creates a rectangular piece of cloth\r
-   * takes the size of the cloth\r
-   * and the number of vertices it should be composed of\r
-   * @param {number} width - width of the cloth\r
-   * @param {number} height - height of the cloth\r
-   * @param {number} numPointsWidth - number of vertices in horizontal direction\r
-   * @param {number} numPointsHeight  - number of vertices in vertical direction\r
-   */\r
-  createBasic(width, height, numPointsWidth, numPointsHeight) {\r
-    /** resulting vertices and faces */\r
-    let vertices = [];\r
-    let faces = [];\r
+class Cloth {\r
+  constructor(width, height, numPointsWidth, numPointsHeight) {\r
+    this.width = width;\r
+    this.height = height;\r
+    this.numPointsWidth = numPointsWidth;\r
+    this.numPointsHeight = numPointsHeight;\r
+    this.windFactor = new THREE.Vector3(5, 2, 2);\r
 \r
     /**\r
      * distance between two vertices horizontally/vertically\r
@@ -122,342 +86,143 @@ export class Cloth {
 \r
     /**\r
      * iterate over the number of vertices in x/y axis\r
-     * and add a new Vector3 to "vertices"\r
+     * and add a new Particle to "particles"\r
      */\r
+    this.particles = [];\r
     for (let y = 0; y < numPointsHeight; y++) {\r
       for (let x = 0; x < numPointsWidth; x++) {\r
-        vertices.push(\r
-          new THREE.Vector3(x * stepWidth, height - y * stepHeight, 0)\r
+        this.particles.push(\r
+          new Particle(\r
+            (x - ((numPointsWidth-1)/2)) * stepWidth,\r
+            height - (y + ((numPointsHeight-1)/2)) * stepHeight,\r
+            0,\r
+            MASS)\r
         );\r
       }\r
     }\r
 \r
+    //this.particles[this.getVertexIndex(0, 0)].movable = false;\r
+    const n = 3;\r
+    for (let i = 0; i <= n; i++)\r
+      this.particles[this.getVertexIndex(0, Math.floor((numPointsHeight-1)*(i/n)))].movable = false;\r
+    //this.particles[this.getVertexIndex(0, numPointsHeight-1)].movable = false;\r
+    //this.particles[this.getVertexIndex(numPointsWidth-1, 0)].movable = false;\r
+\r
+    const REST_DIST_X = width / (numPointsWidth-1);\r
+    const REST_DIST_Y = height / (numPointsHeight-1);\r
+\r
     /**\r
-     * helper function to calculate index of vertex\r
-     * in "vertices" array based on its x and y positions\r
-     * in the mesh\r
-     * @param {number} x - x index of vertex\r
-     * @param {number} y - y index of vertex\r
+     * generate constraints (springs)\r
      */\r
-    function getVertexIndex(x, y) {\r
-      return y * numPointsWidth + x;\r
+    this.constraints = [];\r
+    for (let y = 0; y < numPointsHeight; y++) {\r
+      for (let x = 0; x < numPointsWidth; x++) {\r
+        if (x < numPointsWidth-1) {\r
+          this.constraints.push(new Constraint(\r
+            this.particles[this.getVertexIndex(x, y)],\r
+            this.particles[this.getVertexIndex(x+1, y)],\r
+            REST_DIST_X\r
+          ));\r
+        }\r
+        if (y < numPointsHeight-1) {\r
+          this.constraints.push(new Constraint(\r
+            this.particles[this.getVertexIndex(x, y)],\r
+            this.particles[this.getVertexIndex(x, y+1)],\r
+            REST_DIST_Y\r
+          ));\r
+        }\r
+      }\r
+    }\r
+  }\r
+  generateGeometry() {\r
+    const geometry = new THREE.BufferGeometry();\r
+\r
+    const vertices = [];\r
+    const normals = [];\r
+    const indices = [];\r
+\r
+    for (let particle of this.particles) {\r
+      vertices.push(\r
+        particle.position.x,\r
+        particle.position.y,\r
+        particle.position.z);\r
     }\r
 \r
+    const numPointsWidth = this.numPointsWidth;\r
+    const numPointsHeight = this.numPointsHeight;\r
+\r
     /**\r
      * generate faces based on 4 vertices\r
      * and 6 springs each\r
      */\r
     for (let y = 0; y < numPointsHeight - 1; y++) {\r
       for (let x = 0; x < numPointsWidth - 1; x++) {\r
-        let newFace = new Face(\r
-          getVertexIndex(x, y),\r
-          getVertexIndex(x, y + 1),\r
-          getVertexIndex(x + 1, y),\r
-          getVertexIndex(x + 1, y + 1),\r
+        indices.push(\r
+          this.getVertexIndex(x, y),\r
+          this.getVertexIndex(x+1, y),\r
+          this.getVertexIndex(x+1, y+1)\r
+        );\r
+        indices.push(\r
+          this.getVertexIndex(x, y),\r
+          this.getVertexIndex(x+1, y+1),\r
+          this.getVertexIndex(x, y+1)\r
         );\r
-\r
-        newFace.springs.push(new Spring(vertices, getVertexIndex(x, y), getVertexIndex(x + 1, y)));\r
-        newFace.springs.push(new Spring(vertices, getVertexIndex(x, y), getVertexIndex(x, y + 1)));\r
-        newFace.springs.push(new Spring(vertices, getVertexIndex(x, y), getVertexIndex(x + 1, y + 1)));\r
-        newFace.springs.push(new Spring(vertices, getVertexIndex(x + 1, y), getVertexIndex(x, y + 1)));\r
-        newFace.springs.push(new Spring(vertices, getVertexIndex(x + 1, y), getVertexIndex(x + 1, y + 1)));\r
-        newFace.springs.push(new Spring(vertices, getVertexIndex(x, y + 1), getVertexIndex(x + 1, y + 1)));\r
-\r
-        faces.push(newFace);\r
       }\r
     }\r
 \r
-    /**\r
-     * call createExplicit\r
-     * with generated vertices and faces\r
-     */\r
-    this.createExplicit(vertices, faces);\r
+    geometry.setIndex(indices);\r
+    geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));\r
+    //geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3));\r
+    geometry.computeBoundingSphere();\r
+    geometry.computeVertexNormals();\r
 \r
-    /**\r
-     * hand cloth from left and right upper corners\r
-     */\r
-    this.vertexRigidness[0] = true;\r
-    this.vertexRigidness[numPointsWidth-1] = true;\r
+    return geometry;\r
   }\r
-\r
-  /**\r
-   * Generate THREE JS Geometry\r
-   * (list of vertices and list of indices representing triangles)\r
-   * and calculate the weight of each face and split it between\r
-   * surrounding vertices\r
-   * @param {Array<Vector3>} vertices \r
-   * @param {Array<Face>} faces \r
-   */\r
-  createExplicit(vertices, faces) {\r
-\r
-    /**\r
-     * Copy vertices and initialize vertex weights to 0\r
-     */\r
-    for (let i in vertices) {\r
-      this.geometry.vertices.push(vertices[i].clone());\r
-      this.previousPositions.push(vertices[i].clone());\r
-      // this.geometry.vertices.push(vertices[i]);\r
-      // this.previousPositions.push(vertices[i]);\r
-      this.vertexWeights.push(0);\r
-      this.vertexRigidness.push(false);\r
+  updateGeometry(geometry) {\r
+    const positions = geometry.attributes.position.array;\r
+    for (let i in this.particles) {\r
+      let p = this.particles[i];\r
+      positions[i*3+0] = p.position.x;\r
+      positions[i*3+1] = p.position.y;\r
+      positions[i*3+2] = p.position.z;\r
     }\r
-    /**\r
-     * copy faces,\r
-     * generate two triangles per face,\r
-     * calculate weight of face as its area\r
-     * and split between the 4 vertices\r
-     */\r
-    for (let i in faces) {\r
-      let face = faces[i];\r
-\r
-      /** copy faces to class member */\r
-      this.faces.push(face);\r
-\r
-      /** generate triangles */\r
-      this.geometry.faces.push(new THREE.Face3(\r
-        face.a, face.b, face.c\r
-      ));\r
-      this.geometry.faces.push(new THREE.Face3(\r
-        face.c, face.b, face.d\r
-      ));\r
-\r
-      /**\r
-       * calculate area of face as combined area of\r
-       * its two composing triangles\r
-       */\r
-      let xLength = vectorLength(this.geometry.vertices[face.b], this.geometry.vertices[face.a]);\r
-      let yLength = vectorLength(this.geometry.vertices[face.c], this.geometry.vertices[face.a]);\r
-      let weight = xLength * yLength / 2;\r
-\r
-      xLength = vectorLength(this.geometry.vertices[face.b], this.geometry.vertices[face.d]);\r
-      yLength = vectorLength(this.geometry.vertices[face.c], this.geometry.vertices[face.d]);\r
-      weight += xLength * yLength / 2;\r
-\r
-      /**\r
-       * split weight equally between four surrounding vertices\r
-       */\r
-      this.vertexWeights[face.a] += weight / 4;\r
-      this.vertexWeights[face.b] += weight / 4;\r
-      this.vertexWeights[face.c] += weight / 4;\r
-      this.vertexWeights[face.d] += weight / 4;\r
-    }\r
-\r
-    /**\r
-     * let THREE JS compute bounding sphere around generated mesh\r
-     * needed for View Frustum Culling internally\r
-     */\r
-    this.geometry.computeBoundingSphere();\r
+    geometry.attributes.position.needsUpdate = true;\r
+    geometry.computeBoundingSphere();\r
+    geometry.computeVertexNormals();\r
   }\r
-\r
-  /**\r
-   * generate a debug mesh for visualizing\r
-   * vertices and springs of the cloth\r
-   * and add it to scene for rendering\r
-   * @param {Scene} scene - Scene to add Debug Mesh to\r
-   */\r
-  createDebugMesh(scene) {\r
-    /**\r
-     * helper function to generate a single line\r
-     * between two Vertices with a given color\r
-     * @param {Vector3} from \r
-     * @param {Vector3} to \r
-     * @param {number} color \r
-     */\r
-    function addLine(from, to, color) {\r
-      let geometry = new THREE.Geometry();\r
-      geometry.vertices.push(from);\r
-      geometry.vertices.push(to);\r
-      let material = new THREE.LineBasicMaterial({ color: color, linewidth: 10 });\r
-      let line = new THREE.Line(geometry, material);\r
-      line.renderOrder = 1;\r
-      scene.add(line);\r
-    }\r
-    /**\r
-     * helper function to generate a small sphere\r
-     * at a given Vertex Position with color\r
-     * @param {Vector3} point \r
-     * @param {number} color \r
-     */\r
-    function addPoint(point, color) {\r
-      const geometry = new THREE.SphereGeometry(0.05, 32, 32);\r
-      const material = new THREE.MeshBasicMaterial({ color: color });\r
-      const sphere = new THREE.Mesh(geometry, material);\r
-      sphere.position.set(point.x, point.y, point.z);\r
-      scene.add(sphere);\r
-    }\r
-\r
-    let lineColor = 0x000000;\r
-    let pointColor = 0xff00000;\r
-\r
-    /**\r
-     * generate one line for each of the 6 springs\r
-     * and one point for each of the 4 vertices\r
-     * for all of the faces\r
-     */\r
-    for (let i in this.faces) {\r
-      let face = this.faces[i];\r
-      addLine(this.geometry.vertices[face.a], this.geometry.vertices[face.b], lineColor);\r
-      addLine(this.geometry.vertices[face.a], this.geometry.vertices[face.c], lineColor);\r
-      addLine(this.geometry.vertices[face.a], this.geometry.vertices[face.d], lineColor);\r
-      addLine(this.geometry.vertices[face.b], this.geometry.vertices[face.c], lineColor);\r
-      addLine(this.geometry.vertices[face.b], this.geometry.vertices[face.d], lineColor);\r
-      addLine(this.geometry.vertices[face.c], this.geometry.vertices[face.d], lineColor);\r
-\r
-      addPoint(this.geometry.vertices[face.a], pointColor);\r
-      addPoint(this.geometry.vertices[face.b], pointColor);\r
-      addPoint(this.geometry.vertices[face.c], pointColor);\r
-      addPoint(this.geometry.vertices[face.d], pointColor);\r
-    }\r
-  }\r
-\r
-  previousPositions = [];\r
-  time = 0;\r
-  /**\r
-   * \r
-   * @param {number} dt time in seconds since last frame\r
-   */\r
   simulate(dt) {\r
-    for (let i in this.geometry.vertices) {\r
-      let acceleration = this.getAcceleration(i, dt);\r
-\r
-      //acceleration.clampLength(0, 10);\r
-\r
-      if (Math.abs(acceleration.length()) <= 10e-4) {\r
-        acceleration.set(0, 0, 0);\r
-      }\r
\r
-      let currentPosition = this.verlet(this.geometry.vertices[i].clone(), this.previousPositions[i].clone(), acceleration, dt);\r
-      //let currentPosition = this.euler(this.geometry.vertices[i], acceleration, dt);\r
-     \r
-      this.previousPositions[i].copy(this.geometry.vertices[i]);\r
-      this.geometry.vertices[i].copy(currentPosition);\r
+    let now = performance.now();\r
+    for (let particle of this.particles) {\r
+      let vertex = particle.position;\r
+      let fWind = new THREE.Vector3(\r
+        this.windFactor.x * (Math.sin(vertex.x * vertex.y * now)+1),\r
+        this.windFactor.y * Math.cos(vertex.z * now),\r
+        this.windFactor.z * Math.sin(Math.cos(5 * vertex.x * vertex.y * vertex.z))\r
+      );\r
+      // normalize then multiply?\r
+      if (options.wind)\r
+        particle.addForce(fWind);\r
+      // calculate wind with normal?\r
+\r
+      particle.addForce(GRAVITY);\r
+\r
+      particle.verlet(dt);\r
     }\r
-    //console.log(this.getAcceleration(1, dt));\r
-    \r
-    this.time += dt;\r
 \r
-    for (let face of this.faces) {\r
-      for (let spring of face.springs) {\r
-        spring.update(this.geometry.vertices);\r
-      }\r
+    \r
+    for (let constraint of this.constraints) {\r
+      constraint.satisfy();\r
     }\r
-\r
-    /**\r
-     * let THREE JS compute bounding sphere around generated mesh\r
-     * needed for View Frustum Culling internally\r
-     */\r
-\r
-    this.geometry.verticesNeedUpdate = true;\r
-    this.geometry.elementsNeedUpdate = true;\r
-    this.geometry.computeBoundingSphere();\r
-\r
+    //console.log(tmpCorrection);\r
   }\r
-\r
-\r
-\r
-/**\r
- * Equation of motion for each vertex which represents the acceleration \r
- * @param {number} vertexIndex The index of the current vertex whose acceleration should be calculated\r
- *  @param {number} dt The time passed since last frame\r
- */\r
-getAcceleration(vertexIndex, dt) {\r
-  if (this.vertexRigidness[vertexIndex])\r
-    return new THREE.Vector3(0, 0, 0);\r
-\r
-  let vertex = this.geometry.vertices[vertexIndex];\r
-\r
-  // Mass of vertex\r
-  let M = this.vertexWeights[vertexIndex];\r
-  // constant gravity\r
-  let g = new THREE.Vector3(0, -9.8, 0);\r
-  // stiffness\r
-  let k = 1000;\r
-\r
-  // Wind vector\r
-  let fWind = new THREE.Vector3(\r
-    Math.sin(vertex.x * vertex.y * this.time),\r
-    Math.cos(vertex.z * this.time),\r
-    Math.sin(Math.cos(5 * vertex.x * vertex.y * vertex.z))\r
-  );\r
-  fWind.set(0, 0, 0);\r
-\r
   /**\r
-   * constant determined by the properties of the surrounding fluids (air)\r
-   * achievement of cloth effects through try out\r
-   * */\r
-  let a = 0.01;\r
-\r
-  let velocity = new THREE.Vector3(\r
-    (this.previousPositions[vertexIndex].x - vertex.x) / dt,\r
-    (this.previousPositions[vertexIndex].y - vertex.y) / dt,\r
-    (this.previousPositions[vertexIndex].z - vertex.z) / dt\r
-  );\r
-\r
-  //console.log(velocity, vertex, this.previousPositions[vertexIndex]);\r
-\r
-  let fAirResistance = velocity.cross(velocity).multiplyScalar(-a);\r
-\r
-  let springSum = new THREE.Vector3(0, 0, 0);\r
-\r
-  // Get the bounding springs and add them to the needed springs\r
-  // TODO: optimize\r
-  for (let i in this.faces) {\r
-    if (this.faces[i].a == vertexIndex || this.faces[i].b == vertexIndex || this.faces[i].c == vertexIndex || this.faces[i].d == vertexIndex) {\r
-      for (let j in this.faces[i].springs) {\r
-        if (this.faces[i].springs[j].index1 == vertexIndex || this.faces[i].springs[j].index2 == vertexIndex) {\r
-\r
-          let spring = this.faces[i].springs[j];\r
-          let springDirection = spring.getDirection(this.geometry.vertices);\r
-\r
-\r
-          if (this.faces[i].springs[j].index1 == vertexIndex)\r
-            springDirection.multiplyScalar(-1);\r
-\r
-          springSum.add(springDirection.multiplyScalar(k * (spring.restLength - spring.currentLength)));\r
-        }\r
-      }\r
-    }\r
+   * helper function to calculate index of vertex\r
+   * in "vertices" array based on its x and y positions\r
+   * in the mesh\r
+   * @param {number} x - x index of vertex\r
+   * @param {number} y - y index of vertex\r
+   */\r
+  getVertexIndex(x, y) {\r
+    return y * this.numPointsWidth + x;\r
   }\r
-  \r
-  let result = new THREE.Vector3(1, 1, 1);\r
-\r
-  result.multiplyScalar(M).multiply(g).add(fWind).add(fAirResistance).sub(springSum);\r
-  \r
-  return result;\r
-}\r
-\r
-/**\r
- * The Verlet algorithm as an integrator \r
- * to get the next position of a vertex  \r
- * @param {Vector3} currentPosition \r
- * @param {Vector3} previousPosition \r
- * @param {Vector3} acceleration \r
- * @param {number} passedTime The delta time since last frame\r
- */\r
-verlet(currentPosition, previousPosition, acceleration, passedTime) {\r
-  // verlet algorithm\r
-  // next position = 2 * current Position - previous position + acceleration * (passed time)^2\r
-  // acceleration (dv/dt) = F(net)\r
-  // Dependency for one vertex: gravity, fluids/air, springs\r
-\r
-  let nextPosition = new THREE.Vector3(\r
-    (2 * currentPosition.x) - previousPosition.x + acceleration.x * (passedTime * passedTime),\r
-    (2 * currentPosition.y) - previousPosition.y + acceleration.y * (passedTime * passedTime),\r
-    (2 * currentPosition.z) - previousPosition.z + acceleration.z * (passedTime * passedTime),\r
-  );\r
-\r
-  return nextPosition;\r
-}\r
-\r
-euler(currentPosition, acceleration, passedTime) {\r
-  let nextPosition = new THREE.Vector3(\r
-    currentPosition.x + acceleration.x * passedTime,\r
-    currentPosition.y + acceleration.y * passedTime,\r
-    currentPosition.z + acceleration.z * passedTime,\r
-  );\r
-\r
-  return nextPosition;\r
-}\r
-\r
-}\r
-\r
+}
\ No newline at end of file