physxCAPI/physxCDLL/include/PxContact.h
2023-08-11 10:55:58 +08:00

664 lines
17 KiB
C++

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2023 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
#ifndef PX_CONTACT_H
#define PX_CONTACT_H
/** \addtogroup physics
@{
*/
#include "foundation/PxVec3.h"
#include "foundation/PxAssert.h"
#include "PxConstraintDesc.h"
#include "PxNodeIndex.h"
#if !PX_DOXYGEN
namespace physx
{
#endif
#if PX_VC
#pragma warning(push)
#pragma warning(disable: 4324) // Padding was added at the end of a structure because of a __declspec(align) value.
#endif
#define PXC_CONTACT_NO_FACE_INDEX 0xffffffff
class PxActor;
/**
\brief Header for a contact patch where all points share same material and normal
*/
PX_ALIGN_PREFIX(16)
struct PxContactPatch
{
enum PxContactPatchFlags
{
eHAS_FACE_INDICES = 1, //!< Indicates this contact stream has face indices.
eMODIFIABLE = 2, //!< Indicates this contact stream is modifiable.
eFORCE_NO_RESPONSE = 4, //!< Indicates this contact stream is notify-only (no contact response).
eHAS_MODIFIED_MASS_RATIOS = 8, //!< Indicates this contact stream has modified mass ratios
eHAS_TARGET_VELOCITY = 16, //!< Indicates this contact stream has target velocities set
eHAS_MAX_IMPULSE = 32, //!< Indicates this contact stream has max impulses set
eREGENERATE_PATCHES = 64, //!< Indicates this contact stream needs patches re-generated. This is required if the application modified either the contact normal or the material properties
eCOMPRESSED_MODIFIED_CONTACT = 128
};
/**
\brief Modifiers for scaling the inertia of the involved bodies
*/
PX_ALIGN(16, PxConstraintInvMassScale mMassModification); //16
/**
\brief Contact normal
*/
PX_ALIGN(16, PxVec3 normal); //28
/**
\brief Restitution coefficient
*/
PxReal restitution; //32
/**
\brief Dynamic friction coefficient
*/
PxReal dynamicFriction; //36
/**
\brief Static friction coefficient
*/
PxReal staticFriction; //40
/**
\brief Damping coefficient (for compliant contacts)
*/
PxReal damping; //44
/**
\brief Index of the first contact in the patch
*/
PxU16 startContactIndex; //46
/**
\brief The number of contacts in this patch
*/
PxU8 nbContacts; //47 //Can be a U8
/**
\brief The combined material flag of two actors that come in contact
@see PxMaterialFlag, PxCombineMode
*/
PxU8 materialFlags; //48 //Can be a U16
/**
\brief The PxContactPatchFlags for this patch
*/
PxU16 internalFlags; //50 //Can be a U16
/**
\brief Material index of first body
*/
PxU16 materialIndex0; //52 //Can be a U16
/**
\brief Material index of second body
*/
PxU16 materialIndex1; //54 //Can be a U16
PxU16 pad[5]; //64
}
PX_ALIGN_SUFFIX(16);
/**
\brief Contact point data
*/
PX_ALIGN_PREFIX(16)
struct PxContact
{
/**
\brief Contact point in world space
*/
PxVec3 contact; //12
/**
\brief Separation value (negative implies penetration).
*/
PxReal separation; //16
}
PX_ALIGN_SUFFIX(16);
/**
\brief Contact point data with additional target and max impulse values
*/
PX_ALIGN_PREFIX(16)
struct PxExtendedContact : public PxContact
{
/**
\brief Target velocity
*/
PX_ALIGN(16, PxVec3 targetVelocity); //28
/**
\brief Maximum impulse
*/
PxReal maxImpulse; //32
}
PX_ALIGN_SUFFIX(16);
/**
\brief A modifiable contact point. This has additional fields per-contact to permit modification by user.
\note Not all fields are currently exposed to the user.
*/
PX_ALIGN_PREFIX(16)
struct PxModifiableContact : public PxExtendedContact
{
/**
\brief Contact normal
*/
PX_ALIGN(16, PxVec3 normal); //44
/**
\brief Restitution coefficient
*/
PxReal restitution; //48
/**
\brief Material Flags
*/
PxU32 materialFlags; //52
/**
\brief Shape A's material index
*/
PxU16 materialIndex0; //54
/**
\brief Shape B's material index
*/
PxU16 materialIndex1; //56
/**
\brief static friction coefficient
*/
PxReal staticFriction; //60
/**
\brief dynamic friction coefficient
*/
PxReal dynamicFriction; //64
}
PX_ALIGN_SUFFIX(16);
/**
\brief A class to iterate over a compressed contact stream. This supports read-only access to the various contact formats.
*/
struct PxContactStreamIterator
{
enum StreamFormat
{
eSIMPLE_STREAM,
eMODIFIABLE_STREAM,
eCOMPRESSED_MODIFIABLE_STREAM
};
/**
\brief Utility zero vector to optimize functions returning zero vectors when a certain flag isn't set.
\note This allows us to return by reference instead of having to return by value. Returning by value will go via memory (registers -> stack -> registers), which can
cause performance issues on certain platforms.
*/
PxVec3 zero;
/**
\brief The patch headers.
*/
const PxContactPatch* patch;
/**
\brief The contacts
*/
const PxContact* contact;
/**
\brief The contact triangle face index
*/
const PxU32* faceIndice;
/**
\brief The total number of patches in this contact stream
*/
PxU32 totalPatches;
/**
\brief The total number of contact points in this stream
*/
PxU32 totalContacts;
/**
\brief The current contact index
*/
PxU32 nextContactIndex;
/**
\brief The current patch Index
*/
PxU32 nextPatchIndex;
/**
\brief Size of contact patch header
\note This varies whether the patch is modifiable or not.
*/
PxU32 contactPatchHeaderSize;
/**
\brief Contact point size
\note This varies whether the patch has feature indices or is modifiable.
*/
PxU32 contactPointSize;
/**
\brief The stream format
*/
StreamFormat mStreamFormat;
/**
\brief Indicates whether this stream is notify-only or not.
*/
PxU32 forceNoResponse;
/**
\brief Internal helper for stepping the contact stream iterator
*/
bool pointStepped;
/**
\brief Specifies if this contactPatch has face indices (handled as bool)
@see faceIndice
*/
PxU32 hasFaceIndices;
/**
\brief Constructor
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE PxContactStreamIterator(const PxU8* contactPatches, const PxU8* contactPoints, const PxU32* contactFaceIndices, PxU32 nbPatches, PxU32 nbContacts)
: zero(0.f)
{
bool modify = false;
bool compressedModify = false;
bool response = false;
bool indices = false;
PxU32 pointSize = 0;
PxU32 patchHeaderSize = sizeof(PxContactPatch);
const PxContactPatch* patches = reinterpret_cast<const PxContactPatch*>(contactPatches);
if(patches)
{
modify = (patches->internalFlags & PxContactPatch::eMODIFIABLE) != 0;
compressedModify = (patches->internalFlags & PxContactPatch::eCOMPRESSED_MODIFIED_CONTACT) != 0;
indices = (patches->internalFlags & PxContactPatch::eHAS_FACE_INDICES) != 0;
patch = patches;
contact = reinterpret_cast<const PxContact*>(contactPoints);
faceIndice = contactFaceIndices;
pointSize = compressedModify ? sizeof(PxExtendedContact) : modify ? sizeof(PxModifiableContact) : sizeof(PxContact);
response = (patch->internalFlags & PxContactPatch::eFORCE_NO_RESPONSE) == 0;
}
mStreamFormat = compressedModify ? eCOMPRESSED_MODIFIABLE_STREAM : modify ? eMODIFIABLE_STREAM : eSIMPLE_STREAM;
hasFaceIndices = PxU32(indices);
forceNoResponse = PxU32(!response);
contactPatchHeaderSize = patchHeaderSize;
contactPointSize = pointSize;
nextPatchIndex = 0;
nextContactIndex = 0;
totalContacts = nbContacts;
totalPatches = nbPatches;
pointStepped = false;
}
/**
\brief Returns whether there are more patches in this stream.
\return Whether there are more patches in this stream.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE bool hasNextPatch() const
{
return nextPatchIndex < totalPatches;
}
/**
\brief Returns the total contact count.
\return Total contact count.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getTotalContactCount() const
{
return totalContacts;
}
/**
\brief Returns the total patch count.
\return Total patch count.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getTotalPatchCount() const
{
return totalPatches;
}
/**
\brief Advances iterator to next contact patch.
*/
PX_CUDA_CALLABLE PX_INLINE void nextPatch()
{
PX_ASSERT(nextPatchIndex < totalPatches);
if(nextPatchIndex)
{
if(nextContactIndex < patch->nbContacts)
{
PxU32 nbToStep = patch->nbContacts - this->nextContactIndex;
contact = reinterpret_cast<const PxContact*>(reinterpret_cast<const PxU8*>(contact) + contactPointSize * nbToStep);
}
patch = reinterpret_cast<const PxContactPatch*>(reinterpret_cast<const PxU8*>(patch) + contactPatchHeaderSize);
}
nextPatchIndex++;
nextContactIndex = 0;
}
/**
\brief Returns if the current patch has more contacts.
\return If there are more contacts in the current patch.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE bool hasNextContact() const
{
return nextContactIndex < (patch->nbContacts);
}
/**
\brief Advances to the next contact in the patch.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE void nextContact()
{
PX_ASSERT(nextContactIndex < patch->nbContacts);
if(pointStepped)
{
contact = reinterpret_cast<const PxContact*>(reinterpret_cast<const PxU8*>(contact) + contactPointSize);
faceIndice++;
}
nextContactIndex++;
pointStepped = true;
}
/**
\brief Gets the current contact's normal
\return The current contact's normal.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE const PxVec3& getContactNormal() const
{
return getContactPatch().normal;
}
/**
\brief Gets the inverse mass scale for body 0.
\return The inverse mass scale for body 0.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getInvMassScale0() const
{
return patch->mMassModification.linear0;
}
/**
\brief Gets the inverse mass scale for body 1.
\return The inverse mass scale for body 1.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getInvMassScale1() const
{
return patch->mMassModification.linear1;
}
/**
\brief Gets the inverse inertia scale for body 0.
\return The inverse inertia scale for body 0.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getInvInertiaScale0() const
{
return patch->mMassModification.angular0;
}
/**
\brief Gets the inverse inertia scale for body 1.
\return The inverse inertia scale for body 1.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getInvInertiaScale1() const
{
return patch->mMassModification.angular1;
}
/**
\brief Gets the contact's max impulse.
\return The contact's max impulse.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getMaxImpulse() const
{
return mStreamFormat != eSIMPLE_STREAM ? getExtendedContact().maxImpulse : PX_MAX_REAL;
}
/**
\brief Gets the contact's target velocity.
\return The contact's target velocity.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE const PxVec3& getTargetVel() const
{
return mStreamFormat != eSIMPLE_STREAM ? getExtendedContact().targetVelocity : zero;
}
/**
\brief Gets the contact's contact point.
\return The contact's contact point.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE const PxVec3& getContactPoint() const
{
return contact->contact;
}
/**
\brief Gets the contact's separation.
\return The contact's separation.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getSeparation() const
{
return contact->separation;
}
/**
\brief Gets the contact's face index for shape 0.
\return The contact's face index for shape 0.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getFaceIndex0() const
{
return PXC_CONTACT_NO_FACE_INDEX;
}
/**
\brief Gets the contact's face index for shape 1.
\return The contact's face index for shape 1.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getFaceIndex1() const
{
return hasFaceIndices ? *faceIndice : PXC_CONTACT_NO_FACE_INDEX;
}
/**
\brief Gets the contact's static friction coefficient.
\return The contact's static friction coefficient.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getStaticFriction() const
{
return getContactPatch().staticFriction;
}
/**
\brief Gets the contact's dynamic friction coefficient.
\return The contact's dynamic friction coefficient.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getDynamicFriction() const
{
return getContactPatch().dynamicFriction;
}
/**
\brief Gets the contact's restitution coefficient.
\return The contact's restitution coefficient.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getRestitution() const
{
return getContactPatch().restitution;
}
/**
\brief Gets the contact's damping value.
\return The contact's damping value.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getDamping() const
{
return getContactPatch().damping;
}
/**
\brief Gets the contact's material flags.
\return The contact's material flags.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getMaterialFlags() const
{
return getContactPatch().materialFlags;
}
/**
\brief Gets the contact's material index for shape 0.
\return The contact's material index for shape 0.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE PxU16 getMaterialIndex0() const
{
return PxU16(getContactPatch().materialIndex0);
}
/**
\brief Gets the contact's material index for shape 1.
\return The contact's material index for shape 1.
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE PxU16 getMaterialIndex1() const
{
return PxU16(getContactPatch().materialIndex1);
}
/**
\brief Advances the contact stream iterator to a specific contact index.
\return True if advancing was possible
*/
bool advanceToIndex(const PxU32 initialIndex)
{
PX_ASSERT(this->nextPatchIndex == 0 && this->nextContactIndex == 0);
PxU32 numToAdvance = initialIndex;
if(numToAdvance == 0)
{
PX_ASSERT(hasNextPatch());
nextPatch();
return true;
}
while(numToAdvance)
{
while(hasNextPatch())
{
nextPatch();
PxU32 patchSize = patch->nbContacts;
if(numToAdvance <= patchSize)
{
contact = reinterpret_cast<const PxContact*>(reinterpret_cast<const PxU8*>(contact) + contactPointSize * numToAdvance);
nextContactIndex += numToAdvance;
return true;
}
else
{
numToAdvance -= patchSize;
}
}
}
return false;
}
private:
/**
\brief Internal helper
*/
PX_CUDA_CALLABLE PX_FORCE_INLINE const PxContactPatch& getContactPatch() const
{
return *static_cast<const PxContactPatch*>(patch);
}
PX_CUDA_CALLABLE PX_FORCE_INLINE const PxExtendedContact& getExtendedContact() const
{
PX_ASSERT(mStreamFormat == eMODIFIABLE_STREAM || mStreamFormat == eCOMPRESSED_MODIFIABLE_STREAM);
return *static_cast<const PxExtendedContact*>(contact);
}
};
/**
\brief Contains contact information for a contact reported by the direct-GPU contact report API. See PxScene::copyContactData().
*/
struct PxGpuContactPair
{
PxU8* contactPatches; //!< Ptr to contact patches. Type: PxContactPatch*, size: nbPatches.
PxU8* contactPoints; //!< Ptr to contact points. Type: PxContact*, size: nbContacts.
PxReal* contactForces; //!< Ptr to contact forces. Size: nbContacts.
PxU32 transformCacheRef0; //!< Ref to shape0's transform in transform cache.
PxU32 transformCacheRef1; //!< Ref to shape1's transform in transform cache.
PxNodeIndex nodeIndex0; //!< Unique Id for actor0 if the actor is dynamic.
PxNodeIndex nodeIndex1; //!< Unique Id for actor1 if the actor is dynamic.
PxActor* actor0; //!< Ptr to PxActor for actor0.
PxActor* actor1; //!< Ptr to PxActor for actor1.
PxU16 nbContacts; //!< Num contacts.
PxU16 nbPatches; //!< Num patches.
};
#if PX_VC
#pragma warning(pop)
#endif
#if !PX_DOXYGEN
} // namespace physx
#endif
/** @} */
#endif