This chapter describes how to use PhysX' collision and shape query functionality with individual geometry objects. This is in contrast to ref:collision and ref:scene query functionality, which collide or query against all the objects in a scene. There are four main kinds of geometry queries:
In addition, PhysX provides helpers to compute the AABB of a geometry object, and to compute the distance between a point and a geometry object.
In all of the following functions, a geometry object is defined by its shape (a PxGeometry structure) and its pose (a PxTransform structure). All transforms and vectors of a query are interpreted as being in one arbitrary space, and the results are also returned in that space.
A raycast query traces a point along a line segment and records intersections with the surface of the geometry object. PhysX supports raycasts for all geometry types.
The following code illustrates how to use a raycast query:
PxRaycastHit hitInfo;
PxU32 maxHits = 1;
bool anyHit = false;
PxHitFlags hitFlags = PxHitFlag::ePOSITION|PxHitFlag::eNORMAL|PxHitFlag::eDISTANCE|PxHitFlag::eUV;
PxU32 hitCount = PxGeometryQuery::raycast(origin, unitDir,
geom, pose,
maxDist,
hitFlags,
maxHits, &hitInfo, anyHit);
The arguments are interpreted as follows:
The returned result is the number of intersections found. For each intersection, a PxRaycastHit is populated. The fields of this structure are as follows:
PxRigidActor* actor;
PxShape* shape;
PxVec3 position;
PxVec3 normal;
PxF32 distance;
PxHitFlags flags;
PxU32 faceIndex;
PxF32 u, v;
Some fields are optional, and the flags field indicates which members have been filled with result values. The query will fill fields in the output structure if the corresponding flags were set in the input - for example, if the PxHitFlag::ePOSITION is set in the input hitFlags, the query will fill in the PxRaycastHit::position field, and set the PxHitFlag::ePOSITION flag in PxRaycastHit::flags. If the input flag is not set for a specific member, the result structure may or may not contain valid data for that member. Omitting the eNORMAL and ePOSITION flags in the input can sometimes result in faster queries.
For a raycast which is not initially intersecting the geometry object, the fields are populated as follows (optional fields are listed together with the flag that controls them):
The position field is related to the barycentric coordinates via the following formula, where v0, v1 and v2 are the vertices from the hit triangle:
position = (1 - u - v)*v0 + u*v1 + v*v2;
See Geometry for details of how to retrieve face and vertex data from triangle meshes, convex meshes and height fields using face and vertex indices.
Exceptions to the above behavior may apply if a ray starts inside an object, in which case PhysX may not be able to compute meaningful output values for some fields. In these cases the field will remain unmodified and the corresponding flag will not be set. Specific details vary by geometry type, and are described below.
The exact conditions for raycast intersections are as follows:
For solid objects (sphere, capsule, box, convex) at most one result is returned. If the ray origin is inside a solid object:
If the start or end point of a ray is very close to the surface of the object, it may be treated as being on either side of the surface.
For raycasts, a plane is treated as a solid half-space that includes its boundary (note that this is not the same as for overlaps !!*HOW NOT THE SAME?*!! ). At most one result is returned, and if the ray origin is behind the plane's surface, no hit will be reported even in case the ray intersects the plane.
If the start or end point of a ray is very close to the plane, it may be treated as being on either side of the plane.
Triangle meshes are treated as thin triangle surfaces rather than solid objects. They may be configured to return either an arbitrary hit, the closest hit, or multiple hits.
In general "any hit" queries are faster than "closest hit" queries, and "closest hit" queries are faster than "multiple hits" queries.
By default, back face hits (where the triangle's outward-facing normal has a positive dot product with the ray direction) are culled, and so for any triangle hit the reported normal will have a negative dot product with the ray direction. This behavior may be modified by the mesh instance's PxMeshGeometryFlag::eDOUBLE_SIDED flag and the query's PxHitFlag::eMESH_BOTH_SIDES flag:
For example a transparent glass window could be modeled as a double-sided mesh, so that a ray would hit either side with the reported normal facing opposite to the ray direction. A raycast tracing the path of a bullet that may penetrate the front side of a mesh and emerge from the back could use eMESH_BOTH_SIDES to find both front and back facing triangles even when the mesh is single-sided.
The following diagram shows what happens with different flags, for a single raycast intersecting a mesh in several places.
To use PxHitFlag::eMESH_BOTH_SIDES for selected meshes rather than all, set the flag inside the PxQueryFilterCallback.
If the start or end point of a ray is very close to the surface of a triangle, it may be treated as being on either side of the triangle.
Overlap queries simply check whether two geometry objects overlap. One of the geometries must be a box, sphere, capsule or convex, and the other may be of any type.
The following code illustrates how to use an overlap query:
bool isOverlapping = overlap(geom0, pose0, geom1, pose1);
Overlaps do not support hit flags and return only a boolean result.
If more than a boolean result is needed for meshes and heightfields, use the PxMeshQuery API instead (see PxMeshQuery).
When two objects are intersecting, PhysX can compute the minimal distance and direction by which the objects must be translated to separate them (this quantity is sometimes referred to as MTD, for minimum translational distance, as it is the vector of minimal length by which translation will separate the shapes). One geometry object must be a box, sphere, capsule or convex mesh, and the other may be of any type.
The following code illustrates how to use a penetration depth query:
bool isPenetrating = PxGeometryQuery::computePenetration(direction, depth,
geom0, pose0,
geom1, pose1);
The arguments are interpreted as follows:
The function returns true if the objects are penetrating, in which case it sets the direction and depth fields. Translating the first object by the depenetration vector D = direction * depth will separate the two objects. If the function returns true, the returned depth will always be positive or zero. If objects do not overlap, the function returns false, and the values of the direction and distance fields are undefined.
For simple (convex) shapes, returned results are accurate.
For meshes and heightfields, an iterative algorithm is used and dedicated functions are exposed in PxExtensions:
PxVec3 direction = PxComputeMeshPenetration(maxIter,
geom, geomPose,
meshGeom, meshPose,
nb);
PxVec3 direction = PxComputeHeightFieldPenetration(maxIter,
geom, geomPose,
heightFieldGeom, heightFieldPose,
nb);
Here, maxIter is the maximum number of iterations for the algorithm, and nb is an output argument which will be set to the number of iterations performed. If no overlap is detected, nb is set to zero. The code will attempt at most maxIter iterations but may exit earlier if a depenetration vector is found. Usually maxIter = 4 gives good results.
These functions only compute an approximate depenetration vector, and work best when the amount of overlap between the geometry object and the mesh/heightfield is small. In particular, an intersection with a triangle will be ignored when the object's center is behind the triangle, and if this holds for all intersecting triangles then no overlap is detected, and the functions do not compute an MTD vector.
A sweep query traces one geometry object through space to find the impact point on a second geometry object, and reports information concerning the impact point if one is found. PhysX only supports sweep queries where the first geometry object (the one that is traced through space) is a sphere, box, capsule or convex geometry. The second geometry object may be of any type.
The following code illustrates how to use a sweep query:
PxSweepHit hitInfo;
PxHitFlags hitFlags = PxHitFlag::ePOSITION|PxHitFlag::eNORMAL|PxHitFlag::eDISTANCE;
PxReal inflation = 0.0f;
PxU32 hitCount = PxGeometryQuery::sweep(unitDir, maxDist,
geomToSweep, poseToSweep,
geomSweptAgainst, poseSweptAgainst,
hitInfo,
hitFlags,
inflation);
The arguments are interpreted as follows:
As with raycasts, fields will be filled in the output structure if the corresponding flags were set in the input hitFlags. The fields of PxSweepHit are as follows:
PxRigidActor* actor;
PxShape* shape;
PxVec3 position;
PxVec3 normal;
PxF32 distance;
PxHitFlags flags;
PxU32 faceIndex;
When the sweep hits a convex or triangle mesh, the returned triangle is chosen as follows:
In all cases, the hit point, position and normal reflect the choice of triangle.
Unlike raycasts, u,v coordinates are not supported for sweeps.
For the geometry object swept against:
Similarly to a raycast starting inside an object, a sweep may start with the two geometries initially intersecting. By default PhysX will detect and report the overlap. Use PxSweepHit::hadInitialOverlap() to see if the hit was generated by an initial overlap.
For triangle meshes and height fields, backface culling is performed before overlap checks, and thus no initial overlap is reported if a triangle is culled.
Depending on the value of PxHitFlag::eMTD, PhysX may also calculate the MTD. If PxHitFlag::eMTD is not set:
If PxHitFlag::eMTD is set, the hit results are defined as follows:
- For a convex mesh, it is the face of minimum penetration. If the MTD would separate the objects through an edge or vertex of the convex, the face chosen has a normal closest to the separation direction.
- For triangle meshes and heightfields it is the last penetrated triangle found during the last iteration of the depenetration algorithm.
- For other geometry types, the index is set to 0xffffffff.
This flag will incur additional processing overhead in the case of an initial overlap. In addition, the following restrictions apply:
Testing for initial overlaps sometimes uses a specialized code path and incurs a performance penalty. If is it possible to guarantee that geometry objects are not initially overlapping, the check for overlaps can be suppressed with PxHitFlag::eASSUME_NO_INITIAL_OVERLAP. There are some restrictions on the use of this flag (also, see Pitfalls)
Note
sweeps with PxHitFlag::eMTD use two kinds of backface culling for triangles. First, the triangles are culled based on sweep direction to determine whether there is an overlap. If an overlap is detected, they are further culled by whether the centroid is behind the triangle, and if no triangles are found, the direction will be set opposite to the sweep direction and the distance to 0.
Note
in most cases, translating the first geometry object by -normal*distance will separate the objects. However, an iterative depenetration algorithm is used to find the MTD for triangle meshes and height fields, and the MTD result may not provide complete depenetration from the mesh in some cases. In this case the query should be called a second time after the translation has been applied.
Note
a known issue in PhysX 3.3 is that the face index for a sweep against a convex mesh is undefined when the eMTD flag is not set.
PxHitFlag::ePRECISE_SWEEP enables more accurate sweep code (by default a potentially faster but less accurate solution is used). The ePRECISE_SWEEP flag is not compatible with the inflation parameter, or with the flag PxHitFlag::eMTD.
Height fields are treated as thin triangle surfaces rather than solid objects.
Thickness magnitude has no effect on initial overlap detection or point of impact.
For single-sided height fields the normal of the hit will face in +y local space direction if thickness is < 0 and -y when thickness is > 0.
Height fields are treated as double sided if either one of eDOUBLE_SIDED or eMESH_BOTH_SIDES flags are used.
- The returned hit normal will always face the sweep direction.
eMESH_ANY flag has no effect.
ePRECISE_SWEEP flag has no effect.
There are some pitfalls to be aware of when using sweeps:
The following function computes the distance between a point and a geometry object. Only box, sphere, capsule, and convex shapes are supported:
PxReal dist = PxGeometryQuery::pointDistance(point, geom, pose, closestPoint);
closestPoint is an optional output argument which returns the closest point.
The following function computes the axis-aligned bounding box (AABB) enclosing a geometry object, given its pose:
PxBounds3 bounds = PxGeometryQuery::getWorldBounds(geom, pose, inflation);
The bounding box is scaled by the inflation value, which defaults to 1.01f if not explicitly specified.
PhysX provides additional functionality for obtaining multiple results for triangle mesh and height field overlaps, and for sweeping against arrays of triangles. Only boxes, spheres and capsules may be tested against meshes or heightfields using these functions.
The following code illustrates how to process the mesh triangles touching a given spherical volume:
PxU32 triangleIndexBuffer[bufferSize];
PxU32 startIndex = 0;
bool bufferOverflowOccured = false;
PxU32 nbTriangles = PxMeshQuery::findOverlapTriangleMesh(sphereGeom, spherePose,
meshGeom, meshPose,
triangleIndexBuffer, bufferSize,
startIndex, bufferOverflowOccured);
for(PxU32 i=0; i < nbTriangles; i++)
{
PxTriangle tri;
PxU32 vertexIndices[3];
PxMeshQuery::getTriangle(meshGeom, meshPose, triangleIndexBuffer[i], tri, vertexIndices);
... // process triangle info
}
The findOverlapTriangleMesh method is used to extract the indices of the triangles:
Similar query functionality exists for height fields.
Sometimes, for example, when using the mesh overlap API, it is convenient to be able to sweep against groups of triangles. PhysX provides a function specifically for this purpose, with the following signature:
bool sweep(const PxVec3& unitDir,
const PxReal distance,
const PxGeometry& geom,
const PxTransform& pose,
PxU32 triangleCount,
const PxTriangle* triangles,
PxSweepHit& sweepHit,
PxHitFlags hitFlags = PxHitFlag::eDEFAULT,
const PxU32* cachedIndex = NULL,
const PxReal inflation = 0.0f,
bool doubleSided = false);
The arguments are interpreted as follows:
This function has extra limitations compared to the other sweep queries: