private void UpdateRopeSimulation(float deltaTime) { //actualizar pos1 en la lista por si se ha movido CilinderBody lastRopeSection = ropeSegments[ropeSegments.Count - 1]; lastRopeSection.pos = new Vector3Class(pos1.position); ropeSegments[ropeSegments.Count - 1] = lastRopeSection; //calcular acceleraciones CalculateAccelerations(); //actualizar la posicion de todos los segmentos excepto el ultimo (top) for (int i = 0; i < ropeSegments.Count - 1; i++) { CilinderBody thisRopeSection = new CilinderBody(); //Forward Euler thisRopeSection.speed = ropeSegments[i].speed + ropeSegments[i].acc * deltaTime; thisRopeSection.pos = ropeSegments[i].pos + ropeSegments[i].speed * deltaTime; ropeSegments[i] = thisRopeSection; } //regular estiramiento de los segmentos, tambien se recomienda ejecutar mas de una vez (para corregir el maximo posible) //ya que cuando se cambia la posicion de uno, quiza hace falta regular el resto, y quizá sólo serian accesibles repitiendo el proceso int maximumStretchIterations = 2; for (int i = 0; i < maximumStretchIterations; i++) { ImplementMaximumStretch(); } }
private void CalculateAccelerations() { //calculamos la fuerza de cada muelle y las guardamos en una lista para luego adjudicarla a los segmentos List <Vector3Class> springForces = new List <Vector3Class>(); for (int i = 0; i < ropeSegments.Count - 1; i++) { Vector3Class p1p2 = ropeSegments[i + 1].pos - ropeSegments[i].pos; //elasticity part float part1 = kElasticity * (p1p2.Size() - stringPartLength); //Damping part float part2 = kDamping * ((p1p2.DotProduct(ropeSegments[i + 1].speed - ropeSegments[i].speed, p1p2.Normalize(p1p2)))); //calculamos total del muelle juntando las 2 partes Vector3Class resultForce = p1p2.Normalize(p1p2); resultForce *= (part1 + part2) * -1; //al estar el orden de pos2 a pos1, este force es el negativo (f2) resultForce *= -1; springForces.Add(resultForce); } for (int i = 0; i < ropeSegments.Count - 1; i++) { Vector3Class springForce = new Vector3Class(); //spring que corresponde a F1 de la formula if (i != 0) { springForce -= springForces[i - 1]; } //spring que corresponde a F2 de la formula springForce += springForces[i]; //masa del segmento de la cuerda, hacemos variable a parte para añadir el peso de la bola al ultimo float springMass = massRopeSegment; //segmento con la bola if (i == 0) { springMass = massLastRopeSegment; } //creamos fuerza de gravedad con la masa Vector3Class gravityForce = new Vector3Class(0f, gravity, 0f); gravityForce *= springMass; //sumamos ambas fuerzas calculadas Vector3Class totalForce = springForce + gravityForce; //finalmente, calculamos la aceleracion resultante de la fuerza Vector3Class acceleration = totalForce / springMass; CilinderBody temp = ropeSegments[i]; temp.acc = acceleration; ropeSegments[i] = temp; } }
private void ImplementMaximumStretch() { //loop por todos los puntos para ajustarlos, de arriba a abajo for (int i = ropeSegments.Count - 1; i > 0; i--) { //recibimos 2 segmentos para comparar Vector3Class topSegment = ropeSegments[i].pos; CilinderBody bottomSegment = ropeSegments[i - 1]; //este es CilinderBody porque modificaremos su pos si hace falta //distancia entre ambos segmentos float dist = (topSegment - bottomSegment.pos).Size(); //si esta distancia supera el maximo if (dist > maxStretch) { //calculamos la diferencia entre la distancia actual y el maximo fijado float diffenceLength = dist - maxStretch; //vector normalizado para establecer la direccion del vector para ajustar el segmento Vector3Class adjustDirection = topSegment.Normalize(topSegment - bottomSegment.pos); //vector resultante para ajustar al segmento Vector3Class adjustVec = adjustDirection * diffenceLength; //sumamos vector resultante con posicion de bottomsegment y actualizamos pos del segmento bottomSegment.pos += adjustVec; ropeSegments[i - 1] = bottomSegment; } else if (dist < minStretch) { //calculamos la diferencia entre la distancia actual y el maximo fijado float differenceLength = minStretch - dist; //vector normalizado para establecer la direccion del vector para ajustar el segmento Vector3Class adjustDirection = topSegment.Normalize(bottomSegment.pos - topSegment); //vector resultante para ajustar al segmento Vector3Class adjustVec = adjustDirection * differenceLength; //sumamos vector resultante con posicion de bottomsegment y actualizamos pos del segmento bottomSegment.pos += adjustVec; ropeSegments[i - 1] = bottomSegment; } } }