public void ChangeLength(float newLength) { // clamp new length to sane limits: newLength = Mathf.Clamp(newLength, 0, (rope.blueprint.particleCount - 1) * rope.ropeBlueprint.interParticleDistance); // calculate the change in rope length: float lengthChange = newLength - rope.restLength; // remove: if (lengthChange < 0) { lengthChange = -lengthChange; while (lengthChange > m_CursorElement.restLength) { lengthChange -= m_CursorElement.restLength; int index = rope.elements.IndexOf(m_CursorElement); if (index >= 0) { // positive direction: if (direction) { RemoveParticleAt(rope.solver.particleToActor[m_CursorElement.particle2].indexInActor); rope.elements.RemoveAt(index); if (index < rope.elements.Count && rope.elements[index].particle1 == m_CursorElement.particle2) { rope.elements[index].particle1 = m_CursorElement.particle1; } m_CursorElement = rope.elements[index]; } else // negative direction: { RemoveParticleAt(rope.solver.particleToActor[m_CursorElement.particle1].indexInActor); rope.elements.RemoveAt(index); if (index > 0) { if (rope.elements[index - 1].particle2 == m_CursorElement.particle1) { rope.elements[index - 1].particle2 = m_CursorElement.particle2; } m_CursorElement = rope.elements[index - 1]; } else { m_CursorElement = rope.elements[0]; } } } } // the remaining length is subtracted from the current constraint: if (lengthChange > 0) { m_CursorElement.restLength = Mathf.Max(0, m_CursorElement.restLength - lengthChange); } } // add else { float lengthDelta = Mathf.Min(lengthChange, Mathf.Max(0, rope.ropeBlueprint.interParticleDistance - m_CursorElement.restLength)); // extend the current element, if possible: if (lengthDelta > 0) { m_CursorElement.restLength += lengthDelta; lengthChange -= lengthDelta; } // once the current element has been extended, see if we must add new elements: while (m_CursorElement.restLength + lengthChange > rope.ropeBlueprint.interParticleDistance) { // calculate added length: lengthDelta = Mathf.Min(lengthChange, rope.ropeBlueprint.interParticleDistance); lengthChange -= lengthDelta; if (direction) { // add new particle: int newParticleSolverIndex = AddParticleAt(rope.solver.particleToActor[m_CursorElement.particle1].indexInActor); // insert a new element: ObiStructuralElement newElement = new ObiStructuralElement(); newElement.restLength = lengthDelta; newElement.particle1 = m_CursorElement.particle1; newElement.particle2 = newParticleSolverIndex; m_CursorElement.particle1 = newParticleSolverIndex; int index = rope.elements.IndexOf(m_CursorElement); rope.elements.Insert(index, newElement); m_CursorElement = newElement; } else { // add new particle: int newParticleSolverIndex = AddParticleAt(rope.solver.particleToActor[m_CursorElement.particle2].indexInActor); // insert a new element: ObiStructuralElement newElement = new ObiStructuralElement(); newElement.restLength = lengthDelta; newElement.particle1 = newParticleSolverIndex; newElement.particle2 = m_CursorElement.particle2; m_CursorElement.particle2 = newParticleSolverIndex; int index = rope.elements.IndexOf(m_CursorElement); rope.elements.Insert(index + 1, newElement); m_CursorElement = newElement; } } // the remaining length is added to the current constraint: if (lengthChange > 0) { m_CursorElement.restLength += lengthChange; } } rope.RebuildConstraintsFromElements(); rope.RecalculateRestLength(); }
/** * Changes the length of the rope, adding or removing particles from its end as needed (as long as there are enough pooled particles * left). Since particles are added/removed to/from the end only, any existing particle data (masses, editor selection data) will * be preserved for existing particles when adding new ones. */ public void ChangeLength(float newLength) { if (rope == null) { return; } // Clamp new length to sane limits: newLength = Mathf.Clamp(newLength, 0, (rope.TotalParticles - 1) * rope.InterparticleDistance); // find current extrusion constraint: int constraint = rope.GetConstraintIndexAtNormalizedCoordinate(normalizedCoord); // get constraint batch: ObiDistanceConstraintBatch distanceBatch = rope.DistanceConstraints.GetFirstBatch(); // calculate the change in rope length: float lengthChange = newLength - rope.RestLength; // calculate length change of current constraint: float constraintLengthChange = Mathf.Clamp(lengthChange, -distanceBatch.restLengths[constraint], rope.InterparticleDistance - distanceBatch.restLengths[constraint]); distanceBatch.restLengths[constraint] += constraintLengthChange; lengthChange -= constraintLengthChange; // figure out how many particles we need to add (or remove) and what length will remain after that: int particleChange = lengthChange > 0 ? Mathf.CeilToInt(lengthChange / rope.InterparticleDistance): Mathf.FloorToInt(lengthChange / rope.InterparticleDistance); float remainingLenght = ObiUtils.Mod(lengthChange, rope.InterparticleDistance); if (particleChange > 0) { particleChange = AddParticles(particleChange); // we cannot add any particles, so extend the segment as much as possible. if (particleChange == 0) { remainingLenght = rope.InterparticleDistance; } // Add remaining lenght to the new constraint: constraint = rope.GetConstraintIndexAtNormalizedCoordinate(normalizedCoord); distanceBatch.restLengths[constraint] = remainingLenght; } else if (particleChange < 0) { particleChange = RemoveParticles(-particleChange); // we cannot remove any particles, so reduce the segment as much as possible: if (particleChange == 0) { remainingLenght = 0; } // Add remaining lenght to the new constraint: constraint = rope.GetConstraintIndexAtNormalizedCoordinate(normalizedCoord); distanceBatch.restLengths[constraint] = remainingLenght; } distanceBatch.PushDataToSolver(rope.DistanceConstraints); // Update rest length: rope.RecalculateRestLength(); }