using UnityEngine; using System; using System.Collections.Generic; namespace Obi { [Serializable] public class ObiPinholeConstraintsBatch : ObiConstraintsBatch { [Serializable] public struct PinholeEdge { public int edgeIndex; public float coordinate; public PinholeEdge(int edgeIndex, float coordinate) { this.edgeIndex = edgeIndex; this.coordinate = coordinate; } public float GetRopeCoordinate(ObiActor actor) { int edgeCount = actor.GetDeformableEdgeCount(); return edgeCount > 0 ? Mathf.Clamp01((edgeIndex + coordinate) / edgeCount) : 0; } } protected IPinholeConstraintsBatchImpl m_BatchImpl; /// /// for each constraint, handle of the pinned collider. /// [HideInInspector] public List pinBodies = new List(); /// /// for each constraint, reference to the actor pinned. /// [HideInInspector] public List pinActors = new List(); /// /// index of the pinned collider in the collider world. /// [HideInInspector] public ObiNativeIntList colliderIndices = new ObiNativeIntList(); /// /// Pinhole position expressed in the attachment's local space. /// [HideInInspector] public ObiNativeVector4List offsets = new ObiNativeVector4List(); /// // Normalized coordinate along current edge. /// [HideInInspector] public ObiNativeFloatList edgeMus = new ObiNativeFloatList(); /// /// Edge range as 2 ints (first edge, last edge) for each constraint. /// [HideInInspector] public ObiNativeIntList edgeRanges = new ObiNativeIntList(); /// /// Min/max cooridnate in each of the first and last edges as 2 floats for each constraint. /// [HideInInspector] public ObiNativeFloatList edgeRangeMus = new ObiNativeFloatList(); /// /// Parameters of pinhole constraints. 5 floats per constraint (compliance, friction, motor speed, motor force and normalized coordinate along edge). /// [HideInInspector] public ObiNativeFloatList parameters = new ObiNativeFloatList(); /// /// Relative velocities between rope and pinhole. /// [HideInInspector] public ObiNativeFloatList relativeVelocities = new ObiNativeFloatList(); public override Oni.ConstraintType constraintType { get { return Oni.ConstraintType.Pinhole; } } public override IConstraintsBatchImpl implementation { get { return m_BatchImpl; } } public ObiPinholeConstraintsBatch(ObiPinholeConstraintsData constraints = null) : base() { } public void AddConstraint(PinholeEdge edge, PinholeEdge firstEdge, PinholeEdge lastEdge, ObiActor actor, ObiColliderBase body, Vector3 offset, float compliance, float friction, float motorSpeed, float motorForce, bool clampAtEnds) { RegisterConstraint(); particleIndices.Add(edge.edgeIndex); edgeMus.Add(edge.coordinate); edgeRanges.Add(firstEdge.edgeIndex); edgeRanges.Add(lastEdge.edgeIndex); edgeRangeMus.Add(firstEdge.coordinate); edgeRangeMus.Add(lastEdge.coordinate); pinBodies.Add(body != null ? body.Handle : new ObiColliderHandle()); pinActors.Add(actor); colliderIndices.Add(body != null ? body.Handle.index : -1); offsets.Add(offset); parameters.Add(compliance); parameters.Add(friction); parameters.Add(motorSpeed); parameters.Add(motorForce); parameters.Add(clampAtEnds ? 1 : 0); relativeVelocities.Add(0); } public override void Clear() { base.Clear(); particleIndices.Clear(); pinBodies.Clear(); colliderIndices.Clear(); offsets.Clear(); edgeMus.Clear(); edgeRanges.Clear(); edgeRangeMus.Clear(); parameters.Clear(); relativeVelocities.Clear(); } public override void GetParticlesInvolved(int index, List particles) { particles.Add(particleIndices[index]); } protected override void SwapConstraints(int sourceIndex, int destIndex) { particleIndices.Swap(sourceIndex, destIndex); pinBodies.Swap(sourceIndex, destIndex); colliderIndices.Swap(sourceIndex, destIndex); offsets.Swap(sourceIndex, destIndex); edgeMus.Swap(sourceIndex, destIndex); edgeRanges.Swap(sourceIndex * 2, destIndex * 2); edgeRanges.Swap(sourceIndex * 2 + 1, destIndex * 2 + 1); edgeRangeMus.Swap(sourceIndex * 2, destIndex * 2); edgeRangeMus.Swap(sourceIndex * 2 + 1, destIndex * 2 + 1); for (int i = 0; i < 5; ++i) parameters.Swap(sourceIndex * 5 + i, destIndex * 5 + i); relativeVelocities.Swap(sourceIndex, destIndex); } public override void Merge(ObiActor actor, IObiConstraintsBatch other) { var batch = other as ObiPinholeConstraintsBatch; if (batch != null) { particleIndices.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount); colliderIndices.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount); offsets.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount); edgeRanges.ResizeUninitialized((m_ActiveConstraintCount + batch.activeConstraintCount) * 2); edgeRangeMus.ResizeUninitialized((m_ActiveConstraintCount + batch.activeConstraintCount) * 2); edgeMus.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount); parameters.ResizeUninitialized((m_ActiveConstraintCount + batch.activeConstraintCount) * 5); relativeVelocities.ResizeInitialized(m_ActiveConstraintCount + batch.activeConstraintCount); lambdas.ResizeInitialized(m_ActiveConstraintCount + batch.activeConstraintCount); edgeMus.CopyFrom(batch.edgeMus, 0, m_ActiveConstraintCount, batch.activeConstraintCount); edgeRangeMus.CopyFrom(batch.edgeRangeMus, 0, m_ActiveConstraintCount * 2, batch.activeConstraintCount * 2); offsets.CopyFrom(batch.offsets, 0, m_ActiveConstraintCount, batch.activeConstraintCount); relativeVelocities.CopyFrom(batch.relativeVelocities, 0, m_ActiveConstraintCount, batch.activeConstraintCount); parameters.CopyFrom(batch.parameters, 0, m_ActiveConstraintCount * 5, batch.activeConstraintCount * 5); for (int i = 0; i < batch.activeConstraintCount; ++i) { int currentEdge = -1, firstEdge = -1, lastEdge = -1; if (batch.pinActors[i] != null) { currentEdge = batch.pinActors[i].deformableEdgesOffset + batch.particleIndices[i]; firstEdge = batch.pinActors[i].deformableEdgesOffset + batch.edgeRanges[i * 2]; lastEdge = batch.pinActors[i].deformableEdgesOffset + batch.edgeRanges[i * 2 + 1]; } edgeRanges[(m_ActiveConstraintCount + i) * 2] = firstEdge; edgeRanges[(m_ActiveConstraintCount + i) * 2 + 1] = lastEdge; particleIndices[m_ActiveConstraintCount + i] = Mathf.Clamp(currentEdge, firstEdge, lastEdge); colliderIndices[m_ActiveConstraintCount + i] = batch.pinBodies[i] != null ? batch.pinBodies[i].index : -1; } base.Merge(actor, other); } } public override void AddToSolver(ObiSolver solver) { if (solver != null && solver.implementation != null) { m_BatchImpl = solver.implementation.CreateConstraintsBatch(constraintType) as IPinholeConstraintsBatchImpl; if (m_BatchImpl != null) m_BatchImpl.SetPinholeConstraints(particleIndices, colliderIndices, offsets, edgeMus, edgeRanges, edgeRangeMus, parameters, relativeVelocities, lambdas, m_ActiveConstraintCount); } } public override void RemoveFromSolver(ObiSolver solver) { base.RemoveFromSolver(solver); edgeRanges.Dispose(); colliderIndices.Dispose(); offsets.Dispose(); parameters.Dispose(); if (solver != null && solver.implementation != null) solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl); } } }