The collision plugin allows an RpWorldSector or RpGeometry to be extended with a 'collision tree'. This works much like the 'BSP' tree that defines the large-scale sectorization of an RpWorld, but continues the sectorization down to the level of a few triangles per leaf node. The collision tree does not store any triangle data directly, but references the original triangle array in the world sector or geometry.
The additional collision data greatly improves the efficiency of finding triangle intersections, and various functions are provided to do this. Other functions provide coarse-grain intersection tests with whole world sectors or atomics via their bounding spheres.
For best triangle intersection performance, it is advisable to use low-resolution collision models separate from those to be rendered. However, if collision with the graphics data is desired then the object should not be preinstanced as this process removes the platform independent vertex/triangle data (see RpWorldInstance).
Managing collision data
Collision data for a world sector or geometry can be built using RpCollisionWorldBuildData, and RpCollisionGeometryBuildData (this might commonly be done when exporting a model from an art package). The existence of the data can be tested using RpCollisionWorldQueryData etc, and it may be destroyed using RpCollisionWorldDestroyData etc. Collision data, if it exists, is streamed automatically with a world sector or geometry as plugin extension data.
Low-level Sector Iterator API
This API provides methods for iterating over a world sector tree at the large scale or collision tree at the small scale to find the leaf sectors that intersect a line or box. For a collision tree, the leaf nodes simply reference triangles in an external array, and these may be processed in a variety of ways by the application. For example, this might involve doing precise triangle intersection tests using the functions in the intersection toolkit (RtIntersection Toolkit Overview).
The collision tree of a world sector or geometry may be obtained using RpCollisionWorldSectorGetCollTree or RpCollisionGeometryGetCollTree.
Intersection Test API
This API is built on the low-level sector iterators and provides all-in-one functions that return, via a callback, each intersection found between a given primitive (RpIntersection) and target:
|
|
RpCollisionBuildSortCallBack represents a function that may be called during the generation of collision data for an RpWorldSector or RpGeometry when the rpCOLLISIONBUILD_SORTTRIANGLES option is used. This option means that the triangles of the world sector or geometry are automatically sorted, and this call back is only required in cases where additional triangle data must be processed such as an RpUserDataArray. The call back may be setup in the RpCollisionBuildParam.
|
|
|
RpIntersectionCallBackAtomic represents the function called from RpWorldForAllAtomicIntersections for all intersections between the specified primitive and collision atomics in a given world. This function should return the current atomic to indicate success. The callback may return NULL to terminate further callbacks on the world.
|
|
|
RpIntersectionCallBackGeometryTriangle represents the function called from RpAtomicForAllIntersections and RpCollisionGeometryForAllIntersections for all intersections between the specified primitive and a given atomic. This function should return a pointer to the current collision triangle to indicate success. The callback may return NULL to terminate further callbacks on the atomic. Note that the vertices and normal of the collision triangle are given in the coordinate space of the geometry. If they are required in world coordinates, they must be transformed using RwV3dTransformPoints and RwV3dTransformVectors with the LTM of the atomic's frame. This must be passed via the user-defined data if required.
|
|
|
RpIntersectionCallBackWorldSector represents the function called from RpWorldForAllWorldSectorIntersections for all intersections between the specified primitive and world sectors in a given world. This function should return the current world sector to indicate success. The callback may return NULL to terminate further callbacks on the world.
|
|
|
RpIntersectionCallBackWorldTriangle represents the function called from RpCollisionWorldForAllIntersections for all intersections between the specified primitive and the static geometry in a given world. This function should return a pointer to the current collision triangle to indicate success. The callback may return NULL to terminate further callbacks on the world.
|
|
|
RpCollBBoxClipFlags are used to indicate the faces of an RwBBox that clip a leaf sector of a collision tree (RpCollTree). The shape of the leaf sector is also an axis aligned bounding box. If the flags are zero, then the sector is entirely inside the clip box.
|
|
|
These flags are used in an RpCollisionBuildParam structure to control the generation of collision data for an RpGeometry or RpWorldSector.
|
|
|
RpIntersectType, this type represents the different types of primitives that can be used to intersect with an object (for example, see RpCollisionWorldForAllIntersections): |
|
||||||||||||||||||||
|
RpAtomicForAllIntersections returns, via a callback function, all triangles in an atomic that intersect a given primitive. The callback may return NULL to terminate intersection testing.
If the geometry has multiple morph targets, then the triangles are interpolated according to the current RpInterpolator value before being tested for intersection. Note that a bounding sphere test is not done before testing the triangles of the atomic, as this usually takes place as part of a first pass collision stage, e.g. as in RpWorldForAllAtomicIntersections.
|
|
|
RpCollisionBuildParamInitDefaults initializes an RpCollisionBuildParam structure with the default values.
|
|
||||||||||||
|
RpCollisionGeometryBuildData builds collision extension data for a geometry.
This function is intended for offline use. The collision data is streamed with the geometry as plugin extension data.
|
|
|
RpCollisionGeometryDestroyData is called to destroy collision data for a geometry. The collision and world plug-ins must be attached before using this function. The header file rpcollis.h is required.
|
|
||||||||||||||||||||
|
RpCollisionGeometryForAllIntersections returns, via a callback function, all triangles in a geometry that intersect a given primitive. The callback may return NULL to terminate intersection testing.
If the geometry has multiple morph targets, only the first is tested for intersections. To test for intersections with a morphed atomic, use RpAtomicForAllIntersections. For line queries, the triangles are returned in approximate order of distance along the line. It should not be assumed that the first triangle returned is the nearest. A more flexible way to construct intersection tests similar to this function is to query a geometry's collision tree with the iterator API before doing precise triangle tests. (see RpCollisionGeometryGetCollTree, RpCollSectorLineIt, RpCollSectorBBoxIt, RtIntersection Toolkit Overview). In particular, the iterator API provides a method to efficiently determine the first intersection along a line.
|
|
|
RpCollisionGeometryGetCollTree retrieves the collision tree attached to a geometry.
|
|
|
RpCollisionGeometryQueryData is called to query if collision data exists for the given geometry. The collision and world plug-ins must be attached before using this function. The header file rpcollis.h is required.
|
|
|
RpCollisionPluginAttach is called by the application to indicate that the collision plugin should be used. The call to this function should be placed between RwEngineInit and RwEngineOpen and the world plugin must already be attached. The library rpcollis and the header file rpcollis.h are required.
|
|
||||||||||||
|
RpCollisionWorldBuildData is a convenience function which calls RpCollisionWorldSectorBuildData for all world sectors in a world.
|
|
|
RpCollisionWorldDestroyData is called to destroy the attached collision data for the given world. The collision and world plug-ins must be attached before using this function. The header file rpcollis.h is required.
|
|
||||||||||||||||||||
|
RpCollisionWorldForAllIntersections returns, via a callback function, all triangles in the static geometry of a world that intersect a given primitive. The call back function may return NULL to terminate intersection testing.
A more flexible way to construct intersection tests similar to this function is to use the iterator API to query the world's BSP tree, then each resulting world sector's collision tree before doing precise triangle tests. (see RpSectorLineIt, RpSectorBBoxIt, RpCollisionWorldSectorGetCollTree, RpCollSectorLineIt, RpCollSectorBBoxIt, RtIntersection Toolkit Overview). In particular, the iterator API provides a method to efficiently determine the first intersection along a line.
|
|
|
RpCollisionWorldQueryData is called to query for collision data for the given world. The result is TRUE if any world sectors contains collision data. FALSE if no world sectors contains collision data. The collision and world plug-ins must be attached before using this function. The header file rpcollis.h is required.
|
|
||||||||||||
|
RpCollisionWorldSectorBuildData builds collision extension data for a world sector.
The function RpCollisionWorldBuildData may alternatively be used to generate collision data for all world sectors of an RpWorld. The build functions are intended for offline use in exporters and tools.
|
|
|
RpCollisionWorldSectorDestroyData is called to destroy collision data for a world sector. The collision and world plug-ins must be attached before using this function. The header file rpcollis.h is required.
|
|
|
RpCollisionWorldSectorGetCollTree retrieves the collision tree attached to a world sector.
|
|
|
RpCollisionWorldSectorQueryData is called to query if collision data exists for the given world sector. The collision and world plug-ins must be attached before using this function. The header file rpcollis.h is required.
|
|
||||||||||||||||||||
|
RpCollSectorBBoxItFindNextEntries advances a collision sector bounding box iterator to the next leaf sector intersected, and returns a reference to the entries contained in that sector ('entries' currently mean the triangles of a world sector or geometry).
|
|
|
RpCollSectorBBoxItFinished queries whether a collision sector bounding box iteration process has finished.
|
|
||||||||||||||||||||
|
RpCollSectorBBoxItInit initializes a collision sector bounding box iterator for traversing an RpCollTree to find each sector that intersects a given bounding box.
outerBBox is used for actually determining the RpCollSector intersections. The innerBBox is an optimization feature. The iterator keeps track of RpCollBBoxClipFlags as it traverses the tree, so that they indicate whether the current sector is clipped by the innerBBox. If the flags are zero then the sector must be completely inside. The RpCollSectorBBoxItFindNextEntries function returns the clip flags relevant to each set of entries it finds.
The following code shows an example of usage. This finds all triangles in a world sector that lie inside a given bounding box (
const RpTriangle *tris = RpWorldSectorGetTriangles(worldSector); const RwV3d *verts = RpWorldSectorGetVertices(worldSector); RpCollTree *tree = RpCollisionWorldSectorGetCollTree(worldSector); RwUInt16 *map = RpCollTreeGetEntryMap(tree); RpCollSectorBBoxIt iterator; RpCollSectorBBoxItInit(&iterator, tree, bbox, bbox); while (!RpCollSectorBBoxItFinished(&iterator)) { RwUInt16 i, start, count; RwUInt32 clipFlags; RpCollSectorBBoxItFindNextEntries(&it, &start, &count, &clipFlags); for (i=start; i<(start+count); i++) { RwUInt16 triIndex = map[i]; const RpTriangle *tri = tris + triIndex; const RwV3d *v0 = verts + tri->vertIndex[0]; const RwV3d *v1 = verts + tri->vertIndex[1]; const RwV3d *v2 = verts + tri->vertIndex[2]; if ((clipFlags == 0) || RtIntersectionBBoxTriangle(&bbox, v0, v1, v2)) { ... process triangle ... } } }
|
|
||||||||||||||||
|
RpCollSectorLineItFindNextEntries advances a collision sector line iterator to the next leaf sector intersected, and returns a reference to the entries contained in that sector ('entries' currently mean the triangles of a world sector or geometry).
The entries themselves will lie close to the line but will not necessarily intersect it. Further tests are necessary to determine this.
|
|
|
RpCollSectorLineItFinished queries whether a collision sector line iteration process has finished.
|
|
||||||||||||||||||||
|
RpCollSectorLineItInit initializes an RpCollSectorLineIt iterator object for traversing an RpCollTree to find each leaf sector that intersects the given line.
The iteration process proceeds from the start of the line to the end, but due to the overlapping nature of the sectors, the ordering in terms of distance is loosely defined. This complicates the process of finding the nearest intersection, but the iterator modifier function RpCollSectorLineItSetFarClip is used below to achieve this as efficiently as possible. The example also assumes that the triangles are not sorted into the collision tree order so the entry map is used.
const RpTriangle *tris = RpWorldSectorGetTriangles(worldSector); const RwV3d *verts = RpWorldSectorGetVertices(worldSector); RpCollTree *tree = RpCollisionWorldSectorGetCollTree(worldSector); RwUInt16 *map = RpCollTreeGetEntryMap(tree); RwV3d lineDelta; RpCollSectorLineIt iterator; RwReal minDist = RwRealMAXVAL; RpTriangle *closestTri = NULL; RwV3dSub(&lineDelta, &line->end, &line->start); RpCollSectorLineItInit(&iterator, tree, line, NULL); while (!RpCollSectorLineItFinished(&iterator)) { RwUInt16 i, start, count; RpCollSectorLineItFindNextEntries(&iterator, &start, &count); for (i=start; i<(start+count); i++) { RwUInt16 triIndex = map[i]; const RpTriangle *tri = tris + triIndex; const RwV3d *v0 = verts + tri->vertIndex[0]; const RwV3d *v1 = verts + tri->vertIndex[1]; const RwV3d *v2 = verts + tri->vertIndex[2]; RwReal dist; if (RtIntersectionLineTriangle( &line->start, &lineDelta, v0, v1, v2, &dist) && (dist < minDist)) { minDist = dist; closestTri = tri; RpCollSectorLineItSetFarClip(&iterator, dist); } } }
|
|
||||||||||||||||
|
RpCollSectorLineItInitFromSectorIt initializes an RpCollSectorLineIt iterator object based on the current state of an enclosing RpSectorLineIt iteration loop.
RpSectorLineIt sectIt; RpCollSectorLineIt collSectIt; RpSectorLineItInit(§It, world, line, NULL); while (!RpSectorLineItFinished(§It)) { RpWorldSector *worldSector; RpCollTree *collTree; worldSector = RpSectorLineItFindNextWorldSector(§It); collTree = RpCollisionWorldSectorGetCollTree(worldSector); RpCollSectorLineItInitFromSectorIt(&collSectIt, collTree, §It); while (!RpCollSectorLineItFinished(&collSectIt)) { RwUInt16 start, count; RpCollSectorLineItFindNextEntries(&collSectIt, &start, &count); ... process triangles ... } }
|
|
||||||||||||
|
RpCollSectorLineItSetFarClip modifies a collision sector line iterator to eliminate, from the iteration process, all sectors beyond a given distance.
|
|
|
RpCollTreeGetEntryMap retrieves the mapping table of entries (ie triangles of a world sector or geometry) in a collision tree.
|
|
|
RpSectorBBoxItFindNextWorldSector advances a world sector bounding box iterator, returning the next RpWorldSector that intersects the bounding box.
|
|
|
RpSectorBBoxItFinished queries whether a world sector bounding box iteration process has finished.
|
|
||||||||||||||||
|
RpSectorBBoxItInit initializes an RpSectorBBoxIt iterator object for traversing the RpSector tree of an RpWorld to find each RpWorldSector (a leaf node of the tree) that intersects the given bounding box.
RpSectorBBoxIt it; RpSectorBBoxItInit(&it, world, bbox); while (!RpSectorBBoxItFinished(&it)) { RpWorldSector *worldSector; worldSector = RpSectorBBoxItFindNextWorldSector(&it); ... code to process world sector ... }
|
|
|
RpSectorLineItFindNextWorldSector advances a world sector line iterator, returning the next RpWorldSector that intersects the line.
|
|
|
RpSectorLineItFinished queries whether a world sector line iteration process has finished.
|
|
||||||||||||||||||||
|
RpSectorLineItInit initializes an RpSectorLineIt iterator object for traversing the RpSector tree of an RpWorld to find each RpWorldSector (a leaf node of the tree) that intersects the given line.
RpSectorLineIt it; RpSectorLineItInit(&it, world, line, NULL); while (!RpSectorLineItFinished(&it)) { RpWorldSector *worldSector; worldSector = RpSectorLineItFindNextWorldSector(&it); ... code to process world sector ... } The iteration process proceeds from the start of the line to the end, but due to the overlapping nature of the sectors, the ordering in terms of distance is loosely defined. This complicates the process of finding the nearest intersection along a line, but the function RpSectorLineItSetFarClip can be used to achieve this as efficiently as possible. The padding values fatten the line in positive and negative directions on each axis, so that it represents an axis aligned box swept along the line vector. An equivalent interpretation of this is that the nodes of the BSP tree (axis aligned boxes) are fattened by this amount, and not the line. This could be used in parallel projection shadow calculations, by using the center of an occluder object as the start of the line, setting the padding to bound the object, and setting the line end point at some position away in the lighting direction. A small amount of padding will be used internally even if NULL is specified for the padding parameter to allow for floating point inaccuracies.
|
|
||||||||||||
|
RpSectorLineItSetFarClip modifies an RpSector line iterator to eliminate, from the iteration process, all sectors beyond a given distance.
See RpCollSectorLineItInit for a code example that demonstrates the use of the related function RpCollSectorLineItSetFarClip.
|
|
||||||||||||||||||||
|
RpWorldForAllAtomicIntersections returns, via a callback function, all collision atomics in a world whose bounding spheres intersect a given primitive. The callback may return NULL to terminate intersection tests.
For a more precise intersection test with the triangles of an atomic's geometry, use RpAtomicForAllIntersections or RpCollisionGeometryForAllIntersections.
|
|
||||||||||||||||||||
|
RpWorldForAllWorldSectorIntersections returns, via a callback function, all world sectors in a world that intersect a given primitive. The callback may return NULL to terminate intersection testing.
An alternative to this function is to use the lower-level RpSector iterator API (RpSectorLineIt, RpSectorBBoxIt) to find world sectors that intersect a line or bounding box.
|
© 1993-2004 Criterion Software Limited. All rights reserved. Built Thu Feb 12 13:47:01 2004.
Send Feedback