PxBroadPhase.h#

Fully qualified name: include/PxBroadPhase.h

File members: include/PxBroadPhase.h

// 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-2025 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_BROAD_PHASE_H
#define PX_BROAD_PHASE_H

#include "PxPhysXConfig.h"
#include "foundation/PxBounds3.h"

#if !PX_DOXYGEN
namespace physx
{
#endif

    class PxBaseTask;
    class PxCudaContextManager;
    class PxAllocatorCallback;

    struct PxBroadPhaseType
    {
        enum Enum
        {
            eSAP,
            eMBP,
            eABP,
            ePABP,
            eGPU,
            eLAST
        };
    };

    struct PxBroadPhaseRegion
    {
        PxBounds3   mBounds;
        void*       mUserData;
    };

    struct PxBroadPhaseRegionInfo
    {
        PxBroadPhaseRegion  mRegion;
        PxU32               mNbStaticObjects;
        PxU32               mNbDynamicObjects;
        bool                mActive;
        bool                mOverlap;
    };

    struct PxBroadPhaseCaps
    {
        PxU32   mMaxNbRegions;
    };

    struct PxGpuBroadPhaseDesc
    {
        PxGpuBroadPhaseDesc() :
            gpuBroadPhaseNbBitsShiftX   (4),
            gpuBroadPhaseNbBitsShiftY   (4),
            gpuBroadPhaseNbBitsShiftZ   (4),
            gpuBroadPhaseNbBitsEnvIDX   (0),
            gpuBroadPhaseNbBitsEnvIDY   (0),
            gpuBroadPhaseNbBitsEnvIDZ   (0)
        {
        }

        // The GPU broadphase encodes bounds as integers, and then right-shifts the data by this amount of bits.
        // This makes the bounds a bit larger, which avoids losing and recreating overlaps over and over when
        // two objects are just touching. This effect is similar to what can be achieved with the contact distance
        // parameter, and the amount by which the bounds are inflated depends on the distance from the bounds to
        // the origin (as the bounds encoding does not use a regular float-to-integer conversion, but instead a
        // reinterpretation of the float's bits). The default value in the GPU broadphase has always been 4 bits
        // but it is safe to use 0 here for more accurate bounds.
        PxU8    gpuBroadPhaseNbBitsShiftX;
        PxU8    gpuBroadPhaseNbBitsShiftY;
        PxU8    gpuBroadPhaseNbBitsShiftZ;

        // The bits lost by the previous shifts (gpuBroadPhaseNbBitsShiftXYZ) can be replaced with bits of the
        // environment IDs. This only makes sense when these parameters are used (see PxActor::setEnvironmentID
        // and PxAggregate::setEnvironmentID). In this case a number of bits from the environment IDs are stored
        // in the MSBs of encoded bounds. This has the effect of virtually spreading the bounds over 3D space,
        // which reduces the number of internal overlaps inside the broad-phase. This is mainly useful in RL
        // scenarios with "co-located" environments, but it can also provide performance gains with regular grid
        // configurations, that also generate a lot of internal overlaps on all coordinate axes.
        //
        // Beware: when using this feature, each object of each environment should be assigned a proper environment
        // ID. Objects shared between all environments (i.e. objects whose environment ID is PX_INVALID_U32) will
        // otherwise be internally assigned bounds that cover the entire 3D space, creating a lot of overlaps and
        // potential performance issues. This is only a concern when gpuBroadPhaseNbBitsEnvIDX/Y/Z are non zero,
        // shared objects are fine otherwise.
        PxU8    gpuBroadPhaseNbBitsEnvIDX;
        PxU8    gpuBroadPhaseNbBitsEnvIDY;
        PxU8    gpuBroadPhaseNbBitsEnvIDZ;

        PX_INLINE   bool        isValid()   const
        {
            // This is used on 32bit data so it makes no sense to shift more than 32 bits.
            // It also makes no sense to shift all the bits of source data.
            if( gpuBroadPhaseNbBitsShiftX > 31
            ||  gpuBroadPhaseNbBitsShiftY > 31
            ||  gpuBroadPhaseNbBitsShiftZ > 31)
                return false;

            if( gpuBroadPhaseNbBitsEnvIDX > 31
            ||  gpuBroadPhaseNbBitsEnvIDY > 31
            ||  gpuBroadPhaseNbBitsEnvIDZ > 31)
                return false;

            // We can only store bits from environment IDs in bits shifted away from the source data.
            // So we need to drop (shift) at least as many bits of the source data as we need for env IDs.
            if( gpuBroadPhaseNbBitsEnvIDX > gpuBroadPhaseNbBitsShiftX
            ||  gpuBroadPhaseNbBitsEnvIDY > gpuBroadPhaseNbBitsShiftY
            ||  gpuBroadPhaseNbBitsEnvIDZ > gpuBroadPhaseNbBitsShiftZ)
                return false;
            return true;
        }
    };

    class PxBroadPhaseDesc
    {
        public:
        PxBroadPhaseDesc(PxBroadPhaseType::Enum type = PxBroadPhaseType::eLAST) :
            mType                       (type),
            mContextID                  (0),
            mContextManager             (NULL),
            mFoundLostPairsCapacity     (256 * 1024),
            mDiscardStaticVsKinematic   (false),
            mDiscardKinematicVsKinematic(false)
        {}

        PxBroadPhaseType::Enum  mType;
        PxU64                   mContextID;

        PxCudaContextManager*   mContextManager;
        PxU32                   mFoundLostPairsCapacity;

        bool                    mDiscardStaticVsKinematic;
        bool                    mDiscardKinematicVsKinematic;

        PX_INLINE   bool        isValid()   const
        {
            if(PxU32(mType)>=PxBroadPhaseType::eLAST)
                return false;

            if(mType==PxBroadPhaseType::eGPU && !mContextManager)
                return false;

            return true;
        }
    };

    typedef PxU32 PxBpIndex;
    typedef PxU32 PxBpFilterGroup;
    #define PX_INVALID_BP_FILTER_GROUP  0xffffffff

    PX_C_EXPORT PX_PHYSX_CORE_API   PxBpFilterGroup PxGetBroadPhaseStaticFilterGroup();

    PX_C_EXPORT PX_PHYSX_CORE_API   PxBpFilterGroup PxGetBroadPhaseDynamicFilterGroup(PxU32 id);

    PX_C_EXPORT PX_PHYSX_CORE_API   PxBpFilterGroup PxGetBroadPhaseKinematicFilterGroup(PxU32 id);

    class PxBroadPhaseUpdateData
    {
        public:

        PxBroadPhaseUpdateData( const PxBpIndex* created, PxU32 nbCreated,
                                const PxBpIndex* updated, PxU32 nbUpdated,
                                const PxBpIndex* removed, PxU32 nbRemoved,
                                const PxBounds3* bounds, const PxBpFilterGroup* groups, const float* distances,
                                PxU32 capacity) :
            mCreated    (created),  mNbCreated  (nbCreated),
            mUpdated    (updated),  mNbUpdated  (nbUpdated),
            mRemoved    (removed),  mNbRemoved  (nbRemoved),
            mBounds     (bounds),   mGroups     (groups),   mDistances  (distances),
            mCapacity   (capacity)
        {
        }

        PxBroadPhaseUpdateData(const PxBroadPhaseUpdateData& other) :
            mCreated    (other.mCreated),   mNbCreated  (other.mNbCreated),
            mUpdated    (other.mUpdated),   mNbUpdated  (other.mNbUpdated),
            mRemoved    (other.mRemoved),   mNbRemoved  (other.mNbRemoved),
            mBounds     (other.mBounds),    mGroups     (other.mGroups),    mDistances  (other.mDistances),
            mCapacity   (other.mCapacity)
        {
        }

        PxBroadPhaseUpdateData& operator=(const PxBroadPhaseUpdateData& other);

        const PxBpIndex*        mCreated;
        const PxU32             mNbCreated;

        const PxBpIndex*        mUpdated;
        const PxU32             mNbUpdated;

        const PxBpIndex*        mRemoved;
        const PxU32             mNbRemoved;

        const PxBounds3*        mBounds;
        const PxBpFilterGroup*  mGroups;
        const float*            mDistances;
        const PxU32             mCapacity;
    };

    struct PxBroadPhasePair
    {
        PxBpIndex   mID0;
        PxBpIndex   mID1;
    };

    struct PxBroadPhaseResults
    {
        PxBroadPhaseResults() : mNbCreatedPairs(0), mCreatedPairs(NULL), mNbDeletedPairs(0), mDeletedPairs(NULL)    {}

        PxU32                   mNbCreatedPairs;
        const PxBroadPhasePair* mCreatedPairs;

        PxU32                   mNbDeletedPairs;
        const PxBroadPhasePair* mDeletedPairs;
    };

    class PxBroadPhaseRegions
    {
        protected:
                PxBroadPhaseRegions()   {}
        virtual ~PxBroadPhaseRegions()  {}
        public:

        virtual PxU32   getNbRegions()  const   = 0;

        virtual PxU32   getRegions(PxBroadPhaseRegionInfo* userBuffer, PxU32 bufferSize, PxU32 startIndex=0)    const   = 0;

        virtual PxU32   addRegion(const PxBroadPhaseRegion& region, bool populateRegion, const PxBounds3* bounds, const float* distances)   = 0;

        virtual bool    removeRegion(PxU32 handle)  = 0;

        /*
        \brief Return the number of objects that are not in any region.
        */
        virtual PxU32   getNbOutOfBoundsObjects()   const   = 0;

        /*
        \brief Return an array of objects that are not in any region.
        */
        virtual const PxU32*    getOutOfBoundsObjects() const   = 0;
    };

    class PxBroadPhase
    {
        protected:
                PxBroadPhase()  {}
        virtual ~PxBroadPhase() {}
        public:

        /*
        \brief Releases the broadphase.
        */
        virtual void    release()   = 0;

        virtual PxBroadPhaseType::Enum  getType()   const   = 0;

        virtual void    getCaps(PxBroadPhaseCaps& caps) const   = 0;

        virtual PxBroadPhaseRegions*    getRegions()    = 0;

        virtual PxAllocatorCallback*    getAllocator()  = 0;

        virtual PxU64   getContextID()  const   = 0;

        virtual void    setScratchBlock(void* scratchBlock, PxU32 size) = 0;

        virtual void    update(const PxBroadPhaseUpdateData& updateData, PxBaseTask* continuation=NULL) = 0;

        virtual void    fetchResults(PxBroadPhaseResults& results)  = 0;

        PX_FORCE_INLINE void    updateAndFetchResults(PxBroadPhaseResults& results, const PxBroadPhaseUpdateData& updateData)
        {
            update(updateData);
            fetchResults(results);
        }

        PX_DEPRECATED   PX_FORCE_INLINE void    update(PxBroadPhaseResults& results, const PxBroadPhaseUpdateData& updateData)
        {
            update(updateData);
            fetchResults(results);
        }
    };

    PX_C_EXPORT PX_PHYSX_CORE_API   PxBroadPhase*   PxCreateBroadPhase(const PxBroadPhaseDesc& desc);

    class PxAABBManager
    {
        protected:
                PxAABBManager()     {}
        virtual ~PxAABBManager()    {}
        public:

        /*
        \brief Releases the AABB manager.
        */
        virtual void    release()   = 0;

        virtual PxBroadPhase&   getBroadPhase() = 0;

        virtual const PxBounds3*    getBounds() const   = 0;

        virtual const float*    getDistances()  const   = 0;

        virtual const PxBpFilterGroup*  getGroups() const   = 0;

        virtual PxU32   getCapacity()   const   = 0;

        virtual void    addObject(PxBpIndex index, const PxBounds3& bounds, PxBpFilterGroup group, float distance=0.0f) = 0;

        virtual void    removeObject(PxBpIndex index)   = 0;

        virtual void    updateObject(PxBpIndex index, const PxBounds3* bounds=NULL, const float* distance=NULL) = 0;

        virtual void    update(PxBaseTask* continuation=NULL)   = 0;

        virtual void    fetchResults(PxBroadPhaseResults& results)  = 0;

        PX_FORCE_INLINE void    updateAndFetchResults(PxBroadPhaseResults& results)
        {
            update();
            fetchResults(results);
        }

        PX_DEPRECATED   PX_FORCE_INLINE void    update(PxBroadPhaseResults& results)
        {
            update();
            fetchResults(results);
        }
    };

    PX_C_EXPORT PX_PHYSX_CORE_API   PxAABBManager*  PxCreateAABBManager(PxBroadPhase& broadphase);

#if !PX_DOXYGEN
} // namespace physx
#endif

#endif