// 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 "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 Struct for specifying mass modification for a pair of rigids \deprecated Use #PxConstraintInvMassScale instead. Deprecated since PhysX version 5.1. */ PX_ALIGN_PREFIX(16) struct PX_DEPRECATED PxMassModificationProps { PxReal mInvMassScale0; PxReal mInvInertiaScale0; PxReal mInvMassScale1; PxReal mInvInertiaScale1; } PX_ALIGN_SUFFIX(16); /** \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, PxMassModificationProps 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(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(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(reinterpret_cast(contact) + contactPointSize * nbToStep); } patch = reinterpret_cast(reinterpret_cast(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(reinterpret_cast(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.mInvMassScale0; } /** \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.mInvMassScale1; } /** \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.mInvInertiaScale0; } /** \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.mInvInertiaScale1; } /** \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(reinterpret_cast(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(patch); } PX_CUDA_CALLABLE PX_FORCE_INLINE const PxExtendedContact& getExtendedContact() const { PX_ASSERT(mStreamFormat == eMODIFIABLE_STREAM || mStreamFormat == eCOMPRESSED_MODIFIABLE_STREAM); return *static_cast(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