Tutorial - Utility Functions
Many factors are involved when adopting a third party library into a project as opposed to implementing an in-house one. The developer should make a thorough evaluation of the pros and cons of taking that step because, in the case of serious projects, a wrong choice could translate into lost time, budgets overrun, mediocre turnout of features do to mediocre technology, etc. In many cases depending on the scope of the project this could turn into lost of millions of dollars.
A physics library is certainly not exempt from this process. Among the things the person evaluating the technology should take into consideration are:
- The application will delegate a lot of its own functionality to a black box API and in some case functionality will be duplicated if the third party API does not support a particular feature or does not have and interface for it.
- The API should be evaluated with a fine comb. The developer should test the existing functionality and make their decision base on that, she or he should not move forward counting on the promise of further features with new releases. New Features should be welcome but they should not be mandatory for the completion of the project at hand.
- What extra functionality can be extracted from the new API, given the fact that a great part of the project will be trusted to this black box piece of software? It is possible that the API can do everything it needs to do physically, but it does not provide the ability to be extended resulting in functionality duplication and hacked integrations.
- The API should have good technical support from the creator. This factor should be considered but it should not be the deciding one. The creator of the API should be considered as a last resource for resolving some technical problems not as the main source of information.
The Newton technical development team has realized that this extra functionality is very important when it comes to choose a physics engine, and also realized these features are very helpful to the developer. In this tutorial we will expose some of these extra features:
Ray casting is by far the most important and practical of these features. As we mention before it has nothing to do with the physics part of the engine, but it uses the internal data structures of the engine to provide the application with an efficient and general purpose ray casting interface. The applications of ray casting in a project are enormous. Among them we can mention: Object picking, object placement, Line of sight for target shooting, assist in various AI algorithms, and many more.
In the tutorial we will demonstrate two uses for ray casting: Object placement and Object picking.
Open the file tutorial7_UtilityFuntionality\totorial7.cpp find the function InitScene
The very first few lines of this function create a big flat box to serve as the floor for this tutorial. Then after the floor creation the line
// position the camera relative to the floor cameraEyepoint.m_y = FindFloor (cameraEyepoint.m_x, cameraEyepoint.m_z) + 10.0f;
position the camera eye point 10 meters above the floor.
Find the function FindFloor on the same file. This is the first and one of the simplest uses of the ray cast function. The goal it to shoot a vertical ray from some point up in the space to some point below and return the elevation of the closest static body in the scene.
For that we will shoot a ray for a point 1000 meters up and 1000 meters down, call the ray cast and collect the parametric intersection of the ray with the closet static body in the scene.
The ray cast function does not implement any predefined filtering technique based on bits field or objects list or anything like that. Instead it lets the application decide how rigid bodies will be filtered when the engine is scanning the scene along the ray from begin to end. The application does that by writing a special call back function that will be called each time the engine encounters a rigid body on its way.
In this case that function is RayCastPlacement. It is extremely simple, each time it is called it checks if the rigid body is static, if it is then checks if the parametric intersection is smaller than the previous one, and if it is, then saves the intersection parameter and returns that parameter to let Newton know that it should not check bodies beyond that point.
Upon return the floor is the interpolated value between the upper and lower points. After this the function InitScene continues to populate the scene with some objects. For this tutorial we will place two building structures by calling two similar functions.
CreateBuildingStruture_1 (); CreateBuildingStruture_2 ();
Both functions are very similar so we well describe the first one.
Find the function CreateBuildingStruture_1 on the same file;
In this function we will place a parking lot type of structure in the scene. For that it is very important the initial position of the components touch each other starting from the ground and continuing building up. Once again we need to know the exact elevation of the floor to start building the structure.
Then the function set two different mass values 1kg and 200kg (the reason for the high mass ratios will be explained later) and what follows is a loop building a 10 story high structure by placing 4 lightweight support columns and a heavy platform of top in each iteration.
The second application for ray casting is object picking. First we need to define what objects picking is and how it is done.
Object picking is the act of pointing to a body on the screen and finding out what rigid body was rendered at that pixel position. This is done by knowing the fact that a pixel on the near clipping plane and a pixel on the far clipping plane with the same screen coordinate maps to a straight line on three the dimensional space. To do this we take the point at the mouse position, and set the near clipping coordinate z to zero. Then we invert transform this point by the view port matrix, the projection matrix, and the view matrix of the graphic API. We do the same for the second point except now we set z value to 1 for the far clipping plane.
Once we do that we have the two points defining the line on three d space. We should mention now that this is not an internal part of the physics engine it is just an explanation of how to obtain the point from the screen space and convert it to a line in tree d space. Must graphics engines provide this functionality as a built in feature. Next we collect all of the rigid bodies intersected by the ray going from the origin to the end of the line.
Next we store two values, the parametric intersection and the position of the point relative to the hit rigid body.
Next, as long as the mouse button is depressed we want to apply a force to the body at the hit point, that will tend to drive to zero the distance from that point in the body space and the same point on the line at the new mouse position. For that we use a penalty force.
To do all this we need to modify the mouse routine function which is found in the keyboard function. The big if-else statement is the part implementing the mouse position collection and doing the data manipulation. The important part is the implementation of the RayCastFilter callback function. This function is similar to the find floor except that it collects the closest dynamic body and also the pointer to the rigid body.
The object pick effect is done by implementing a new apply force and torque PhysicsApplyPickForce function callback which is set to the hit body when it is picked and reset back to the standard apply gravity when the body is let loose.
The Newton engine was designed with an event driven user interface. However there are situation in which an application needs to iterate through all the object is the scene collecting information about each object for many different purposes. These situations are rare but inevitable nevertheless. Examples of these cases are setting global state for all objects in the scene at the hit of a button, or displaying debug information for objects in global manner, and other application dependent uses.
The Newton engine comes with two kind or Iterators, one for rigid bodies and the second is almost exclusive for debugging the collision geometry in the scene. The second iterator comes handy when the behavior of some objects is the scene is odd, or when making complex collision objects. The first one can be used for a variety of purposes.
In this tutorial we use the Body Set globally the state of auto sleeping for each body, and also to display the collision geometry of each body on the scene.
- It is important to emphasize that iterators are helper functions designed to assist the application in debugging and balancing the physics scene. These functions are by not mean efficient and the application should not rely on them for runtime functionality as they will severally degrade the performance of the engine.
Find The function Keyboard(), and you will see that two new interface keys had been added. F1 and F2
The Key F1 will toggle a global auto sleep flag and call the Iterator function NewtonWorldForEachBodyDo passing the pointer to the function callback ToggleAutoSleep
The function ToggleAutoSleep will be called for each body in the scene changing the state of the body from sleeping to awake, or vise versa depending on the global auto sleep flag, the function also forces the body to wake up state.
The second key F2 toggles a global debug flag to indicate the main render loop if it has to render the debug geometry of each collision geometry in the scene. If you look at the end of the function DrawScene, the if statement will call the DebugShowCollision
The function Debug collision implements two nested loops, one the outer one iterates through each body on the scene passing the callback DebugShowBodyCollision And the DebugShowBodyCollision iterate through each collision geometry in the scene by calling DebugShowGeometryCollision. It should be pointed out that these functions are not meant to be efficient and they will render all the bodies on the scene, therefore they can degrade performance significantly on large scene. The application should implement more efficient versions of these functions by adding some kind of filtering.
Active Bodies Tracking
The third facture we are going to used is the Activation Deactivation Notification callback.