forked from bepu/bepuphysics2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDemoCallbacks.cs
168 lines (150 loc) · 9.29 KB
/
DemoCallbacks.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
158
159
160
161
162
163
164
165
166
167
168
using BepuUtilities;
using BepuPhysics;
using BepuPhysics.Collidables;
using BepuPhysics.CollisionDetection;
using BepuPhysics.Constraints;
using System;
using System.Runtime.CompilerServices;
using System.Numerics;
namespace Demos;
public struct DemoPoseIntegratorCallbacks : IPoseIntegratorCallbacks
{
/// <summary>
/// Gravity to apply to dynamic bodies in the simulation.
/// </summary>
public Vector3 Gravity;
/// <summary>
/// Fraction of dynamic body linear velocity to remove per unit of time. Values range from 0 to 1. 0 is fully undamped, while values very close to 1 will remove most velocity.
/// </summary>
public float LinearDamping;
/// <summary>
/// Fraction of dynamic body angular velocity to remove per unit of time. Values range from 0 to 1. 0 is fully undamped, while values very close to 1 will remove most velocity.
/// </summary>
public float AngularDamping;
/// <summary>
/// Gets how the pose integrator should handle angular velocity integration.
/// </summary>
public readonly AngularIntegrationMode AngularIntegrationMode => AngularIntegrationMode.Nonconserving;
/// <summary>
/// Gets whether the integrator should use substepping for unconstrained bodies when using a substepping solver.
/// If true, unconstrained bodies will be integrated with the same number of substeps as the constrained bodies in the solver.
/// If false, unconstrained bodies use a single step of length equal to the dt provided to Simulation.Timestep.
/// </summary>
public readonly bool AllowSubstepsForUnconstrainedBodies => false;
/// <summary>
/// Gets whether the velocity integration callback should be called for kinematic bodies.
/// If true, IntegrateVelocity will be called for bundles including kinematic bodies.
/// If false, kinematic bodies will just continue using whatever velocity they have set.
/// Most use cases should set this to false.
/// </summary>
public readonly bool IntegrateVelocityForKinematics => false;
public void Initialize(Simulation simulation)
{
//In this demo, we don't need to initialize anything.
//If you had a simulation with per body gravity stored in a CollidableProperty<T> or something similar, having the simulation provided in a callback can be helpful.
}
/// <summary>
/// Creates a new set of simple callbacks for the demos.
/// </summary>
/// <param name="gravity">Gravity to apply to dynamic bodies in the simulation.</param>
/// <param name="linearDamping">Fraction of dynamic body linear velocity to remove per unit of time. Values range from 0 to 1. 0 is fully undamped, while values very close to 1 will remove most velocity.</param>
/// <param name="angularDamping">Fraction of dynamic body angular velocity to remove per unit of time. Values range from 0 to 1. 0 is fully undamped, while values very close to 1 will remove most velocity.</param>
public DemoPoseIntegratorCallbacks(Vector3 gravity, float linearDamping = .03f, float angularDamping = .03f) : this()
{
Gravity = gravity;
LinearDamping = linearDamping;
AngularDamping = angularDamping;
}
Vector3Wide gravityWideDt;
Vector<float> linearDampingDt;
Vector<float> angularDampingDt;
/// <summary>
/// Callback invoked ahead of dispatches that may call into <see cref="IntegrateVelocity"/>.
/// It may be called more than once with different values over a frame. For example, when performing bounding box prediction, velocity is integrated with a full frame time step duration.
/// During substepped solves, integration is split into substepCount steps, each with fullFrameDuration / substepCount duration.
/// The final integration pass for unconstrained bodies may be either fullFrameDuration or fullFrameDuration / substepCount, depending on the value of AllowSubstepsForUnconstrainedBodies.
/// </summary>
/// <param name="dt">Current integration time step duration.</param>
/// <remarks>This is typically used for precomputing anything expensive that will be used across velocity integration.</remarks>
public void PrepareForIntegration(float dt)
{
//No reason to recalculate gravity * dt for every body; just cache it ahead of time.
//Since these callbacks don't use per-body damping values, we can precalculate everything.
linearDampingDt = new Vector<float>(MathF.Pow(MathHelper.Clamp(1 - LinearDamping, 0, 1), dt));
angularDampingDt = new Vector<float>(MathF.Pow(MathHelper.Clamp(1 - AngularDamping, 0, 1), dt));
gravityWideDt = Vector3Wide.Broadcast(Gravity * dt);
}
/// <summary>
/// Callback for a bundle of bodies being integrated.
/// </summary>
/// <param name="bodyIndices">Indices of the bodies being integrated in this bundle.</param>
/// <param name="position">Current body positions.</param>
/// <param name="orientation">Current body orientations.</param>
/// <param name="localInertia">Body's current local inertia.</param>
/// <param name="integrationMask">Mask indicating which lanes are active in the bundle. Active lanes will contain 0xFFFFFFFF, inactive lanes will contain 0.</param>
/// <param name="workerIndex">Index of the worker thread processing this bundle.</param>
/// <param name="dt">Durations to integrate the velocity over. Can vary over lanes.</param>
/// <param name="velocity">Velocity of bodies in the bundle. Any changes to lanes which are not active by the integrationMask will be discarded.</param>
public void IntegrateVelocity(Vector<int> bodyIndices, Vector3Wide position, QuaternionWide orientation, BodyInertiaWide localInertia, Vector<int> integrationMask, int workerIndex, Vector<float> dt, ref BodyVelocityWide velocity)
{
//This is a handy spot to implement things like position dependent gravity or per-body damping.
//This implementation uses a single damping value for all bodies that allows it to be precomputed.
//We don't have to check for kinematics; IntegrateVelocityForKinematics returns false, so we'll never see them in this callback.
//Note that these are SIMD operations and "Wide" types. There are Vector<float>.Count lanes of execution being evaluated simultaneously.
//The types are laid out in array-of-structures-of-arrays (AOSOA) format. That's because this function is frequently called from vectorized contexts within the solver.
//Transforming to "array of structures" (AOS) format for the callback and then back to AOSOA would involve a lot of overhead, so instead the callback works on the AOSOA representation directly.
velocity.Linear = (velocity.Linear + gravityWideDt) * linearDampingDt;
velocity.Angular = velocity.Angular * angularDampingDt;
}
}
public struct DemoNarrowPhaseCallbacks : INarrowPhaseCallbacks
{
public SpringSettings ContactSpringiness;
public float MaximumRecoveryVelocity;
public float FrictionCoefficient;
public DemoNarrowPhaseCallbacks(SpringSettings contactSpringiness, float maximumRecoveryVelocity = 2f, float frictionCoefficient = 1f)
{
ContactSpringiness = contactSpringiness;
MaximumRecoveryVelocity = maximumRecoveryVelocity;
FrictionCoefficient = frictionCoefficient;
}
public void Initialize(Simulation simulation)
{
//Use a default if the springiness value wasn't initialized... at least until struct field initializers are supported outside of previews.
if (ContactSpringiness.AngularFrequency == 0 && ContactSpringiness.TwiceDampingRatio == 0)
{
ContactSpringiness = new(30, 1);
MaximumRecoveryVelocity = 2f;
FrictionCoefficient = 1f;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool AllowContactGeneration(int workerIndex, CollidableReference a, CollidableReference b, ref float speculativeMargin)
{
//While the engine won't even try creating pairs between statics at all, it will ask about kinematic-kinematic pairs.
//Those pairs cannot emit constraints since both involved bodies have infinite inertia. Since most of the demos don't need
//to collect information about kinematic-kinematic pairs, we'll require that at least one of the bodies needs to be dynamic.
return a.Mobility == CollidableMobility.Dynamic || b.Mobility == CollidableMobility.Dynamic;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool AllowContactGeneration(int workerIndex, CollidablePair pair, int childIndexA, int childIndexB)
{
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool ConfigureContactManifold<TManifold>(int workerIndex, CollidablePair pair, ref TManifold manifold, out PairMaterialProperties pairMaterial) where TManifold : unmanaged, IContactManifold<TManifold>
{
pairMaterial.FrictionCoefficient = FrictionCoefficient;
pairMaterial.MaximumRecoveryVelocity = MaximumRecoveryVelocity;
pairMaterial.SpringSettings = ContactSpringiness;
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool ConfigureContactManifold(int workerIndex, CollidablePair pair, int childIndexA, int childIndexB, ref ConvexContactManifold manifold)
{
return true;
}
public void Dispose()
{
}
}