Skip to content

Commit

Permalink
Added UnsafeManifoldViewer for grabbing contact data from contact con…
Browse files Browse the repository at this point in the history
…straints.
  • Loading branch information
RossNordby committed Nov 11, 2018
1 parent a4536ec commit 8ee8de0
Show file tree
Hide file tree
Showing 10 changed files with 672 additions and 71 deletions.
39 changes: 30 additions & 9 deletions BepuPhysics/CollisionDetection/ContactConstraintAccessor.cs
Expand Up @@ -95,11 +95,19 @@ public unsafe void ScatterNewImpulses<TContactImpulses>(ref ConstraintReference
ref CollidablePair pair, ref TContactManifold manifoldPointer, ref TCollisionCache collisionCache, ref PairMaterialProperties material, TCallBodyHandles bodyHandles)
where TCallbacks : struct, INarrowPhaseCallbacks
where TCollisionCache : IPairCacheEntry;

public unsafe abstract void GetUnsafeManifoldViewer(Solver solver, in ConstraintLocation location, out UnsafeManifoldViewer viewer);
}

public interface IContactViewablePrestepData<TPrestepData> where TPrestepData : IContactViewablePrestepData<TPrestepData>
{
void CreateViewer(out UnsafeManifoldViewer viewer);
}


//Note that the vast majority of the 'work' done by these accessor implementations is just type definitions used to call back into some other functions that need that type knowledge.
public abstract class ContactConstraintAccessor<TConstraintDescription, TBodyHandles, TAccumulatedImpulses, TContactImpulses, TConstraintCache> : ContactConstraintAccessor
public abstract class ContactConstraintAccessor<TConstraintDescription, TBodyHandles, TPrestepData, TAccumulatedImpulses, TContactImpulses, TConstraintCache> : ContactConstraintAccessor
where TPrestepData : struct, IContactViewablePrestepData<TPrestepData>
where TConstraintDescription : IConstraintDescription<TConstraintDescription>
where TConstraintCache : IPairCacheEntry
{
Expand Down Expand Up @@ -211,9 +219,19 @@ protected static void CopyContactData(ref NonconvexContactManifold manifold, ref
targetContact.PenetrationDepth = sourceContact.Depth;
}
}

public unsafe override void GetUnsafeManifoldViewer(Solver solver, in ConstraintLocation location, out UnsafeManifoldViewer viewer)
{
ref var batch = ref solver.Sets[location.SetIndex].Batches[location.BatchIndex];
ref var typeBatch = ref batch.TypeBatches[batch.TypeIndexToTypeBatchIndex[location.TypeId]];
BundleIndexing.GetBundleIndices(location.IndexInTypeBatch, out var bundleIndex, out var innerIndex);
ref var prestep = ref GatherScatter.GetOffsetInstance(ref Buffer<TPrestepData>.Get(typeBatch.PrestepData.Memory, bundleIndex), innerIndex);
prestep.CreateViewer(out viewer);
}
}
public class ConvexOneBodyAccessor<TConstraintDescription, TAccumulatedImpulses, TContactImpulses, TConstraintCache> :
ContactConstraintAccessor<TConstraintDescription, int, TAccumulatedImpulses, TContactImpulses, TConstraintCache>
public class ConvexOneBodyAccessor<TConstraintDescription, TPrestepData, TAccumulatedImpulses, TContactImpulses, TConstraintCache> :
ContactConstraintAccessor<TConstraintDescription, int, TPrestepData, TAccumulatedImpulses, TContactImpulses, TConstraintCache>
where TPrestepData : struct, IContactViewablePrestepData<TPrestepData>
where TConstraintDescription : IConvexOneBodyContactConstraintDescription<TConstraintDescription>
where TConstraintCache : IPairCacheEntry
{
Expand All @@ -228,8 +246,9 @@ public class ConvexOneBodyAccessor<TConstraintDescription, TAccumulatedImpulses,
}
}

public class ConvexTwoBodyAccessor<TConstraintDescription, TAccumulatedImpulses, TContactImpulses, TConstraintCache> :
ContactConstraintAccessor<TConstraintDescription, TwoBodyHandles, TAccumulatedImpulses, TContactImpulses, TConstraintCache>
public class ConvexTwoBodyAccessor<TConstraintDescription, TPrestepData, TAccumulatedImpulses, TContactImpulses, TConstraintCache> :
ContactConstraintAccessor<TConstraintDescription, TwoBodyHandles, TPrestepData, TAccumulatedImpulses, TContactImpulses, TConstraintCache>
where TPrestepData : struct, IContactViewablePrestepData<TPrestepData>
where TConstraintDescription : IConvexTwoBodyContactConstraintDescription<TConstraintDescription>
where TConstraintCache : IPairCacheEntry
{
Expand All @@ -244,8 +263,9 @@ public class ConvexTwoBodyAccessor<TConstraintDescription, TAccumulatedImpulses,
}
}

public class NonconvexOneBodyAccessor<TConstraintDescription, TAccumulatedImpulses, TContactImpulses, TConstraintCache> :
ContactConstraintAccessor<TConstraintDescription, int, TAccumulatedImpulses, TContactImpulses, TConstraintCache>
public class NonconvexOneBodyAccessor<TConstraintDescription, TPrestepData, TAccumulatedImpulses, TContactImpulses, TConstraintCache> :
ContactConstraintAccessor<TConstraintDescription, int, TPrestepData, TAccumulatedImpulses, TContactImpulses, TConstraintCache>
where TPrestepData : struct, IContactViewablePrestepData<TPrestepData>
where TConstraintDescription : INonconvexOneBodyContactConstraintDescription<TConstraintDescription>
where TConstraintCache : IPairCacheEntry
{
Expand All @@ -263,8 +283,9 @@ public class NonconvexOneBodyAccessor<TConstraintDescription, TAccumulatedImpuls
}
}

public class NonconvexTwoBodyAccessor<TConstraintDescription, TAccumulatedImpulses, TContactImpulses, TConstraintCache> :
ContactConstraintAccessor<TConstraintDescription, TwoBodyHandles, TAccumulatedImpulses, TContactImpulses, TConstraintCache>
public class NonconvexTwoBodyAccessor<TConstraintDescription, TPrestepData, TAccumulatedImpulses, TContactImpulses, TConstraintCache> :
ContactConstraintAccessor<TConstraintDescription, TwoBodyHandles, TPrestepData, TAccumulatedImpulses, TContactImpulses, TConstraintCache>
where TPrestepData : struct, IContactViewablePrestepData<TPrestepData>
where TConstraintDescription : INonconvexTwoBodyContactConstraintDescription<TConstraintDescription>
where TConstraintCache : IPairCacheEntry
{
Expand Down
15 changes: 13 additions & 2 deletions BepuPhysics/CollisionDetection/NarrowPhase.cs
Expand Up @@ -125,6 +125,18 @@ protected NarrowPhase()
flushWorkerLoop = FlushWorkerLoop;
}

/// <summary>
/// Gets an unsafe pointer to the solver's prestep data representing a contact manifold.
/// </summary>
/// <param name="constraintHandle">Constraint handle of a contact manifold constraint to view.</param>
/// <param name="viewer">Unsafe manifold viewer for the requested pair.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void GetUnsafeManifoldViewer(int constraintHandle, out UnsafeManifoldViewer viewer)
{
ref var location = ref Solver.HandleToConstraint[constraintHandle];
contactConstraintAccessors[location.TypeId].GetUnsafeManifoldViewer(Solver, location, out viewer);
}

public void Prepare(float dt, IThreadDispatcher threadDispatcher = null)
{
timestepDuration = dt;
Expand All @@ -137,8 +149,7 @@ public void Prepare(float dt, IThreadDispatcher threadDispatcher = null)
protected abstract void OnPreflush(IThreadDispatcher threadDispatcher, bool deterministic);
protected abstract void OnPostflush(IThreadDispatcher threadDispatcher);


bool deterministic;

int flushJobIndex;
QuickList<NarrowPhaseFlushJob> flushJobs;
IThreadDispatcher threadDispatcher;
Expand Down
276 changes: 276 additions & 0 deletions BepuPhysics/CollisionDetection/UnsafeManifoldViewer.cs
@@ -0,0 +1,276 @@
using BepuPhysics.Constraints;
using BepuUtilities;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;

namespace BepuPhysics.CollisionDetection
{
/// <summary>
/// Data associated with a single contact in a contact manifold.
/// </summary>
public struct ContactData
{
/// <summary>
/// Offset from the center of body A to the contact.
/// </summary>
public Vector3 OffsetA;
/// <summary>
/// Normal of the contact surface.
/// </summary>
public Vector3 Normal;
/// <summary>
/// Penetration depth at the contact location.
/// </summary>
public float Depth;
}


/// <summary>
/// Data shared across an entire contact manifold.
/// </summary>
public struct ManifoldData
{
public float FrictionCoefficient;
public SpringSettings SpringSettings;
public float MaximumRecoveryVelocity;
}

/// <summary>
/// Raw data bundle shared across an entire contact manifold.
/// </summary>
public struct ManifoldDataWide
{
public Vector<float> FrictionCoefficient;
public SpringSettingsWide SpringSettings;
public Vector<float> MaximumRecoveryVelocity;
}


/// <summary>
/// Accesses existing contact data in the solver.
/// Movement of memory in the solver may invalidate this view and result in access violations; do not continue to use an instance if anything changes in the solver during its lifespan.
/// </summary>
public unsafe struct UnsafeManifoldViewer
{
byte* offsetABase;
byte* normalBase;
byte* depthBase;
byte* common;
int offsetDepthStride;
int normalStride;

int contactCount;
bool convex;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal UnsafeManifoldViewer(int contactCount, bool convex, void* common, void* offsetABase, int offsetDepthStride, void* normalBase, int normalStride, void* depthBase)
{
this.offsetABase = (byte*)offsetABase;
this.normalBase = (byte*)normalBase;
this.depthBase = (byte*)depthBase;
this.common = (byte*)common;
this.offsetDepthStride = offsetDepthStride;
this.normalStride = normalStride;

this.contactCount = contactCount;
this.convex = convex;
}

/// <summary>
/// Gets the number of contacts in the manifold.
/// </summary>
public int ContactCount => contactCount;

/// <summary>
/// Gets whether this manifold is convex. Convex manifolds share the same normal for every contact; nonconvex manifolds do not.
/// </summary>
public bool Convex => convex;

/// <summary>
/// Gets or sets the contact data at the given index in the manifold.
/// </summary>
/// <param name="index">Index of the contact to access.</param>
/// <returns>Contact data at the given index in the manifold.</returns>
public ContactData this[int index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
Debug.Assert(index >= 0 && index < contactCount, "Index must be within the contact count.");
ContactData toReturn;
GetOffsetA(index, out toReturn.OffsetA);
GetNormal(index, out toReturn.Normal);
toReturn.Depth = GetDepth(index);
return toReturn;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
Debug.Assert(index >= 0 && index < contactCount, "Index must be within the contact count.");
SetOffsetA(index, value.OffsetA);
SetNormal(index, value.Normal);
GetDepth(index) = value.Depth;
}
}

/// <summary>
/// Gets a reference to the offset bundle in the solver prestep data.
/// </summary>
/// <param name="index">Contact index to access.</param>
/// <returns>Reference to a contact's offset bundle in the solver prestep data.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref Vector3Wide GetOffsetAWide(int index)
{
Debug.Assert(index >= 0 && index < contactCount, "Index must be within the contact count.");
return ref Unsafe.AsRef<Vector3Wide>(offsetABase + offsetDepthStride * index);
}

/// <summary>
/// Gets the offset from body A to the contact for the given contact index.
/// </summary>
/// <param name="index">Index of the contact to access.</param>
/// <param name="offsetA">Offset from body A to the contact location.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void GetOffsetA(int index, out Vector3 offsetA)
{
Vector3Wide.ReadFirst(GetOffsetAWide(index), out offsetA);
}

/// <summary>
/// Sets the offset from body A to the contact for the given contact index.
/// </summary>
/// <param name="index">Index of the contact to access.</param>
/// <param name="offsetA">New offset from body A to the contact location.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetOffsetA(int index, in Vector3 offsetA)
{
Vector3Wide.WriteFirst(offsetA, ref GetOffsetAWide(index));
}

/// <summary>
/// Gets a reference to the normal bundle in the solver prestep data.
/// </summary>
/// <param name="index">Contact index to access.</param>
/// <returns>Reference to a contact's normal bundle in the solver prestep data.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref Vector3Wide GetNormalWide(int index)
{
Debug.Assert(index >= 0 && index < contactCount, "Index must be within the contact count.");
return ref Unsafe.AsRef<Vector3Wide>(normalBase + normalStride * index);
}

/// <summary>
/// Gets the normal for the given contact index.
/// </summary>
/// <param name="index">Index of the contact to access.</param>
/// <param name="normal">Normal for the accessed contact.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void GetNormal(int index, out Vector3 normal)
{
Vector3Wide.ReadFirst(GetNormalWide(index), out normal);
}

/// <summary>
/// Sets the normal for the given contact index.
/// </summary>
/// <param name="index">Index of the contact to access.</param>
/// <param name="normal">New normal for the accessed contact.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetNormal(int index, in Vector3 normal)
{
Vector3Wide.WriteFirst(normal, ref GetNormalWide(index));
}

/// <summary>
/// Gets a reference to the depth in the solver prestep data.
/// </summary>
/// <param name="index">Contact index to access.</param>
/// <returns>Reference to a contact's depth in the solver prestep data.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref float GetDepth(int index)
{
Debug.Assert(index >= 0 && index < contactCount, "Index must be within the contact count.");
return ref Unsafe.AsRef<float>(depthBase + offsetDepthStride * index);
}

/// <summary>
/// Gets a reference to the depth bundle in the solver prestep data.
/// </summary>
/// <returns>Reference to a contact's depth bundle in the solver prestep data.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref ManifoldDataWide GetManifoldDataWide()
{
//Note that this assumes the memory layout matches the ManifoldDataWide struct.
return ref Unsafe.AsRef<ManifoldDataWide>(common);
}

/// <summary>
/// Gets the data shared across the entire manifold.
/// </summary>
/// <param name="depth">Depth for the accessed contact.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void GetManifoldData(out ManifoldData manifoldData)
{
ref var wide = ref GetManifoldDataWide();
manifoldData.FrictionCoefficient = wide.FrictionCoefficient[0];
SpringSettingsWide.ReadFirst(wide.SpringSettings, out manifoldData.SpringSettings);
manifoldData.MaximumRecoveryVelocity = wide.MaximumRecoveryVelocity[0];
}

/// <summary>
/// Sets the data shared across the entire manifold.
/// </summary>
/// <param name="manifoldData">New manifold data.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetManifoldData(in ManifoldData manifoldData)
{
ref var wide = ref GetManifoldDataWide();
GatherScatter.GetFirst(ref wide.FrictionCoefficient) = manifoldData.FrictionCoefficient;
SpringSettingsWide.WriteFirst(manifoldData.SpringSettings, ref wide.SpringSettings);
GatherScatter.GetFirst(ref wide.MaximumRecoveryVelocity) = manifoldData.MaximumRecoveryVelocity;
}

/// <summary>
/// Gets a reference to the friction coefficient for the manifold.
/// </summary>
public ref float FrictionCoefficient
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return ref GatherScatter.GetFirst(ref GetManifoldDataWide().FrictionCoefficient); }
}

/// <summary>
/// Gets a reference to the maximum recovery velocity for the manifold.
/// </summary>
public ref float MaximumRecoveryVelocity
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return ref GatherScatter.GetFirst(ref GetManifoldDataWide().MaximumRecoveryVelocity); }
}

/// <summary>
/// Gets the spring settings for the manifold.
/// </summary>
/// <param name="springSettings">Spring settings for the manifold.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void GetSpringSettings(out SpringSettings springSettings)
{
SpringSettingsWide.ReadFirst(GetManifoldDataWide().SpringSettings, out springSettings);
}

/// <summary>
/// Sets the spring settings for the manifold.
/// </summary>
/// <param name="springSettings">Spring settings for the manifold.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetSpringSettings(in SpringSettings springSettings)
{
SpringSettingsWide.WriteFirst(springSettings, ref GetManifoldDataWide().SpringSettings);
}

}
}

0 comments on commit 8ee8de0

Please sign in to comment.