forked from bepu/bepuphysics2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathOneBodyTypeProcessor.cs
157 lines (137 loc) · 9.41 KB
/
OneBodyTypeProcessor.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
using BepuUtilities;
using BepuUtilities.Collections;
using BepuUtilities.Memory;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace BepuPhysics.Constraints
{
/// <summary>
/// Prestep, warm start and solve iteration functions for a constraint type.
/// </summary>
/// <typeparam name="TPrestepData">Type of the prestep data used by the constraint.</typeparam>
/// <typeparam name="TAccumulatedImpulse">Type of the accumulated impulses used by the constraint.</typeparam>
public interface IOneBodyConstraintFunctions<TPrestepData, TAccumulatedImpulse>
{
static abstract void WarmStart(in Vector3Wide positionA, in QuaternionWide orientationA, in BodyInertiaWide inertiaA,
ref TPrestepData prestep, ref TAccumulatedImpulse accumulatedImpulses, ref BodyVelocityWide wsvA);
static abstract void Solve(in Vector3Wide positionA, in QuaternionWide orientationA, in BodyInertiaWide inertiaA, float dt, float inverseDt,
ref TPrestepData prestep, ref TAccumulatedImpulse accumulatedImpulses, ref BodyVelocityWide wsvA);
/// <summary>
/// Gets whether this constraint type requires incremental updates for each substep taken beyond the first.
/// </summary>
static abstract bool RequiresIncrementalSubstepUpdates { get; }
static abstract void IncrementallyUpdateForSubstep(in Vector<float> dt, in BodyVelocityWide velocity, ref TPrestepData prestepData);
}
//Not a big fan of complex generic-filled inheritance hierarchies, but this is the shortest evolutionary step to removing duplicates.
//There are some other options if this inheritance hierarchy gets out of control.
/// <summary>
/// Shared implementation across all one body constraints.
/// </summary>
public abstract class OneBodyTypeProcessor<TPrestepData, TAccumulatedImpulse, TConstraintFunctions,
TWarmStartAccessFilterA, TSolveAccessFilterA>
: TypeProcessor<Vector<int>, TPrestepData, TAccumulatedImpulse>
where TPrestepData : unmanaged where TAccumulatedImpulse : unmanaged
where TConstraintFunctions : unmanaged, IOneBodyConstraintFunctions<TPrestepData, TAccumulatedImpulse>
where TWarmStartAccessFilterA : unmanaged, IBodyAccessFilter
where TSolveAccessFilterA : unmanaged, IBodyAccessFilter
{
protected sealed override int InternalBodiesPerConstraint => 1;
struct OneBodySortKeyGenerator : ISortKeyGenerator<Vector<int>>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetSortKey(int constraintIndex, ref Buffer<Vector<int>> bodyReferences)
{
BundleIndexing.GetBundleIndices(constraintIndex, out var bundleIndex, out var innerIndex);
//We sort based on the body references within the constraint.
//Note that it is impossible for there to be two references to the same body within a constraint batch,
//so there's no need to worry about the case where the comparison is equal.
return GatherScatter.Get(ref bodyReferences[bundleIndex], innerIndex);
}
}
internal sealed override void GenerateSortKeysAndCopyReferences(
ref TypeBatch typeBatch,
int bundleStart, int localBundleStart, int bundleCount,
int constraintStart, int localConstraintStart, int constraintCount,
ref int firstSortKey, ref int firstSourceIndex, ref Buffer<byte> bodyReferencesCache)
{
GenerateSortKeysAndCopyReferences<OneBodySortKeyGenerator>(
ref typeBatch,
bundleStart, localBundleStart, bundleCount,
constraintStart, localConstraintStart, constraintCount,
ref firstSortKey, ref firstSourceIndex, ref bodyReferencesCache);
}
internal sealed override void VerifySortRegion(ref TypeBatch typeBatch, int bundleStartIndex, int constraintCount, ref Buffer<int> sortedKeys, ref Buffer<int> sortedSourceIndices)
{
VerifySortRegion<OneBodySortKeyGenerator>(ref typeBatch, bundleStartIndex, constraintCount, ref sortedKeys, ref sortedSourceIndices);
}
//The following covers the common loop logic for all one body constraints. Each iteration invokes the warm start function type.
//This abstraction should, in theory, have zero overhead if the implementation of the interface is in a struct with aggressive inlining.
//By providing the overrides at this level, the concrete implementation (assuming it inherits from one of the prestep-providing variants)
//only has to specify *type* arguments associated with the interface-implementing struct-delegates. It's going to look very strange, but it's low overhead
//and minimizes per-type duplication.
public override void WarmStart<TIntegratorCallbacks, TBatchIntegrationMode, TAllowPoseIntegration>(
ref TypeBatch typeBatch, ref Buffer<IndexSet> integrationFlags, Bodies bodies, ref TIntegratorCallbacks integratorCallbacks,
float dt, float inverseDt, int startBundle, int exclusiveEndBundle, int workerIndex)
{
var prestepBundles = typeBatch.PrestepData.As<TPrestepData>();
var bodyReferencesBundles = typeBatch.BodyReferences.As<Vector<int>>();
var accumulatedImpulsesBundles = typeBatch.AccumulatedImpulses.As<TAccumulatedImpulse>();
for (int i = startBundle; i < exclusiveEndBundle; ++i)
{
ref var prestep = ref prestepBundles[i];
ref var accumulatedImpulses = ref accumulatedImpulsesBundles[i];
ref var references = ref bodyReferencesBundles[i];
GatherAndIntegrate<TIntegratorCallbacks, TBatchIntegrationMode, TWarmStartAccessFilterA, TAllowPoseIntegration>(bodies, ref integratorCallbacks, ref integrationFlags, 0, dt, workerIndex, i, ref references,
out var positionA, out var orientationA, out var wsvA, out var inertiaA);
//if (typeof(TAllowPoseIntegration) == typeof(AllowPoseIntegration))
// function.UpdateForNewPose(positionA, orientationA, inertiaA, wsvA, new Vector<float>(dt), accumulatedImpulses, ref prestep);
TConstraintFunctions.WarmStart(positionA, orientationA, inertiaA, ref prestep, ref accumulatedImpulses, ref wsvA);
if (typeof(TBatchIntegrationMode) == typeof(BatchShouldNeverIntegrate))
{
bodies.ScatterVelocities<TWarmStartAccessFilterA>(ref wsvA, ref references);
}
else
{
//This batch has some integrators, which means that every bundle is going to gather all velocities.
//(We don't make per-bundle determinations about this to avoid an extra branch and instruction complexity, and the difference is very small.)
bodies.ScatterVelocities<AccessAll>(ref wsvA, ref references);
}
}
}
public override void Solve(ref TypeBatch typeBatch, Bodies bodies, float dt, float inverseDt, int startBundle, int exclusiveEndBundle)
{
var prestepBundles = typeBatch.PrestepData.As<TPrestepData>();
var bodyReferencesBundles = typeBatch.BodyReferences.As<Vector<int>>();
var accumulatedImpulsesBundles = typeBatch.AccumulatedImpulses.As<TAccumulatedImpulse>();
for (int i = startBundle; i < exclusiveEndBundle; ++i)
{
ref var prestep = ref prestepBundles[i];
ref var accumulatedImpulses = ref accumulatedImpulsesBundles[i];
ref var references = ref bodyReferencesBundles[i];
bodies.GatherState<TSolveAccessFilterA>(references, true, out var positionA, out var orientationA, out var wsvA, out var inertiaA);
TConstraintFunctions.Solve(positionA, orientationA, inertiaA, dt, inverseDt, ref prestep, ref accumulatedImpulses, ref wsvA);
bodies.ScatterVelocities<TSolveAccessFilterA>(ref wsvA, ref references);
}
}
public override bool RequiresIncrementalSubstepUpdates => TConstraintFunctions.RequiresIncrementalSubstepUpdates;
public override void IncrementallyUpdateForSubstep(ref TypeBatch typeBatch, Bodies bodies, float dt, float inverseDt, int startBundle, int exclusiveEndBundle)
{
var prestepBundles = typeBatch.PrestepData.As<TPrestepData>();
var bodyReferencesBundles = typeBatch.BodyReferences.As<Vector<int>>();
var dtWide = new Vector<float>(dt);
for (int i = startBundle; i < exclusiveEndBundle; ++i)
{
ref var prestep = ref prestepBundles[i];
ref var references = ref bodyReferencesBundles[i];
bodies.GatherState<AccessOnlyVelocity>(references, true, out _, out _, out var wsvA, out _);
TConstraintFunctions.IncrementallyUpdateForSubstep(dtWide, wsvA, ref prestep);
}
}
}
public abstract class OneBodyContactTypeProcessor<TPrestepData, TAccumulatedImpulse, TConstraintFunctions>
: OneBodyTypeProcessor<TPrestepData, TAccumulatedImpulse, TConstraintFunctions, AccessNoPose, AccessNoPose>
where TPrestepData : unmanaged where TAccumulatedImpulse : unmanaged
where TConstraintFunctions : unmanaged, IOneBodyConstraintFunctions<TPrestepData, TAccumulatedImpulse>
{
}
}