(61d00a474) v0.9.7.1
This commit is contained in:
@@ -1,3 +1,10 @@
|
||||
// Copyright (c) 2017 Kastellanos Nikolaos
|
||||
|
||||
/* Original source Farseer Physics Engine:
|
||||
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
|
||||
* Microsoft Permissive License (Ms-PL) v1.1
|
||||
*/
|
||||
|
||||
/*
|
||||
* Farseer Physics Engine:
|
||||
* Copyright (c) 2012 Ian Qvist
|
||||
@@ -25,7 +32,12 @@ using System.Diagnostics;
|
||||
using FarseerPhysics.Collision;
|
||||
using FarseerPhysics.Collision.Shapes;
|
||||
using FarseerPhysics.Common;
|
||||
using FarseerPhysics.Common.Maths;
|
||||
using Microsoft.Xna.Framework;
|
||||
#if NET40 || NET45 || PORTABLE40 || PORTABLE45 || W10 || W8_1 || WP8_1
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
#endif
|
||||
|
||||
namespace FarseerPhysics.Dynamics.Contacts
|
||||
{
|
||||
@@ -82,21 +94,24 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
|
||||
public class ContactSolver
|
||||
{
|
||||
public TimeStep _step;
|
||||
public Position[] _positions;
|
||||
public Velocity[] _velocities;
|
||||
public ContactPositionConstraint[] _positionConstraints;
|
||||
public ContactVelocityConstraint[] _velocityConstraints;
|
||||
public Contact[] _contacts;
|
||||
public int _count;
|
||||
int _velocityConstraintsMultithreadThreshold;
|
||||
int _positionConstraintsMultithreadThreshold;
|
||||
|
||||
public void Reset(TimeStep step, int count, Contact[] contacts, Position[] positions, Velocity[] velocities, bool warmstarting = Settings.EnableWarmstarting)
|
||||
public void Reset(ref TimeStep step, int count, Contact[] contacts, Position[] positions, Velocity[] velocities,
|
||||
int velocityConstraintsMultithreadThreshold, int positionConstraintsMultithreadThreshold)
|
||||
{
|
||||
_step = step;
|
||||
_count = count;
|
||||
_positions = positions;
|
||||
_velocities = velocities;
|
||||
_contacts = contacts;
|
||||
_velocityConstraintsMultithreadThreshold = velocityConstraintsMultithreadThreshold;
|
||||
_positionConstraintsMultithreadThreshold = positionConstraintsMultithreadThreshold;
|
||||
|
||||
// grow the array
|
||||
if (_velocityConstraints == null || _velocityConstraints.Length < count)
|
||||
@@ -169,10 +184,10 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
ManifoldPoint cp = manifold.Points[j];
|
||||
VelocityConstraintPoint vcp = vc.points[j];
|
||||
|
||||
if (Settings.EnableWarmstarting)
|
||||
if (step.warmStarting)
|
||||
{
|
||||
vcp.normalImpulse = _step.dtRatio * cp.NormalImpulse;
|
||||
vcp.tangentImpulse = _step.dtRatio * cp.TangentImpulse;
|
||||
vcp.normalImpulse = step.dtRatio * cp.NormalImpulse;
|
||||
vcp.tangentImpulse = step.dtRatio * cp.TangentImpulse;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -224,18 +239,17 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
|
||||
Debug.Assert(manifold.PointCount > 0);
|
||||
|
||||
Transform xfA = new Transform();
|
||||
Transform xfB = new Transform();
|
||||
xfA.q.Set(aA);
|
||||
xfB.q.Set(aB);
|
||||
xfA.p = cA - MathUtils.Mul(xfA.q, localCenterA);
|
||||
xfB.p = cB - MathUtils.Mul(xfB.q, localCenterB);
|
||||
Transform xfA = new Transform(Vector2.Zero, aA);
|
||||
Transform xfB = new Transform(Vector2.Zero, aB);
|
||||
xfA.p = cA - Complex.Multiply(ref localCenterA, ref xfA.q);
|
||||
xfB.p = cB - Complex.Multiply(ref localCenterB, ref xfB.q);
|
||||
|
||||
Vector2 normal;
|
||||
FixedArray2<Vector2> points;
|
||||
WorldManifold.Initialize(ref manifold, ref xfA, radiusA, ref xfB, radiusB, out normal, out points);
|
||||
|
||||
vc.normal = normal;
|
||||
Vector2 tangent = MathUtils.Rot270(ref vc.normal);
|
||||
|
||||
int pointCount = vc.pointCount;
|
||||
for (int j = 0; j < pointCount; ++j)
|
||||
@@ -245,17 +259,16 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
vcp.rA = points[j] - cA;
|
||||
vcp.rB = points[j] - cB;
|
||||
|
||||
float rnA = MathUtils.Cross(vcp.rA, vc.normal);
|
||||
float rnB = MathUtils.Cross(vcp.rB, vc.normal);
|
||||
float rnA = MathUtils.Cross(ref vcp.rA, ref vc.normal);
|
||||
float rnB = MathUtils.Cross(ref vcp.rB, ref vc.normal);
|
||||
|
||||
float kNormal = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
|
||||
|
||||
vcp.normalMass = kNormal > 0.0f ? 1.0f / kNormal : 0.0f;
|
||||
|
||||
Vector2 tangent = MathUtils.Cross(vc.normal, 1.0f);
|
||||
|
||||
float rtA = MathUtils.Cross(vcp.rA, tangent);
|
||||
float rtB = MathUtils.Cross(vcp.rB, tangent);
|
||||
float rtA = MathUtils.Cross(ref vcp.rA, ref tangent);
|
||||
float rtB = MathUtils.Cross(ref vcp.rB, ref tangent);
|
||||
|
||||
float kTangent = mA + mB + iA * rtA * rtA + iB * rtB * rtB;
|
||||
|
||||
@@ -263,7 +276,7 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
|
||||
// Setup a velocity bias for restitution.
|
||||
vcp.velocityBias = 0.0f;
|
||||
float vRel = Vector2.Dot(vc.normal, vB + MathUtils.Cross(wB, vcp.rB) - vA - MathUtils.Cross(wA, vcp.rA));
|
||||
float vRel = Vector2.Dot(vc.normal, vB + MathUtils.Cross(wB, ref vcp.rB) - vA - MathUtils.Cross(wA, ref vcp.rA));
|
||||
if (vRel < -Settings.VelocityThreshold)
|
||||
{
|
||||
vcp.velocityBias = -vc.restitution * vRel;
|
||||
@@ -276,10 +289,10 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
VelocityConstraintPoint vcp1 = vc.points[0];
|
||||
VelocityConstraintPoint vcp2 = vc.points[1];
|
||||
|
||||
float rn1A = MathUtils.Cross(vcp1.rA, vc.normal);
|
||||
float rn1B = MathUtils.Cross(vcp1.rB, vc.normal);
|
||||
float rn2A = MathUtils.Cross(vcp2.rA, vc.normal);
|
||||
float rn2B = MathUtils.Cross(vcp2.rB, vc.normal);
|
||||
float rn1A = MathUtils.Cross(ref vcp1.rA, ref vc.normal);
|
||||
float rn1B = MathUtils.Cross(ref vcp1.rB, ref vc.normal);
|
||||
float rn2A = MathUtils.Cross(ref vcp2.rA, ref vc.normal);
|
||||
float rn2B = MathUtils.Cross(ref vcp2.rB, ref vc.normal);
|
||||
|
||||
float k11 = mA + mB + iA * rn1A * rn1A + iB * rn1B * rn1B;
|
||||
float k22 = mA + mB + iA * rn2A * rn2A + iB * rn2B * rn2B;
|
||||
@@ -325,15 +338,15 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
float wB = _velocities[indexB].w;
|
||||
|
||||
Vector2 normal = vc.normal;
|
||||
Vector2 tangent = MathUtils.Cross(normal, 1.0f);
|
||||
Vector2 tangent = MathUtils.Rot270(ref normal);
|
||||
|
||||
for (int j = 0; j < pointCount; ++j)
|
||||
{
|
||||
VelocityConstraintPoint vcp = vc.points[j];
|
||||
Vector2 P = vcp.normalImpulse * normal + vcp.tangentImpulse * tangent;
|
||||
wA -= iA * MathUtils.Cross(vcp.rA, P);
|
||||
wA -= iA * MathUtils.Cross(ref vcp.rA, ref P);
|
||||
vA -= mA * P;
|
||||
wB += iB * MathUtils.Cross(vcp.rB, P);
|
||||
wB += iB * MathUtils.Cross(ref vcp.rB, ref P);
|
||||
vB += mB * P;
|
||||
}
|
||||
|
||||
@@ -346,10 +359,115 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
|
||||
public void SolveVelocityConstraints()
|
||||
{
|
||||
for (int i = 0; i < _count; ++i)
|
||||
if (_count >= _velocityConstraintsMultithreadThreshold && System.Environment.ProcessorCount > 1)
|
||||
{
|
||||
if (_count == 0) return;
|
||||
var batchSize = (int)Math.Ceiling((float)_count / System.Environment.ProcessorCount);
|
||||
var batches = (int)Math.Ceiling((float)_count / batchSize);
|
||||
|
||||
#if NET40 || NET45
|
||||
SolveVelocityConstraintsWaitLock.Reset(batches);
|
||||
for (int i = 0; i < batches; i++)
|
||||
{
|
||||
var start = i * batchSize;
|
||||
var end = Math.Min(start + batchSize, _count);
|
||||
ThreadPool.QueueUserWorkItem( SolveVelocityConstraintsCallback, SolveVelocityConstraintsState.Get(this, start,end));
|
||||
}
|
||||
// We avoid SolveVelocityConstraintsWaitLock.Wait(); because it spins a few milliseconds before going into sleep. Going into sleep(0) directly in a while loop is faster.
|
||||
while (SolveVelocityConstraintsWaitLock.CurrentCount > 0)
|
||||
Thread.Sleep(0);
|
||||
#elif PORTABLE40 || PORTABLE45 || W10 || W8_1 || WP8_1
|
||||
Parallel.For(0, batches, (i) =>
|
||||
{
|
||||
var start = i * batchSize;
|
||||
var end = Math.Min(start + batchSize, _count);
|
||||
SolveVelocityConstraints(start, end);
|
||||
});
|
||||
#else
|
||||
SolveVelocityConstraints(0, _count);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
SolveVelocityConstraints(0, _count);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#if NET40 || NET45
|
||||
CountdownEvent SolveVelocityConstraintsWaitLock = new CountdownEvent(0);
|
||||
static void SolveVelocityConstraintsCallback(object state)
|
||||
{
|
||||
var svcState = (SolveVelocityConstraintsState)state;
|
||||
|
||||
svcState.ContactSolver.SolveVelocityConstraints(svcState.Start, svcState.End);
|
||||
SolveVelocityConstraintsState.Return(svcState);
|
||||
svcState.ContactSolver.SolveVelocityConstraintsWaitLock.Signal();
|
||||
}
|
||||
|
||||
private class SolveVelocityConstraintsState
|
||||
{
|
||||
private static System.Collections.Concurrent.ConcurrentQueue<SolveVelocityConstraintsState> _queue = new System.Collections.Concurrent.ConcurrentQueue<SolveVelocityConstraintsState>(); // pool
|
||||
|
||||
public ContactSolver ContactSolver;
|
||||
public int Start { get; private set; }
|
||||
public int End { get; private set; }
|
||||
|
||||
private SolveVelocityConstraintsState()
|
||||
{
|
||||
}
|
||||
|
||||
internal static object Get(ContactSolver contactSolver, int start, int end)
|
||||
{
|
||||
SolveVelocityConstraintsState result;
|
||||
if (!_queue.TryDequeue(out result))
|
||||
result = new SolveVelocityConstraintsState();
|
||||
|
||||
result.ContactSolver = contactSolver;
|
||||
result.Start = start;
|
||||
result.End = end;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static void Return(object state)
|
||||
{
|
||||
_queue.Enqueue((SolveVelocityConstraintsState)state);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private void SolveVelocityConstraints(int start, int end)
|
||||
{
|
||||
for (int i = start; i < end; ++i)
|
||||
{
|
||||
ContactVelocityConstraint vc = _velocityConstraints[i];
|
||||
|
||||
#if NET40 || NET45 || PORTABLE40 || PORTABLE45 || W10 || W8_1 || WP8_1
|
||||
// find lower order item
|
||||
int orderedIndexA = vc.indexA;
|
||||
int orderedIndexB = vc.indexB;
|
||||
if (orderedIndexB < orderedIndexA)
|
||||
{
|
||||
orderedIndexA = vc.indexB;
|
||||
orderedIndexB = vc.indexA;
|
||||
}
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref _velocities[orderedIndexA].Lock, 1, 0) == 0)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref _velocities[orderedIndexB].Lock, 1, 0) == 0)
|
||||
break;
|
||||
System.Threading.Interlocked.Exchange(ref _velocities[orderedIndexA].Lock, 0);
|
||||
}
|
||||
#if NET40 || NET45
|
||||
Thread.Sleep(0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int indexA = vc.indexA;
|
||||
int indexB = vc.indexB;
|
||||
float mA = vc.invMassA;
|
||||
@@ -364,7 +482,7 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
float wB = _velocities[indexB].w;
|
||||
|
||||
Vector2 normal = vc.normal;
|
||||
Vector2 tangent = MathUtils.Cross(normal, 1.0f);
|
||||
Vector2 tangent = MathUtils.Rot270(ref normal);
|
||||
float friction = vc.friction;
|
||||
|
||||
Debug.Assert(pointCount == 1 || pointCount == 2);
|
||||
@@ -376,7 +494,7 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
VelocityConstraintPoint vcp = vc.points[j];
|
||||
|
||||
// Relative velocity at contact
|
||||
Vector2 dv = vB + MathUtils.Cross(wB, vcp.rB) - vA - MathUtils.Cross(wA, vcp.rA);
|
||||
Vector2 dv = vB + MathUtils.Cross(wB, ref vcp.rB) - vA - MathUtils.Cross(wA, ref vcp.rA);
|
||||
|
||||
// Compute tangent force
|
||||
float vt = Vector2.Dot(dv, tangent) - vc.tangentSpeed;
|
||||
@@ -392,10 +510,10 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
Vector2 P = lambda * tangent;
|
||||
|
||||
vA -= mA * P;
|
||||
wA -= iA * MathUtils.Cross(vcp.rA, P);
|
||||
wA -= iA * MathUtils.Cross(ref vcp.rA, ref P);
|
||||
|
||||
vB += mB * P;
|
||||
wB += iB * MathUtils.Cross(vcp.rB, P);
|
||||
wB += iB * MathUtils.Cross(ref vcp.rB, ref P);
|
||||
}
|
||||
|
||||
// Solve normal constraints
|
||||
@@ -404,7 +522,7 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
VelocityConstraintPoint vcp = vc.points[0];
|
||||
|
||||
// Relative velocity at contact
|
||||
Vector2 dv = vB + MathUtils.Cross(wB, vcp.rB) - vA - MathUtils.Cross(wA, vcp.rA);
|
||||
Vector2 dv = vB + MathUtils.Cross(wB, ref vcp.rB) - vA - MathUtils.Cross(wA, ref vcp.rA);
|
||||
|
||||
// Compute normal impulse
|
||||
float vn = Vector2.Dot(dv, normal);
|
||||
@@ -418,10 +536,10 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
// Apply contact impulse
|
||||
Vector2 P = lambda * normal;
|
||||
vA -= mA * P;
|
||||
wA -= iA * MathUtils.Cross(vcp.rA, P);
|
||||
wA -= iA * MathUtils.Cross(ref vcp.rA, ref P);
|
||||
|
||||
vB += mB * P;
|
||||
wB += iB * MathUtils.Cross(vcp.rB, P);
|
||||
wB += iB * MathUtils.Cross(ref vcp.rB, ref P);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -465,8 +583,8 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
Debug.Assert(a.X >= 0.0f && a.Y >= 0.0f);
|
||||
|
||||
// Relative velocity at contact
|
||||
Vector2 dv1 = vB + MathUtils.Cross(wB, cp1.rB) - vA - MathUtils.Cross(wA, cp1.rA);
|
||||
Vector2 dv2 = vB + MathUtils.Cross(wB, cp2.rB) - vA - MathUtils.Cross(wA, cp2.rA);
|
||||
Vector2 dv1 = vB + MathUtils.Cross(wB, ref cp1.rB) - vA - MathUtils.Cross(wA, ref cp1.rA);
|
||||
Vector2 dv2 = vB + MathUtils.Cross(wB, ref cp2.rB) - vA - MathUtils.Cross(wA, ref cp2.rA);
|
||||
|
||||
// Compute normal velocity
|
||||
float vn1 = Vector2.Dot(dv1, normal);
|
||||
@@ -477,7 +595,7 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
b.Y = vn2 - cp2.velocityBias;
|
||||
|
||||
// Compute b'
|
||||
b -= MathUtils.Mul(ref vc.K, a);
|
||||
b -= MathUtils.Mul(ref vc.K, ref a);
|
||||
|
||||
const float k_errorTol = 1e-3f;
|
||||
//B2_NOT_USED(k_errorTol);
|
||||
@@ -493,7 +611,7 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
//
|
||||
// x = - inv(A) * b'
|
||||
//
|
||||
Vector2 x = -MathUtils.Mul(ref vc.normalMass, b);
|
||||
Vector2 x = -MathUtils.Mul(ref vc.normalMass, ref b);
|
||||
|
||||
if (x.X >= 0.0f && x.Y >= 0.0f)
|
||||
{
|
||||
@@ -504,10 +622,10 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
Vector2 P1 = d.X * normal;
|
||||
Vector2 P2 = d.Y * normal;
|
||||
vA -= mA * (P1 + P2);
|
||||
wA -= iA * (MathUtils.Cross(cp1.rA, P1) + MathUtils.Cross(cp2.rA, P2));
|
||||
wA -= iA * (MathUtils.Cross(ref cp1.rA, ref P1) + MathUtils.Cross(ref cp2.rA, ref P2));
|
||||
|
||||
vB += mB * (P1 + P2);
|
||||
wB += iB * (MathUtils.Cross(cp1.rB, P1) + MathUtils.Cross(cp2.rB, P2));
|
||||
wB += iB * (MathUtils.Cross(ref cp1.rB, ref P1) + MathUtils.Cross(ref cp2.rB, ref P2));
|
||||
|
||||
// Accumulate
|
||||
cp1.normalImpulse = x.X;
|
||||
@@ -548,10 +666,10 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
Vector2 P1 = d.X * normal;
|
||||
Vector2 P2 = d.Y * normal;
|
||||
vA -= mA * (P1 + P2);
|
||||
wA -= iA * (MathUtils.Cross(cp1.rA, P1) + MathUtils.Cross(cp2.rA, P2));
|
||||
wA -= iA * (MathUtils.Cross(ref cp1.rA, ref P1) + MathUtils.Cross(ref cp2.rA, ref P2));
|
||||
|
||||
vB += mB * (P1 + P2);
|
||||
wB += iB * (MathUtils.Cross(cp1.rB, P1) + MathUtils.Cross(cp2.rB, P2));
|
||||
wB += iB * (MathUtils.Cross(ref cp1.rB, ref P1) + MathUtils.Cross(ref cp2.rB, ref P2));
|
||||
|
||||
// Accumulate
|
||||
cp1.normalImpulse = x.X;
|
||||
@@ -590,10 +708,10 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
Vector2 P1 = d.X * normal;
|
||||
Vector2 P2 = d.Y * normal;
|
||||
vA -= mA * (P1 + P2);
|
||||
wA -= iA * (MathUtils.Cross(cp1.rA, P1) + MathUtils.Cross(cp2.rA, P2));
|
||||
wA -= iA * (MathUtils.Cross(ref cp1.rA, ref P1) + MathUtils.Cross(ref cp2.rA, ref P2));
|
||||
|
||||
vB += mB * (P1 + P2);
|
||||
wB += iB * (MathUtils.Cross(cp1.rB, P1) + MathUtils.Cross(cp2.rB, P2));
|
||||
wB += iB * (MathUtils.Cross(ref cp1.rB, ref P1) + MathUtils.Cross(ref cp2.rB, ref P2));
|
||||
|
||||
// Accumulate
|
||||
cp1.normalImpulse = x.X;
|
||||
@@ -630,10 +748,10 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
Vector2 P1 = d.X * normal;
|
||||
Vector2 P2 = d.Y * normal;
|
||||
vA -= mA * (P1 + P2);
|
||||
wA -= iA * (MathUtils.Cross(cp1.rA, P1) + MathUtils.Cross(cp2.rA, P2));
|
||||
wA -= iA * (MathUtils.Cross(ref cp1.rA, ref P1) + MathUtils.Cross(ref cp2.rA, ref P2));
|
||||
|
||||
vB += mB * (P1 + P2);
|
||||
wB += iB * (MathUtils.Cross(cp1.rB, P1) + MathUtils.Cross(cp2.rB, P2));
|
||||
wB += iB * (MathUtils.Cross(ref cp1.rB, ref P1) + MathUtils.Cross(ref cp2.rB, ref P2));
|
||||
|
||||
// Accumulate
|
||||
cp1.normalImpulse = x.X;
|
||||
@@ -651,6 +769,11 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
_velocities[indexA].w = wA;
|
||||
_velocities[indexB].v = vB;
|
||||
_velocities[indexB].w = wB;
|
||||
|
||||
#if NET40 || NET45 || PORTABLE40 || PORTABLE45 || W10 || W8_1 || WP8_1
|
||||
System.Threading.Interlocked.Exchange(ref _velocities[orderedIndexB].Lock, 0);
|
||||
System.Threading.Interlocked.Exchange(ref _velocities[orderedIndexA].Lock, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,12 +797,71 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
}
|
||||
|
||||
public bool SolvePositionConstraints()
|
||||
{
|
||||
bool contactsOkay = false;
|
||||
|
||||
if (_count >= _positionConstraintsMultithreadThreshold && System.Environment.ProcessorCount > 1)
|
||||
{
|
||||
if (_count == 0) return true;
|
||||
var batchSize = (int)Math.Ceiling((float)_count / System.Environment.ProcessorCount);
|
||||
var batches = (int)Math.Ceiling((float)_count / batchSize);
|
||||
|
||||
#if NET40 || NET45 || PORTABLE40 || PORTABLE45 || W10 || W8_1 || WP8_1
|
||||
Parallel.For(0, batches, (i) =>
|
||||
{
|
||||
var start = i * batchSize;
|
||||
var end = Math.Min(start + batchSize, _count);
|
||||
var res = SolvePositionConstraints(start, end);
|
||||
lock (this)
|
||||
{
|
||||
contactsOkay = contactsOkay || res;
|
||||
}
|
||||
});
|
||||
#else
|
||||
contactsOkay = SolvePositionConstraints(0, _count);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
contactsOkay = SolvePositionConstraints(0, _count);
|
||||
}
|
||||
|
||||
return contactsOkay;
|
||||
}
|
||||
|
||||
private bool SolvePositionConstraints(int start, int end)
|
||||
{
|
||||
float minSeparation = 0.0f;
|
||||
|
||||
for (int i = 0; i < _count; ++i)
|
||||
for (int i = start; i < end; ++i)
|
||||
{
|
||||
ContactPositionConstraint pc = _positionConstraints[i];
|
||||
|
||||
#if NET40 || NET45 || PORTABLE40 || PORTABLE45 || W10 || W8_1 || WP8_1
|
||||
// Find lower order item.
|
||||
int orderedIndexA = pc.indexA;
|
||||
int orderedIndexB = pc.indexB;
|
||||
if (orderedIndexB < orderedIndexA)
|
||||
{
|
||||
orderedIndexA = pc.indexB;
|
||||
orderedIndexB = pc.indexA;
|
||||
}
|
||||
|
||||
// Lock bodies.
|
||||
for (; ; )
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref _positions[orderedIndexA].Lock, 1, 0) == 0)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref _positions[orderedIndexB].Lock, 1, 0) == 0)
|
||||
break;
|
||||
System.Threading.Interlocked.Exchange(ref _positions[orderedIndexA].Lock, 0);
|
||||
}
|
||||
#if NET40 || NET45
|
||||
Thread.Sleep(0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int indexA = pc.indexA;
|
||||
int indexB = pc.indexB;
|
||||
@@ -693,25 +875,22 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
|
||||
Vector2 cA = _positions[indexA].c;
|
||||
float aA = _positions[indexA].a;
|
||||
|
||||
Vector2 cB = _positions[indexB].c;
|
||||
float aB = _positions[indexB].a;
|
||||
|
||||
// Solve normal constraints
|
||||
for (int j = 0; j < pointCount; ++j)
|
||||
{
|
||||
Transform xfA = new Transform();
|
||||
Transform xfB = new Transform();
|
||||
xfA.q.Set(aA);
|
||||
xfB.q.Set(aB);
|
||||
xfA.p = cA - MathUtils.Mul(xfA.q, localCenterA);
|
||||
xfB.p = cB - MathUtils.Mul(xfB.q, localCenterB);
|
||||
Transform xfA = new Transform(Vector2.Zero, aA);
|
||||
Transform xfB = new Transform(Vector2.Zero, aB);
|
||||
xfA.p = cA - Complex.Multiply(ref localCenterA, ref xfA.q);
|
||||
xfB.p = cB - Complex.Multiply(ref localCenterB, ref xfB.q);
|
||||
|
||||
Vector2 normal;
|
||||
Vector2 point;
|
||||
float separation;
|
||||
|
||||
PositionSolverManifold.Initialize(pc, xfA, xfB, j, out normal, out point, out separation);
|
||||
PositionSolverManifold.Initialize(pc, ref xfA, ref xfB, j, out normal, out point, out separation);
|
||||
|
||||
Vector2 rA = point - cA;
|
||||
Vector2 rB = point - cB;
|
||||
@@ -723,8 +902,8 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
float C = MathUtils.Clamp(Settings.Baumgarte * (separation + Settings.LinearSlop), -Settings.MaxLinearCorrection, 0.0f);
|
||||
|
||||
// Compute the effective mass.
|
||||
float rnA = MathUtils.Cross(rA, normal);
|
||||
float rnB = MathUtils.Cross(rB, normal);
|
||||
float rnA = MathUtils.Cross(ref rA, ref normal);
|
||||
float rnB = MathUtils.Cross(ref rB, ref normal);
|
||||
float K = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
|
||||
|
||||
// Compute normal impulse
|
||||
@@ -733,17 +912,22 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
Vector2 P = impulse * normal;
|
||||
|
||||
cA -= mA * P;
|
||||
aA -= iA * MathUtils.Cross(rA, P);
|
||||
aA -= iA * MathUtils.Cross(ref rA, ref P);
|
||||
|
||||
cB += mB * P;
|
||||
aB += iB * MathUtils.Cross(rB, P);
|
||||
aB += iB * MathUtils.Cross(ref rB, ref P);
|
||||
}
|
||||
|
||||
_positions[indexA].c = cA;
|
||||
_positions[indexA].a = aA;
|
||||
|
||||
_positions[indexB].c = cB;
|
||||
_positions[indexB].a = aB;
|
||||
|
||||
#if NET40 || NET45 || PORTABLE40 || PORTABLE45 || W10 || W8_1 || WP8_1
|
||||
// Unlock bodies.
|
||||
System.Threading.Interlocked.Exchange(ref _positions[orderedIndexB].Lock, 0);
|
||||
System.Threading.Interlocked.Exchange(ref _positions[orderedIndexA].Lock, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
// We can't expect minSpeparation >= -b2_linearSlop because we don't
|
||||
@@ -791,18 +975,16 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
// Solve normal constraints
|
||||
for (int j = 0; j < pointCount; ++j)
|
||||
{
|
||||
Transform xfA = new Transform();
|
||||
Transform xfB = new Transform();
|
||||
xfA.q.Set(aA);
|
||||
xfB.q.Set(aB);
|
||||
xfA.p = cA - MathUtils.Mul(xfA.q, localCenterA);
|
||||
xfB.p = cB - MathUtils.Mul(xfB.q, localCenterB);
|
||||
Transform xfA = new Transform(Vector2.Zero, aA);
|
||||
Transform xfB = new Transform(Vector2.Zero, aB);
|
||||
xfA.p = cA - Complex.Multiply(ref localCenterA, ref xfA.q);
|
||||
xfB.p = cB - Complex.Multiply(ref localCenterB, ref xfB.q);
|
||||
|
||||
Vector2 normal;
|
||||
Vector2 point;
|
||||
float separation;
|
||||
|
||||
PositionSolverManifold.Initialize(pc, xfA, xfB, j, out normal, out point, out separation);
|
||||
PositionSolverManifold.Initialize(pc, ref xfA, ref xfB, j, out normal, out point, out separation);
|
||||
|
||||
Vector2 rA = point - cA;
|
||||
Vector2 rB = point - cB;
|
||||
@@ -814,8 +996,8 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
float C = MathUtils.Clamp(Settings.Baumgarte * (separation + Settings.LinearSlop), -Settings.MaxLinearCorrection, 0.0f);
|
||||
|
||||
// Compute the effective mass.
|
||||
float rnA = MathUtils.Cross(rA, normal);
|
||||
float rnB = MathUtils.Cross(rB, normal);
|
||||
float rnA = MathUtils.Cross(ref rA, ref normal);
|
||||
float rnB = MathUtils.Cross(ref rB, ref normal);
|
||||
float K = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
|
||||
|
||||
// Compute normal impulse
|
||||
@@ -824,10 +1006,10 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
Vector2 P = impulse * normal;
|
||||
|
||||
cA -= mA * P;
|
||||
aA -= iA * MathUtils.Cross(rA, P);
|
||||
aA -= iA * MathUtils.Cross(ref rA, ref P);
|
||||
|
||||
cB += mB * P;
|
||||
aB += iB * MathUtils.Cross(rB, P);
|
||||
aB += iB * MathUtils.Cross(ref rB, ref P);
|
||||
}
|
||||
|
||||
_positions[indexA].c = cA;
|
||||
@@ -872,8 +1054,8 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
case ManifoldType.Circles:
|
||||
{
|
||||
normal = new Vector2(1.0f, 0.0f);
|
||||
Vector2 pointA = MathUtils.Mul(ref xfA, manifold.LocalPoint);
|
||||
Vector2 pointB = MathUtils.Mul(ref xfB, manifold.Points[0].LocalPoint);
|
||||
Vector2 pointA = Transform.Multiply(ref manifold.LocalPoint, ref xfA);
|
||||
Vector2 pointB = Transform.Multiply(manifold.Points[0].LocalPoint, ref xfB);
|
||||
if (Vector2.DistanceSquared(pointA, pointB) > Settings.Epsilon * Settings.Epsilon)
|
||||
{
|
||||
normal = pointB - pointA;
|
||||
@@ -888,12 +1070,12 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
|
||||
case ManifoldType.FaceA:
|
||||
{
|
||||
normal = MathUtils.Mul(xfA.q, manifold.LocalNormal);
|
||||
Vector2 planePoint = MathUtils.Mul(ref xfA, manifold.LocalPoint);
|
||||
normal = Complex.Multiply(ref manifold.LocalNormal, ref xfA.q);
|
||||
Vector2 planePoint = Transform.Multiply(ref manifold.LocalPoint, ref xfA);
|
||||
|
||||
for (int i = 0; i < manifold.PointCount; ++i)
|
||||
{
|
||||
Vector2 clipPoint = MathUtils.Mul(ref xfB, manifold.Points[i].LocalPoint);
|
||||
Vector2 clipPoint = Transform.Multiply(manifold.Points[i].LocalPoint, ref xfB);
|
||||
Vector2 cA = clipPoint + (radiusA - Vector2.Dot(clipPoint - planePoint, normal)) * normal;
|
||||
Vector2 cB = clipPoint - radiusB * normal;
|
||||
points[i] = 0.5f * (cA + cB);
|
||||
@@ -903,12 +1085,12 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
|
||||
case ManifoldType.FaceB:
|
||||
{
|
||||
normal = MathUtils.Mul(xfB.q, manifold.LocalNormal);
|
||||
Vector2 planePoint = MathUtils.Mul(ref xfB, manifold.LocalPoint);
|
||||
normal = Complex.Multiply(ref manifold.LocalNormal, ref xfB.q);
|
||||
Vector2 planePoint = Transform.Multiply(ref manifold.LocalPoint, ref xfB);
|
||||
|
||||
for (int i = 0; i < manifold.PointCount; ++i)
|
||||
{
|
||||
Vector2 clipPoint = MathUtils.Mul(ref xfA, manifold.Points[i].LocalPoint);
|
||||
Vector2 clipPoint = Transform.Multiply(manifold.Points[i].LocalPoint, ref xfA);
|
||||
Vector2 cB = clipPoint + (radiusB - Vector2.Dot(clipPoint - planePoint, normal)) * normal;
|
||||
Vector2 cA = clipPoint - radiusA * normal;
|
||||
points[i] = 0.5f * (cA + cB);
|
||||
@@ -924,19 +1106,22 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
|
||||
private static class PositionSolverManifold
|
||||
{
|
||||
public static void Initialize(ContactPositionConstraint pc, Transform xfA, Transform xfB, int index, out Vector2 normal, out Vector2 point, out float separation)
|
||||
public static void Initialize(ContactPositionConstraint pc, ref Transform xfA, ref Transform xfB, int index, out Vector2 normal, out Vector2 point, out float separation)
|
||||
{
|
||||
Debug.Assert(pc.pointCount > 0);
|
||||
|
||||
|
||||
switch (pc.type)
|
||||
{
|
||||
case ManifoldType.Circles:
|
||||
{
|
||||
Vector2 pointA = MathUtils.Mul(ref xfA, pc.localPoint);
|
||||
Vector2 pointB = MathUtils.Mul(ref xfB, pc.localPoints[0]);
|
||||
Vector2 pointA = Transform.Multiply(ref pc.localPoint, ref xfA);
|
||||
Vector2 pointB = Transform.Multiply(pc.localPoints[0], ref xfB);
|
||||
normal = pointB - pointA;
|
||||
normal.Normalize();
|
||||
|
||||
// Handle zero normalization
|
||||
if (normal != Vector2.Zero)
|
||||
normal.Normalize();
|
||||
|
||||
point = 0.5f * (pointA + pointB);
|
||||
separation = Vector2.Dot(pointB - pointA, normal) - pc.radiusA - pc.radiusB;
|
||||
}
|
||||
@@ -944,10 +1129,10 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
|
||||
case ManifoldType.FaceA:
|
||||
{
|
||||
normal = MathUtils.Mul(xfA.q, pc.localNormal);
|
||||
Vector2 planePoint = MathUtils.Mul(ref xfA, pc.localPoint);
|
||||
Complex.Multiply(ref pc.localNormal, ref xfA.q, out normal);
|
||||
Vector2 planePoint = Transform.Multiply(ref pc.localPoint, ref xfA);
|
||||
|
||||
Vector2 clipPoint = MathUtils.Mul(ref xfB, pc.localPoints[index]);
|
||||
Vector2 clipPoint = Transform.Multiply(pc.localPoints[index], ref xfB);
|
||||
separation = Vector2.Dot(clipPoint - planePoint, normal) - pc.radiusA - pc.radiusB;
|
||||
point = clipPoint;
|
||||
}
|
||||
@@ -955,10 +1140,10 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
|
||||
case ManifoldType.FaceB:
|
||||
{
|
||||
normal = MathUtils.Mul(xfB.q, pc.localNormal);
|
||||
Vector2 planePoint = MathUtils.Mul(ref xfB, pc.localPoint);
|
||||
Complex.Multiply(ref pc.localNormal, ref xfB.q, out normal);
|
||||
Vector2 planePoint = Transform.Multiply(ref pc.localPoint, ref xfB);
|
||||
|
||||
Vector2 clipPoint = MathUtils.Mul(ref xfA, pc.localPoints[index]);
|
||||
Vector2 clipPoint = Transform.Multiply(pc.localPoints[index], ref xfA);
|
||||
separation = Vector2.Dot(clipPoint - planePoint, normal) - pc.radiusA - pc.radiusB;
|
||||
point = clipPoint;
|
||||
|
||||
@@ -976,4 +1161,6 @@ namespace FarseerPhysics.Dynamics.Contacts
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user