In this note, we focus on the new features we added to our Collision Detection module, and then show you with C++ code fragments how to use the new functions. As a reminder, this component is part of our C3D Modeler’s geometric kernel.
The primary task of a collision detector is searching for collisions between two faces of bodies. But our collision detector can also be used to carry out more tasks:
- Find the collisions between solid or polygonal bodies, and between groups of these bodies
- Measure the minimum distances between objects and so determine the sizes of gaps between bodies of assemblies
- Detect collisions in both static and dynamic scenes
As our collision detector has a very narrow focus – it only searches for collisions between bodies – then to make it even more useful, our developers greatly optimized its operations:
- Higher performance in statics, when working with hierarchical scenes, and during geometric searches for intersections and gaps between bodies
- Higher performance in dynamics, where collisions are searched for in real-time
- Greater memory optimization by compressing representations of scenes, and by having reusable inserts and body subassemblies.
The newest version of our collision detector searches for collisions of nested bodies and of “ray” type objects. By implementing ray support, we made it possible to solve several specific tasks at once.
New Detection Case: Nested Bodies
One difficult collision detection problem is where one body is located inside another, which normally is detected as the absence of a collision. Rays let us detect them.
To detect nested bodies, you should call the usual function that searches for the collisions of bodies:
// Search if a ray and a body intersect cdet_result MbCollisionDetectionUtility::CheckCollision( cdet_query & cdQuery );
When they are nested, the detector returns a new message type:
// Pair of nested bodies found cdet_query::message::CDET_INCLUDED
The following code fragments describe each step in working with the Collision Detection module to register body nesting:
Let's assume that two MbSolid solids were previously created in the scene:
MbSolid & solid1;
MbSolid & solid2;
We know their positions in space, which are given by the transition matrices from the global coordinate system (CS) to the local CS of these solids:
MbPlacement3D & placement1;
MbPlacement3D & placement2;
Let's also assume that a collision detector had been created earlier:
Add the bodies to the detector:
cdet.AddSolid( solid1, placement1 );
cdet.AddSolid( solid2, placement2 );
Then, run the collision search:
If the bodies intersect, for example if solid1 is inside solid2, then the function returns
CDET_RESULT_Intersected. To clarify whether solid1 is contained within solid2, you need to refine the detector’s search by calling a collision search with a custom query:
cdet.CheckCollisions( colQuery ); ,
...where colQuery is a custom collision search query.
When creating custom requests, you must specify the callback function. It is called by the detector every time a collision event is detected. It allows you to process data from this event on the user side, including the type of collision. The callback function has this signature:
cback_res (*cback_func)( cdet_query *, message, cback_data & ); ,
...where the message parameter is an enumeration specifying possible collision types, one of which is
The cback_data parameter is a type containing the first and second body of the collision event. If the type of collision is one body nesting in another, then the detector initializes a variable of type cback_data.
You can see that working with nested body events is no different from working with other types of events: it occurs through the callback function of the collision search request. This is all that’s needed to process the cdet_query::CDET_INCLUDED event type.
New Detection Cases: Rays
The second problem solved by our updated collision detection module is related to the passage of a ray through a solid body or a shell. It is worth noting that to the collision detector a ray is not an infinite straight line, but a geometric ray that has a starting point and a direction vector.
If we draw a plane perpendicular to it through the vertex of the ray, then the ray will lie in exactly one of the two half-spaces into which the plane has divided the space. Like a solid body, a ray has a position in space, which is given by its transition matrix.
We implemented a function in our API that adds a ray to the collision detector. The function detects the ray’s vertex, direction, and position in space:
// Add a ray to the Collision Detector cdet_item MbCollisionDetectionUtility::AddRay( const MbCartPoint3D & origin, const MbVector3D & direction, const MbPlacement3D & place, cdet_app_item appItem );
To register ray collisions, we employ the API function we used previously,
The code fragments below demonstrate how to work with the Collision Detection module when registering the passage of a ray.
Let's assume that, as in the previous example, a collision detector was created earlier:
It is necessary to register a ray using the function mentioned above,
When you run a collision search via cdet.CheckCollisions(...), the detector will detect the intersection of a ray and a solid body (if they intersect). If they intersect, the rays are added to the detector.
CDET_RESULT_Intersected result is returned by function cdet_result
MbCollisionDetectionUtility::CheckCollision(...), and the cback_data type variable in the callback function contains information about the corresponding pair of objects.
Future Plans for Collision Detection
We plan to implement a precision control in our collision detector so that you can specify under which conditions bodies can be considered non-colliding when they penetrate each other only slightly.