Unlike many other engines using third-party solutions, Unigine features its own built-in physics module.
The advantages of using a built-in module are as follows:
- Memory efficiency: a single instance of the world is used (in case if external solution is used we have to create and store another copy of our world)
- Performance: calls to external functions, excessive data conversion and transmission between integrated systems are avoided
It should be clear that it is not a high-precision simulation of real world physics! The simulation is just an approximation based on simplified calculations and decreased accuracy providing realistic look within the strict limits of real-time mode. Achieving this always involves a trade-off between accuracy and performance.
Though in general Unigine uses a simplified Newtonian physics with an impulse-based approach, the integration of collision detection, gravity, friction, buoyancy, joints and external physical forces provides realistic simulation of physical bodies and complex interactions between them.
Use Cases and Limitations of Built-in Physics
Unigine physics module is quite limited, however, in a number of cases it helps programmers and designers to make their work easier. Here is the list of the use cases when it is better to use built-in physics rather than hard-coding or bone-based animation:
- Collision detection (prevention of moving through walls, interpenetration of solid bodies, etc.)
- Simulation of perfectly elastic collisions (redistribution of kinetic energy)
- Simulation of various joints, motors and springs
- Simulation of basic physical phenomena: gravity, friction (static and sliding), buoyancy (for relatively calm water without big waves)
- Simulation of external forces (wind, force field)
- Procedural destruction of meshes
- Simulation of deformable cloth and ropes
- Rag doll simulation
It should be understood that the scope of simulation using built-in physics is limited to the cases listed above. Thus, there are a large number of cases that cannot be solved this way, including the following:
- High-precision physics simulation
- Flight dynamics simulation
- Fluid dynamics simulation
- Simulation of gravitational fields
- Simulation of inelastic collisions
- Digging of the ground
- Physical destruction of complex objects
Though some tasks involving a large number of objects can be solved using built-in physics, it may significantly reduce performance. In this case, as in the cases listed above, it is recommended to use alternative ways described in the next chapter.
Alternatives to Built-in Physics
When a problem cannot be solved by means of the built-in physics module or takes too much time, several other approaches can be used: bone-based animation, hard coding or using an external physics engine.
In some cases, when an object's behavior cannot be implemented by using physics simulation or requires too many calculations, the bone-based animation can be used instead.
Bone-based animation is a technique in which animated object is represented by two components:
- Surface representation used to draw the object (called skin or mesh)
- Hierarchical set of interconnected bones (called the skeleton or rig) used to animate (pose and keyframe) the mesh
This technique serves to make the animation process more convenient. Each bone of the rig is associated with some part of the object's mesh. Skinning is the process of creating this association. Changing bone transformations modifies the mesh.
There are two ways of using bone animation:
- Baked bone animation to use pre-baked keyframes stored in .anim file
- Procedural bone animation using ObjectMeshSkinned class to change bone transformations in real-time
Meshes and animation can be created using third-party graphics software (3ds Max, Maya, etc.) converted to Unigine native format (.mesh and .anim) by means of corresponding plugins and then used in the world.
- The first use case is when you need to have a complex mechanism with a large number of various joints working in the background of a factory workshop. Simulation of this mechanism using physics will significantly reduce performance. You can use a baked bone-based animation instead.
- The second use case is determined by the fact that bones cannot be affected physically. Imagine we have an antenna, which is represented by a single mesh containing a number of bones, attached to a vehicle. To make it move realistically we have to write a script (in Unigine script, C++ or C#) calculating necessary bone transformations and providing desired behavior of the antenna.
Another way to replace physics simulation achieving a realistic result without performance drops is code-based approach, which involves writing some code to programmatically change transformations of objects and their behavior.
- The first use case is when we want to simulate object deformation as a result of an inelastic collision. Built-in physics does not implement inelastic collision simulation. However, we can detect a collision and then change the deform object's mesh in the script (in Unigine script, C++ or C#) providing desired deformation.
Deformation (i.e. changing positions of mesh vertices) is available for dynamic meshes only!
- The second use case is when there are a large number of interacting elements, e.g. tank tracks and suspension. In case when we have many tanks, the calculation of physics will drop FPS down. Moreover, due to approximation errors the whole mechanism may blow up or look unnatural. We write a script, which calculates the movement of suspension and track plates, providing stability and desired degree of realism.
Using code-based tricks makes it possible to maintain acceptable FPS and to tweak the behavior of objects.
External Physics Engines
In cases when a precise physical simulation is required (e.g. flight dynamics, fluid dynamics etc.) it is recommended to use a specialized third-party solution that provides required functionality. Unigine does not currently offer a solution for third-party physics integration. Therefore, all necessary product-specific guidelines on how to integrate a certain third-party solution into your application are to be obtained from the party offering this solution.
Very often the best results can be achieved using a combination of different methods or techniques. So, the approaches described above can be successfully combined to provide convincing look and acceptable performance.
The use case illustrating successful combination of several approaches is associated with simulation of physical destruction of complex objects, e.g. collapsing bridges, exploding buildings, etc. Realistic simulation in this case is impossible in real time. However, it can be pre-computed using a third-party offline physics simulation software and then converted to a baked bone-based animation for use in a real-time application.
Physical Interaction of Objects. Basic Entities
While the majority of node types in the scene serves as auxiliary means or as decorations, the Object type can have physical properties and interact with other objects and the environment. For these properties to be assigned, the object should have a "body " (a physical approximation of the object), and the body should have at least one "shape " (a volume in space occupied by a body). To connect bodies and restrict their movement relative to each other the "joints " are used. The picture below illustrates relationships between these entities.
In order for an object to interact with other objects as well as external physical forces it must have a body. A body can be considered as a physical approximation of the object, it describes its behavior and represents a set of its dynamic parameters, such as mass, velocity, etc. There are several types of bodies: dummy, rigid, ragdoll, fracture, rope, cloth, water, and path. Each type of body is used for simulation of a specific type of object.
Mass parameters of the body can be set up manually or determined automatically using the shape-based parameters. It is convenient when a body has several shapes.
Body mass and density are used for buoyancy simulation in accordance with the Archimedes' principle.
While the body determines object’s behavior, the shape represents the volume of space occupied by a physical body. The shape is invisible and doesn’t have to be the same as the object’s mesh. Actually a rough approximation (sphere, capsule, cylinder, box or a convex hull) is often more efficient and indistinguishable. A physical body has one or several collision shapes allowing objects to collide with each other.
Objects with shapes also fall down under gravity, bounce off static surfaces or slide along them. Sliding and bouncing is determined by restitution and friction coefficients included in the list of shape parameters. A body without a single shape assigned behaves as a dummy body that can be connected to other bodies using joints, but does not collide and is immune to gravity.
In virtual worlds, like in a real world, we would like to have complex objects consisting of several interconnected parts (for example, a robotic arm or a car). That’s exactly what the joints are used for.
A joint connects two rigid bodies and represents certain constraints i.e. it restricts movement of connected bodies relative to each other. When the force applied to a joint is too strong, the joint breaks. The implementation of destructible joints includes the limits of linear and angular motion, so if the force exceeds these limits, the joint will be broken. There are several types of joints: fixed, hinge, ball, prismatic, cylindrical, suspension, wheel, and path.
When using joints it is very important to ensure mass balance – avoid connection of too heavy bodies to light ones, otherwise the system may become unstable. As it was mentioned before, physics simulation uses approximate calculations, therefore, if the difference of mass between two connected bodies is significant, accumulation of errors and precision issues lead to instability of the result.
Thus, when making a car model do not set the mass of the car body equal to 2000 kg and the wheels – to 10 kg, it might be better to use 5 kg for the body and 1 kg for each wheel to provide realistic behavior.
Collision and Intersection Detection
To restrict interpenetration of solid bodies, prevent moving through walls, and make things look more natural and familiar to the eye, the collision detection is used.
There are two types of collision detection implemented in Unigine:
- Discrete collision detection is performed in certain intervals of time and each frame is treated separately from others. In general, discretization improves performance. However, when a project framerate is already low, a small fast-moving object is likely to teleport from one point to another instead of moving there smoothly and collision will not be detected.
- Continuous collision detection does not suffer this problem as the moving body is extruded along its trajectory (between two adjacent frames). In cases when something gets into this volume and a collision is detected, the body is taken back in time to correct the collision reaction.
Collision detection is a very expensive operation, and since our scene may have hundreds of objects, a lot of effort is put into optimization.
- The first parameter contributing to the cost is collision shape complexity. As a rule, most 3d objects are represented by a complex and detailed visible mesh and an invisible simplified shape used by a physics engine for collision detection. Types of shapes available are listed above.
To reduce computational load it is strongly recommended to use simple collision shapes instead of complex ones when it is possible.
- The second parameter is a number of checks to be performed – the worst case would be all-against-all. To exclude unnecessary checks (e.g. two objects hardly collide if they are far from each other) the scene is to be split up into sections.
The process of collision detection is divided into two phases:
- Broad phase detection is a computationally low cost operation that quickly answers the question: Which objects have a strong possibility of colliding?
- Narrow phase is a computationally intense mesh on mesh collision detection, and thus cannot be performed on every pair of objects each frame. It answers the question: What part of object A collided with object B?
There is another important step which follows collision detection – collision response, or the result of collision (e.g. two balls bounce off of each other). Friction, restitution and other parameters are taken into account in calculation of collision response.
In case when some object's surfaces participate in collisions, and others don't, collision detection can be enabled on a per-surface basis. For example, a dashboard inside a cockpit, as it is covered by other surfaces.
Intersection detection lies at the heart of collision detection, but a particular case of ray intersection (ray casting) serves a little different purposes. Calculation of intersection between a ray cast from a certain point in a certain direction and a surface is fast and inexpensive and therefore sometimes can be used instead of computing collision. For example, calculation of collisions of car wheels with the ground takes time and decreases framerate. In this case we can use intersection of rays cast from the bottom of the car with the ground instead of precise collision detection using collision shapes, thus reducing computational costs and increasing performance.
To make collision and intersection detection flexible and selective, and to reduce calculation costs, the mechanism of bit masking is used. For example, we have an object, which does not participate in interactions with others, but we want it to lie on the ground. Matching the collision bit masks of this object and the ground (at least one bit in the masks should match) provides the necessary effect. One object can participate in several collision and intersection checks as only one bit in the mask is required to match for a pair of objects.
Simulation of Physics
Simulation of physics is performed in a looped sequence of the following stages on a per-frame basis:
There are two modes of physics simulation:
- Single-threaded, when all stages go one after another
- Multi-threaded, when some of the operations are performed in parallel
Physics is simulated with its own fixed FPS, which does not depend on rendering framerate, a variable FPS cannot be used here because it makes calculation results unstable.
Calculation of physics for all dynamic objects on the scene takes too much time. To ensure consistent frame rate and exclude unnecessary calculations some optimization approaches are used:
- When a body is moving slower than a specified minimum linear or angular velocity for a specified period (freeze frames), it is assumed that it has come to a halt. During this period of inactivity, there is actually no need to simulate it. If this happens, the object remains in a resting state until it is affected by another object or a force. Therefore, such object is excluded from all steps of the simulation except collision detection. This state is called freezing and it allows to save a great deal of computational resources.
Frozen blue and unfrozen red boxes. The impulse applied to the pyramid of boxes unfroze all but one.
- If interacting objects are far away from the viewer they do not make a noticeable contribution to the whole image and thus can be neglected. Simulation distance setting specifies the distance from the viewer when physical interactions are no longer calculated.