#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS) using UnityEngine; using Unity.Jobs; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Mathematics; using Unity.Burst; using System.Collections; namespace Obi { public class BurstStretchShearConstraintsBatch : BurstConstraintsBatchImpl, IStretchShearConstraintsBatchImpl { private NativeArray orientationIndices; private NativeArray restLengths; private NativeArray restOrientations; private NativeArray stiffnesses; public BurstStretchShearConstraintsBatch(BurstStretchShearConstraints constraints) { m_Constraints = constraints; m_ConstraintType = Oni.ConstraintType.StretchShear; } public void SetStretchShearConstraints(ObiNativeIntList particleIndices, ObiNativeIntList orientationIndices, ObiNativeFloatList restLengths, ObiNativeQuaternionList restOrientations, ObiNativeVector3List stiffnesses, ObiNativeFloatList lambdas, int count) { this.particleIndices = particleIndices.AsNativeArray(); this.orientationIndices = orientationIndices.AsNativeArray(); this.restLengths = restLengths.AsNativeArray(); this.restOrientations = restOrientations.AsNativeArray(); this.stiffnesses = stiffnesses.AsNativeArray(); this.lambdas = lambdas.AsNativeArray(); m_ConstraintCount = count; } public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps) { var projectConstraints = new StretchShearConstraintsBatchJob() { particleIndices = particleIndices, orientationIndices = orientationIndices, restLengths = restLengths, restOrientations = restOrientations, stiffnesses = stiffnesses, lambdas = lambdas.Reinterpret(), positions = solverImplementation.positions, orientations = solverImplementation.orientations, invMasses = solverImplementation.invMasses, invRotationalMasses = solverImplementation.invRotationalMasses, deltas = solverImplementation.positionDeltas, orientationDeltas = solverImplementation.orientationDeltas, counts = solverImplementation.positionConstraintCounts, orientationCounts = solverImplementation.orientationConstraintCounts, deltaTimeSqr = substepTime * substepTime }; return projectConstraints.Schedule(m_ConstraintCount, 32, inputDeps); } public override JobHandle Apply(JobHandle inputDeps, float substepTime) { var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType); var applyConstraints = new ApplyStretchShearConstraintsBatchJob() { particleIndices = particleIndices, orientationIndices = orientationIndices, positions = solverImplementation.positions, deltas = solverImplementation.positionDeltas, counts = solverImplementation.positionConstraintCounts, orientations = solverImplementation.orientations, orientationDeltas = solverImplementation.orientationDeltas, orientationCounts = solverImplementation.orientationConstraintCounts, sorFactor = parameters.SORFactor }; return applyConstraints.Schedule(m_ConstraintCount, 64, inputDeps); } [BurstCompile] public struct StretchShearConstraintsBatchJob : IJobParallelFor { [ReadOnly] public NativeArray particleIndices; [ReadOnly] public NativeArray orientationIndices; [ReadOnly] public NativeArray restLengths; [ReadOnly] public NativeArray restOrientations; [ReadOnly] public NativeArray stiffnesses; public NativeArray lambdas; [ReadOnly] public NativeArray positions; [ReadOnly] public NativeArray orientations; [ReadOnly] public NativeArray invMasses; [ReadOnly] public NativeArray invRotationalMasses; [NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray deltas; [NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray orientationDeltas; [NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray counts; [NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray orientationCounts; [ReadOnly] public float deltaTimeSqr; public void Execute(int i) { int p1 = particleIndices[i * 2]; int p2 = particleIndices[i * 2 + 1]; int q = orientationIndices[i]; float w1 = invMasses[p1]; float w2 = invMasses[p2]; // calculate time adjusted compliance float3 compliances = stiffnesses[i] / deltaTimeSqr; float3 e = math.rotate(restOrientations[i],new float3(0, 0, 1)); quaternion basis = math.mul(orientations[q],restOrientations[i]); // calculate rod vector in local element space: float3 gamma = math.rotate(math.conjugate(basis), (positions[p2] - positions[p1]).xyz) / (restLengths[i] + BurstMath.epsilon); // subtract third director vector (0,0,1): gamma[2] -= 1; float3 W = new float3((w1 + w2) / (restLengths[i] + BurstMath.epsilon) + invRotationalMasses[q] * 4.0f * restLengths[i] + BurstMath.epsilon); float3 dlambda = (gamma - compliances * lambdas[i]) / (compliances + W); lambdas[i] += dlambda; // convert lambda delta lambda back to world space: dlambda = math.mul(basis, dlambda); deltas[p1] += new float4(dlambda, 0) * w1; deltas[p2] -= new float4(dlambda, 0) * w2; quaternion e_3 = new quaternion(e.x,e.y,e.z,0); quaternion q_e_3_bar = math.mul(orientations[q],math.conjugate(e_3)); // calculate rotation delta: quaternion rotDelta = math.mul(new quaternion(dlambda[0], dlambda[1], dlambda[2], 0.0f),q_e_3_bar); rotDelta.value *= 2.0f * invRotationalMasses[q] * restLengths[i]; orientationDeltas[q] = rotDelta; counts[p1]++; counts[p2]++; orientationCounts[q]++; } } [BurstCompile] public struct ApplyStretchShearConstraintsBatchJob : IJobParallelFor { [ReadOnly] public NativeArray particleIndices; [ReadOnly] public NativeArray orientationIndices; [ReadOnly] public float sorFactor; [NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray positions; [NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray deltas; [NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray counts; [NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray orientations; [NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray orientationDeltas; [NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray orientationCounts; public void Execute(int i) { int p1 = particleIndices[i * 2]; int p2 = particleIndices[i * 2 + 1]; int q1 = orientationIndices[i]; if (counts[p1] > 0) { positions[p1] += deltas[p1] * sorFactor / counts[p1]; deltas[p1] = float4.zero; counts[p1] = 0; } if (counts[p2] > 0) { positions[p2] += deltas[p2] * sorFactor / counts[p2]; deltas[p2] = float4.zero; counts[p2] = 0; } if (orientationCounts[q1] > 0) { quaternion q = orientations[q1]; q.value += orientationDeltas[q1].value * sorFactor / orientationCounts[q1]; orientations[q1] = math.normalize(q); orientationDeltas[q1] = new quaternion(0, 0, 0, 0); orientationCounts[q1] = 0; } } } } } #endif