/// <summary> /// Updates the positions of bones acted upon by the joints given to this solver. /// This variant of the solver can be used when there are no goal-driven controls in the simulation. /// This amounts to running just the 'fixer iterations' of a normal control-driven solve. /// </summary> public void Solve(List <IKJoint> joints) { ActiveSet.UpdateActiveSet(joints); //Reset the permutation index; every solve should proceed in exactly the same order. permutationMapper.PermutationIndex = 0; float updateRate = 1 / TimeStepDuration; foreach (var joint in ActiveSet.joints) { joint.Preupdate(TimeStepDuration, updateRate); } for (int i = 0; i < FixerIterationCount; i++) { //Update the world inertia tensors of objects for the latest position. foreach (Bone bone in ActiveSet.bones) { bone.UpdateInertiaTensor(); } //Update the per-constraint jacobians and effective mass for the current bone orientations and positions. foreach (IKJoint joint in ActiveSet.joints) { joint.UpdateJacobiansAndVelocityBias(); joint.ComputeEffectiveMass(); joint.WarmStart(); } for (int j = 0; j < VelocitySubiterationCount; j++) { //A permuted version of the indices is used. The randomization tends to avoid issues with solving order in corner cases. for (int jointIndex = 0; jointIndex < ActiveSet.joints.Count; ++jointIndex) { int remappedIndex = permutationMapper.GetMappedIndex(jointIndex, ActiveSet.joints.Count); ActiveSet.joints[remappedIndex].SolveVelocityIteration(); } //Increment to use the next permutation. ++permutationMapper.PermutationIndex; } //Integrate the positions of the bones forward. foreach (Bone bone in ActiveSet.bones) { bone.UpdatePosition(); } } //Clear out accumulated impulses; they should not persist through to another solving round because the state could be arbitrarily different. for (int j = 0; j < ActiveSet.joints.Count; j++) { ActiveSet.joints[j].ClearAccumulatedImpulses(); } }
private void SolveIteration(int i) { var constraint = constraints.Elements[permutationMapper.GetMappedIndex(i, constraints.Count)]; constraint.EnterLock(); constraint.SolveIteration(); constraint.ApplyImpulses(); constraint.ExitLock(); }
/// <summary> /// Constructs a new demo. /// </summary> /// <param name="game">Game owning this demo.</param> public PermutationTestDemo(DemosGame game) : base(game) { var permutations = new HashSet <Permutation>(); var mapper = new PermutationMapper(); var representedIndices = new HashSet <int>(); mapper.PermutationIndex = 0; const int setSize = 250; const int iterationCount = 150000; var conflicts = 0; for (int i = 0; i < iterationCount; ++i) { var permutedIndices = new int[setSize]; for (int setIndex = 0; setIndex < setSize; ++setIndex) { permutedIndices[setIndex] = mapper.GetMappedIndex(setIndex, setSize); } for (int index = 0; index < permutedIndices.Length; ++index) { if (!representedIndices.Add(permutedIndices[index])) { throw new Exception("Not a permutation!"); } } representedIndices.Clear(); var permutation = new Permutation(permutedIndices); if (!permutations.Add(permutation)) { ++conflicts; } ++mapper.PermutationIndex; if (i % (iterationCount / 100) == 0) { Console.WriteLine("{0}% complete", ((double)i * 100) / iterationCount); } } Console.WriteLine("Set size: {0}", setSize); Console.WriteLine("Iteration count: {0}", iterationCount); Console.WriteLine("Permutation count: {0}", permutations.Count); Console.WriteLine("Conflict count: {0}", conflicts); }