forked from bepu/bepuphysics2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CenterDistanceConstraint.cs
142 lines (122 loc) · 7.12 KB
/
CenterDistanceConstraint.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
using BepuPhysics.CollisionDetection;
using BepuUtilities;
using BepuUtilities.Memory;
using System;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using static BepuUtilities.GatherScatter;
namespace BepuPhysics.Constraints
{
/// <summary>
/// Constrains the center of two bodies to be separated by a goal distance.
/// </summary>
public struct CenterDistanceConstraint : ITwoBodyConstraintDescription<CenterDistanceConstraint>
{
/// <summary>
/// Target distance between the body centers.
/// </summary>
public float TargetDistance;
/// <summary>
/// Spring frequency and damping parameters.
/// </summary>
public SpringSettings SpringSettings;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CenterDistanceConstraint(float targetDistance, in SpringSettings springSettings)
{
TargetDistance = targetDistance;
SpringSettings = springSettings;
}
public int ConstraintTypeId
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return CenterDistanceTypeProcessor.BatchTypeId;
}
}
public Type TypeProcessorType => typeof(CenterDistanceTypeProcessor);
public void ApplyDescription(ref TypeBatch batch, int bundleIndex, int innerIndex)
{
Debug.Assert(TargetDistance >= 0, "CenterDistanceConstraint.TargetDistance must be nonnegative.");
ConstraintChecker.AssertValid(SpringSettings, nameof(CenterDistanceConstraint));
Debug.Assert(ConstraintTypeId == batch.TypeId, "The type batch passed to the description must match the description's expected type.");
ref var target = ref GetOffsetInstance(ref Buffer<CenterDistancePrestepData>.Get(ref batch.PrestepData, bundleIndex), innerIndex);
GatherScatter.GetFirst(ref target.TargetDistance) = TargetDistance;
SpringSettingsWide.WriteFirst(SpringSettings, ref target.SpringSettings);
}
public void BuildDescription(ref TypeBatch batch, int bundleIndex, int innerIndex, out CenterDistanceConstraint description)
{
Debug.Assert(ConstraintTypeId == batch.TypeId, "The type batch passed to the description must match the description's expected type.");
ref var source = ref GetOffsetInstance(ref Buffer<CenterDistancePrestepData>.Get(ref batch.PrestepData, bundleIndex), innerIndex);
description.TargetDistance = GatherScatter.GetFirst(ref source.TargetDistance);
SpringSettingsWide.ReadFirst(source.SpringSettings, out description.SpringSettings);
}
}
public struct CenterDistancePrestepData
{
public Vector<float> TargetDistance;
public SpringSettingsWide SpringSettings;
}
public struct CenterDistanceProjection
{
public Vector3Wide JacobianA;
public Vector<float> BiasVelocity;
public Vector<float> SoftnessImpulseScale;
public Vector<float> EffectiveMass;
public Vector<float> InverseMassA;
public Vector<float> InverseMassB;
}
public struct CenterDistanceConstraintFunctions : IConstraintFunctions<CenterDistancePrestepData, CenterDistanceProjection, Vector<float>>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Prestep(Bodies bodies, ref TwoBodyReferences bodyReferences, int count, float dt, float inverseDt, ref BodyInertias inertiaA, ref BodyInertias inertiaB,
ref CenterDistancePrestepData prestep, out CenterDistanceProjection projection)
{
bodies.GatherOffsets(ref bodyReferences, count, out var ab);
Vector3Wide.Length(ab, out var distance);
Vector3Wide.Scale(ab, Vector<float>.One / distance, out projection.JacobianA);
var useFallback = Vector.LessThan(distance, new Vector<float>(1e-10f));
projection.JacobianA.X = Vector.ConditionalSelect(useFallback, Vector<float>.One, projection.JacobianA.X);
projection.JacobianA.Y = Vector.ConditionalSelect(useFallback, Vector<float>.Zero, projection.JacobianA.Y);
projection.JacobianA.Z = Vector.ConditionalSelect(useFallback, Vector<float>.Zero, projection.JacobianA.Z);
SpringSettingsWide.ComputeSpringiness(prestep.SpringSettings, dt, out var positionErrorToVelocity, out var effectiveMassCFMScale, out projection.SoftnessImpulseScale);
//Jacobian is just the unit length direction, so the effective mass is simple:
projection.EffectiveMass = effectiveMassCFMScale / (inertiaA.InverseMass + inertiaB.InverseMass);
projection.InverseMassA = inertiaA.InverseMass;
projection.InverseMassB = inertiaB.InverseMass;
//Compute the position error and bias velocities. Note the order of subtraction when calculating error- we want the bias velocity to counteract the separation.
projection.BiasVelocity = (distance - prestep.TargetDistance) * positionErrorToVelocity;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void ApplyImpulse(ref BodyVelocities a, ref BodyVelocities b, ref CenterDistanceProjection projection, ref Vector<float> impulse)
{
Vector3Wide.Scale(projection.JacobianA, impulse * projection.InverseMassA, out var changeA);
Vector3Wide.Scale(projection.JacobianA, impulse * projection.InverseMassB, out var negatedChangeB);
Vector3Wide.Add(a.Linear, changeA, out a.Linear);
Vector3Wide.Subtract(b.Linear, negatedChangeB, out b.Linear);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WarmStart(ref BodyVelocities velocityA, ref BodyVelocities velocityB, ref CenterDistanceProjection projection, ref Vector<float> accumulatedImpulse)
{
ApplyImpulse(ref velocityA, ref velocityB, ref projection, ref accumulatedImpulse);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Solve(ref BodyVelocities velocityA, ref BodyVelocities velocityB, ref CenterDistanceProjection projection, ref Vector<float> accumulatedImpulse)
{
//csi = projection.BiasImpulse - accumulatedImpulse * projection.SoftnessImpulseScale - (csiaLinear + csiaAngular + csibLinear + csibAngular);
Vector3Wide.Dot(velocityA.Linear, projection.JacobianA, out var linearCSVA);
Vector3Wide.Dot(velocityB.Linear, projection.JacobianA, out var negatedCSVB);
var csi = (projection.BiasVelocity - (linearCSVA - negatedCSVB)) * projection.EffectiveMass - accumulatedImpulse * projection.SoftnessImpulseScale;
accumulatedImpulse += csi;
ApplyImpulse(ref velocityA, ref velocityB, ref projection, ref csi);
}
}
/// <summary>
/// Handles the solve iterations of a bunch of distance servos.
/// </summary>
public class CenterDistanceTypeProcessor : TwoBodyTypeProcessor<CenterDistancePrestepData, CenterDistanceProjection, Vector<float>, CenterDistanceConstraintFunctions>
{
public const int BatchTypeId = 35;
}
}