using UnityEngine; using System.Collections; using System.Collections.Generic; using System; namespace Obi { [Serializable] public class ObiShapeMatchingConstraintsBatch : ObiConstraintsBatch { protected IShapeMatchingConstraintsBatchImpl m_BatchImpl; /// /// index of the first particle in each constraint. /// public ObiNativeIntList firstIndex = new ObiNativeIntList(); /// /// amount of particles in each constraint. /// public ObiNativeIntList numIndices = new ObiNativeIntList(); /// /// whether the constraint is implicit (0) or explicit (>0). /// public ObiNativeIntList explicitGroup = new ObiNativeIntList(); /// /// 5 floats per constraint: stiffness, plastic yield, creep, recovery and max deformation. /// public ObiNativeFloatList materialParameters = new ObiNativeFloatList(); /// /// rest center of mass for each constraint. /// public ObiNativeVector4List restComs = new ObiNativeVector4List(); /// /// current center of mass for each constraint. /// public ObiNativeVector4List coms = new ObiNativeVector4List(); /// /// current best-match orientation for each constraint. /// public ObiNativeQuaternionList orientations = new ObiNativeQuaternionList(); /// /// current best-match linear transform for each constraint. /// public ObiNativeMatrix4x4List linearTransforms = new ObiNativeMatrix4x4List(); /// /// current plastic deformation for each constraint. /// public ObiNativeMatrix4x4List plasticDeformations = new ObiNativeMatrix4x4List(); public override Oni.ConstraintType constraintType { get { return Oni.ConstraintType.ShapeMatching; } } public override IConstraintsBatchImpl implementation { get { return m_BatchImpl; } } public ObiShapeMatchingConstraintsBatch(ObiShapeMatchingConstraintsData constraints = null) : base() { } public void AddConstraint(int[] indices, bool isExplicit) { RegisterConstraint(); firstIndex.Add((int)particleIndices.count); numIndices.Add((int)indices.Length); explicitGroup.Add(isExplicit ? 1 : 0); particleIndices.AddRange(indices); materialParameters.AddRange(new float[] { 1, 1, 1, 1, 1 }); } public override void Clear() { base.Clear(); firstIndex.Clear(); numIndices.Clear(); explicitGroup.Clear(); particleIndices.Clear(); materialParameters.Clear(); } public override void GetParticlesInvolved(int index, List particles) { int first = firstIndex[index]; int num = numIndices[index]; for (int i = first; i < first + num; ++i) particles.Add(particleIndices[i]); } public void RemoveParticleFromConstraint(int constraintIndex, int particleIndex) { int first = firstIndex[constraintIndex]; int num = numIndices[constraintIndex]; int found = 0; for (int i = first + num - 1; i >= first; --i) { if (particleIndices[i] == particleIndex) { found++; particleIndices.RemoveAt(i); } } // update num indices of the current constraint: numIndices[constraintIndex] -= found; // update firstIndex of following constraints: for (int i = constraintIndex + 1; i < constraintCount; ++i) firstIndex[i] -= found; } protected override void SwapConstraints(int sourceIndex, int destIndex) { firstIndex.Swap(sourceIndex, destIndex); numIndices.Swap(sourceIndex, destIndex); explicitGroup.Swap(sourceIndex, destIndex); for (int i = 0; i < 5; ++i) materialParameters.Swap(sourceIndex * 5 + i, destIndex * 5 + i); restComs.Swap(sourceIndex, destIndex); coms.Swap(sourceIndex, destIndex); orientations.Swap(sourceIndex, destIndex); linearTransforms.Swap(sourceIndex, destIndex); plasticDeformations.Swap(sourceIndex, destIndex); } public override void Merge(ObiActor actor, IObiConstraintsBatch other) { var batch = other as ObiShapeMatchingConstraintsBatch; var user = actor as IShapeMatchingConstraintsUser; if (batch != null && user != null) { if (!user.shapeMatchingConstraintsEnabled) return; int initialIndexCount = particleIndices.count; // shape matching constraint particle indices are not reordered when deactivating constraints, // so instead of using batch.activeConstraintCount, batch.constraintCount. We need all of them. int numActiveIndices = 0; for (int i = 0; i < batch.constraintCount; ++i) numActiveIndices += batch.numIndices[i]; particleIndices.ResizeUninitialized(initialIndexCount + numActiveIndices); firstIndex.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount); numIndices.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount); explicitGroup.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount); materialParameters.ResizeUninitialized((m_ActiveConstraintCount + batch.activeConstraintCount) * 5); restComs.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount); coms.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount); orientations.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount); linearTransforms.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount); plasticDeformations.ResizeInitialized(m_ActiveConstraintCount + batch.activeConstraintCount, Matrix4x4.identity); lambdas.ResizeInitialized(m_ActiveConstraintCount + batch.activeConstraintCount); numIndices.CopyFrom(batch.numIndices, 0, m_ActiveConstraintCount, batch.activeConstraintCount); explicitGroup.CopyFrom(batch.explicitGroup, 0, m_ActiveConstraintCount, batch.activeConstraintCount); orientations.CopyReplicate(actor.actorLocalToSolverMatrix.rotation, m_ActiveConstraintCount, batch.activeConstraintCount); for (int i = 0; i < numActiveIndices; ++i) particleIndices[initialIndexCount + i] = actor.solverIndices[batch.particleIndices[i]]; for (int i = 0; i < batch.activeConstraintCount; ++i) { firstIndex[m_ActiveConstraintCount + i] = batch.firstIndex[i] + initialIndexCount; materialParameters[(m_ActiveConstraintCount + i) * 5] = batch.materialParameters[i * 5] * user.deformationResistance; materialParameters[(m_ActiveConstraintCount + i) * 5 + 1] = batch.materialParameters[i * 5 + 1] * user.plasticYield; materialParameters[(m_ActiveConstraintCount + i) * 5 + 2] = batch.materialParameters[i * 5 + 2] * user.plasticCreep; materialParameters[(m_ActiveConstraintCount + i) * 5 + 3] = batch.materialParameters[i * 5 + 3] * user.plasticRecovery; materialParameters[(m_ActiveConstraintCount + i) * 5 + 4] = batch.materialParameters[i * 5 + 4] * user.maxDeformation; } base.Merge(actor, other); } } public override void AddToSolver(ObiSolver solver) { // Create distance constraints batch directly. m_BatchImpl = solver.implementation.CreateConstraintsBatch(constraintType) as IShapeMatchingConstraintsBatchImpl; if (m_BatchImpl != null) { m_BatchImpl.SetShapeMatchingConstraints(particleIndices, firstIndex, numIndices, explicitGroup, materialParameters, restComs, coms, orientations, linearTransforms, plasticDeformations, lambdas, m_ActiveConstraintCount); m_BatchImpl.CalculateRestShapeMatching(); } } public override void RemoveFromSolver(ObiSolver solver) { //Remove batch: solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl); } public void RecalculateRestShapeMatching() { if (m_BatchImpl != null) m_BatchImpl.CalculateRestShapeMatching(); } } }