Smooth Trajectories for Mobile VR in Unity
Visualize physical performance in a comprehensive manner.
Introduction
In this post, I would like to elaborate on a simple method to create persistent trajectories in a Unity 3D environment. When working on a Virtual Reality project for mobile devices in Unity, there is sometimes the need to draw the trajectory of a specific object (any GameObject, actually) that has been launched and subsequently landed at a specific distance from its launch point. That trajectory consists of a “live” part (Trail), which is visible during the object’s flight, as well as a static part which becomes visible immediately after the completion of the object’s landing, roll and stop. That arrangement can be particularly useful for applications related to sciences (e.g. physics, astronomy, chemistry, etc.) or gaming. For instance, Virtual Reality apps that involve competitive sports such as golf or soccer, need to clearly display ball trajectories. So let’s see how that could be implemented in a manner that offers simplicity and flexibility to the developer.
Launch
As a starting point, it recommend taking a quick look at the following implementation (https://github.com/mkoutroumpas/Trajectories). It is a sample Unity project that consists of a very basic Scene with a flat terrain and a sphere with specific dimensions and weight. That Sphere is the “projectile”; the very GameObject that will be launched by applying a specific Force upon it.
The C# script that controls the launch of any object that it has been attached to, thus making it “launch-able”, is LaunchableObject.cs. Just add it as a Script component to the Sphere, and that is all; any movement of the Sphere will now cause trajectory calculations to take place. We can even assign a default launch Force to the LaunchableObject Script component, thus completing the basic project setup. Of course, a launch Force can alternatively be set through code. A core part of the LaunchableObject class is shown below; it involves ongoing calculation of the Sphere’s speed and position.
The ongoing output of the trajectory calculations is available on every execution of the Update() method, through the LaunchableObject’s public properties named StartPosition, CarryPosition and TotalPosition. That can be very useful in displaying live trajectory data during debugging or even during the actual gameplay. A good example of this is golf, where there is the need to display live distance information for the apex, the carry and the total of a performed shot.
Trajectory Drawing
As demonstrated in the following image, in order to actually display the trajectory we need to add two empty GameObjects as children to our Sphere object; the first will contain a TrailRenderer (used to display “live” trails) and the second a LineRenderer (used to visually recreate the static trajectory path).
The technique to create the static trajectory itself, is also simple: position measurements are taken at specific time intervals during the Sphere’s flight and the resulting List of Points is directly passed to the LineRenderer in order to draw a continuous line. As an alternative option to the basic setup, we could supply an array of launch Forces to the Sphere instead of only one single Force, by passing a List of Vector3 objects to the MultipleLaunch method (see code below).
Due to the multiple consecutive launches of the Sphere, the output will appear as a continuous animation of “a Sphere that hops around”. The final trajectory that will be displayed will cover the Sphere’s complete path, consisting of multiple consecutive trajectories from the initial point of launch to the final point of landing and stop, as displayed below.
Results
The following short video shows the final result deployed on a Nokia 5 smartphone running Android 9.0, with Virtual Reality support and the Google Cardboard SDK installed and enabled.
As we can see, the trajectory is drawn in a smooth manner without flickering or risk of motion sickness, and the user gets a very clear idea of the Sphere’s path at all times. I do not recommend increasing the default width of the LineRenderer, because path drawing could become visually confusing to the user for very short flight distances.