The Viro Developer Hub

Welcome to the Viro developer hub. You'll find comprehensive guides and sample code to help you start working with Viro as quickly as possible, as well as support if you get stuck. Let's jump right in!

Get Started

Viro contains a simple but powerful Physics engine. This engine enables developers to build interactive experiences that simulate real world forces. This development guide will go through the basics of creating physics objects and offer an overview of the experiences that can be created with them.

In Viro, almost every 3D control can be physics-enabled through the PhysicsBody object. For example, to make a Box fall due to gravity, simply initialize its parent Node's PhysicsBody with a mass and type, as shown below.

Box box = new Box(1, 1, 1);

Node boxNode = new Node();
boxNode.setGeometry(box);
boxNode.initPhysicsBody(PhysicsBody.RigidBodyType.DYNAMIC, 1, new PhysicsShapeBox(1, 1, 1));                    

Each PhyicsBody must have a RigidBodyType that dictates the behavior of the physics body. Physics bodies must also be given a PhysicsShape to represent the collision mesh of the body.

Physics Body Type

There are three types of physics bodies available in Viro: Dynamic, Kinematic, and Static. Each has unique movement and interaction behavior. Note also there is a mass requirement associated with each type.

Property
Static RigidBody
Kinematic RigidBody
Dynamic RigidBody

Mass (in kg)

  • Must have 0 mass.
  • Must have 0 Mass.
  • Positive Mass (cannot be negative).

Movement Behavior

  • Cannot move.
  • Can be moved under explicit developer/user control.
  • Designed to be moved under simulation (you should not be directly manipulating / animating this object's position).
  • Can be moved by colliding against other objects, and in response to forces and impulse.

Collision Behavior

  • Can collide only with dynamic bodies.
  • Least resource intensive. - Works well with static objects like floor, ground, etc.
  • Can collide with dynamic bodies.
  • Does not collide with other other kinematic bodies or static bodies.
  • Cannot be influenced by dynamic bodies.
  • Behaves like a movable object with infinite mass during collisions (will always push objects away).
  • Works well with objects you wish to directly move with animations with fine movement detail.
  • Can collide with any body type.
  • Works well with objects that do not have applied animations, and that are reactive to forces applied in the world.

Physics Shape

After specifying a type, Viro will need to determine the actual shape of the physics object representing the control's geometry. This can be specified through the PhysicsShape. There are three kinds of shapes that the physics body accepts: PhysicsShapeBox, PhysicsShapeSphere, and PhysicsShapeAutoCompound, as shown below.

Shape
Parameters

PhysicsShapeBox

Accepts width, height, and length. Will be centered around the origin of the Node.

PhysicsShapeSphere

Accepts a radius parameter. Creates a sphere that will be centered around the origin of the Node.

PhysicsShapeAutoCompound

No parameters. Viro automatically iterates through the Node's subtree and infers the physics shape.

Note you can toggle the setDebugDraw flag on the PhysicsWorld to draw all meshes representing physics shapes. This is demonstrated in the image above, and is primarily used for debugging purposes (it comes at a significant performance cost).

It is important to note that physics objects cannot be recursively stacked. That is, a Node that is physics-enabled cannot have children that also have their own physics-enabled bodies. There is no hierarchy to physics bodies. Compound shapes, however -- where multiple geometric objects are compounded together to form a single physics body -- are supported in Viro.

Physics Body Forces

Various kinds of forces can be applied to physics-enabled Nodes. Viro automatically manages the reconciling of these forces on a Node's transform when they are applied.

Constant Forces

Constant forces can be useful in situations for moving objects in constant motion; for example, when adding thrust to a spaceship being launched into the sky. To apply a constant directional force, invoke applyForce(Vector magnitude, Vector location) on the PhysicsBody. For each force, you can specify both its magnitude (in newtons) and its location (on the object).

Rotational forces are also supported. To apply a constant rotational force, use the applyTorque(Vector torque) method.

Impulsive Forces and Motion

Impulse forces are useful in situations where you would like to apply an instantaneous burst of force to an object. These are often useful for launching projectile objects. Rotational impulses are supported as well. The relevant methods are applyImpulse(Vector impulse, Vector location) and applyTorqueImpulse(Vector torque).

Velocity

Developers have access to finer control over object movement via the `velocity``` property on PhysicsBody. Setting this property will override any forces that are already applied to the object.

Forces and Drag Behavior

With Viro, the default behavior of drag events works with physics-enabled Nodes; users are still able to drag objects around the scene. Viro handles this by temporarily converting any dragged physics bodies into kinematic types during the drag, then switching back to the original types upon completion of the drag. This can be used to give users the ability to fling objects toward other dynamic-typed physics bodies. An example of this is shown below.

Drag and drop physics bodies.

Drag and drop physics bodies.

Physics Body Properties

PhysicsBodies have additional properties that the developer can tune to achieve different kinds of behavior. Two of these are friction and restitution.

Restitution controls how "bouncy" an object or surface is. When two objects collide, some of the energy of the collision is used to deform the collided objects, some is used rebound the objects from one another, and some is lost to heat. Restitution is a measure of how much of that kinetic energy is used for objects to rebound from one another. To take a real-world example, a massive bowling bowl has a low coefficient of restitution -- it doesn't really bounce on the floor -- whereas a basketball has a high coefficient of restitution.

Note the restitution factor is applied on both the objects involved in the collision. In the image below, that means both the floor and each colliding ball. Restitution of 1.0 implies a perfectly elastic collision: kinetic energy is conserved and the ball will bounce right back up to its initial height. A value of 0.0 represents a completely inelastic collision: the ball will stick to the floor after colliding and have zero velocity.

Friction is used to calculate the force of resistance an object encounters when moving across another. A value of 0.0 implies no friction, whereas a value of 1.0 implies high friction. When two physics bodies are in contact, their respective friction values are used to create a friction coefficient, which is in turn used to compute the applied frictional force for the two colliding objects. In other words, the friction values of both objects are considered. For example, a metal sword has a different coefficient of friction when rubbing against cloth than against wood.

Physics World

While most physics parameters are set through the individual PhysicsBody properties of each object, there are some global physics properties that can be modified. These are accessed from the PhysicsWorld object, which is retrieved directly from the Scene. PhysicsWorld has the following properties:

gravity globally accelerates physics bodies in a specific direction. To make objects float without falling, set gravity to 0.0. The default is -9.8 m/s in the negative Y direction, to simulate gravity on Earth.

debugDraw will render lines representing the physics shapes for all physics objects in the scene. This is a useful tool for debugging physics bodies. It provides developers visual feedback on where the physics objects are, and how they interact with one another.

Collision Events

Colliding Objects

Developers can register CollisionListeners to receive collision events that occur for a given PhysicsBody. As shown below, upon collision the collided point and normal are both returned in world coordinates. The tag of the collided object is also returned, which can be used provide information to the callback about what the PhysicsBody has collided against.

Node node = new Node();
PhysicsBody physicsBody = boxNode.initPhysicsBody(PhysicsBody.RigidBodyType.DYNAMIC, 1, new PhysicsShapeBox(1, 1, 1)); 

physicsBody.setCollisionListener(new PhysicsBody.CollisionListener() {
    public void onCollided(String collidedTag, Vector position, Vector normal) {
	      // Respond to the collision
    }
});

Physics Ray Hit Test

In addition to registering for collision callbacks, developers can actively query the scene for collisions with ray intersection tests. This can be done in two ways:

1) findCollisionsWithRayAsync(from, to, closest, viroTag)
This shoots a single ray into scene starting at from and ending at to. The viroTag enables developers to identify this collisionRay event within the collisionCallback of all in-scene physics bodies. If only the nearest result is desired, set the closest flag to true. This function returns true if any objects have been hit.

2) findCollisionsWithShapeAsync(from, to, shapeString, shapeParam, viroTag)
This method fires a physics shape into the scene and determines what physics objects collide with the shape. The shapeString is either "box" or "sphere", and shapeParam are shape parameters as described above for boxes and spheres. If from != to, this method only invokes the callback of the closest object that has been hit. Otherwise, if from == to (if this isn't a collision test along a path), then the collision callback is triggered on all collided objects.

You can view those methods in greater detail here.

Physics


Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.