Parallel Computing II
This is the second page of the Parallel Computing tutorial series, where we reimplement the "Ray Tracing in One Weekend" code in the Java language. We transform the sequential code to parallel code following the TornadoVM programming model for execution on GPUs using TornadoVM.
Go to the first start of the tutorial
Let us continue.
An Abstraction for Hittable Objects
The "Ray Tracing in One Weekend" tutorial defines some helper classes to structure the code better. Let us implement the HitRecord class and Hittable interface in Java.
Java
Create the HitRecord class
You must have noticed that we use Lombok extensively in our code. So far, we haven't seen any clashes with TornadoVM. But if we see clashes in the future, we'll need to revert to standard Java. As for now, we'll go with the saying, "If it is working, don't change it."
Note: although we use Lombok, we've intentionally defined the instance variables as public variables. This allows us to access instance variables without using the getters. Although this goes against every standard in Java, by doing so, our Java code will look very similar to the reference C++ code in the "Ray Tracing in One Weekend" tutorial.
The code for Hittable interface is next.
Java
Every object that reacts to a Ray will extend and implement this interface.
In the C++ code of the "Ray Tracing in One Weekend" tutorial, the hit() function returns a bool value and other computed values through one of the function call output parameters.
We need to redesign our code slightly since Java only supports pass-by-value in method calls. That is why we added the boolean variable hitDetected to the HitRecord class, and in our Java code, the hit() method returns a HitRecord. We'll need to observe the ripple effects of this design change in our future code.
The Sphere Class
Now let us implement the Sphere class
Java
Given a Ray, the Sphere will decide whether the Ray hits the Sphere or not. If the Sphere registers a hit, then it will save hit information in the HitRecord.
A List of Hittable Objects
We have a generic object called a Hittable that the ray can intersect with. We now add a class that stores a list of Hittables
Java
The HittableList.hit() will go through all the objects, calling their hit() methods. It will save the color information of the nearest object.
We added a utility function getObjectCount() for later use when we write parallel code.
Let us create a world variable in our AppManager.
Java
Now let us create a few spheres and initialize the HittableList object in the main() method.
Java
Render the World
Sequential Code
Writing the ImageCPU.render7_World() method should be straighstraight forward.
Java
Recall that we decided to write our actual rendering code inside the Camera class.
Add the two methods to the Camera class. Namely Camera.getRay() and Camera.render7_World().
Java
The getRay() method is a convenience that we will use frequently in the future.
The actual rendering work will be done in the rayColor() method. Add the Camera.rayColor() method as shown next.
Java
Recall that the variable world is of type HittableList. The world.hit() method will loop through all the objects, call their respective hit() methods, and collect hit information. In the loop, the world.hit() method will keep track of the closest object and return that information to Camera.rayColor().
The Interval Class
Since we are following the "Ray Tracing in One Weekend" tutorial, let us implement the Interval class as in the tutorial.
Java
We need to make several changes/additions to our source code in order to use the Interval class.
Add a new method hit() that uses the Interval class
Implement this new method in all classes that implement the Hittable interface. This includes the HittableList and Sphere classes.
Java
1) Modifications of the Hittable class
Java
2.a) Modifications of the Sphere class
Override the hit(Ray, Interval) method in the Sphere class with the following implementation.
Java
2.b) Modifications of the HittableList class
Override the hit(Ray, Interval) method in the HittableList class with the following implementation.
Now, let us modify our Camera class to use this Interval class. Following our practice of preserving old code, we will write a new method in the Camera class that utilizes the Interval class.
First, we will write a method to compute the color of a pixel by giving it a Ray and the world.
Java
Now, for each pixel, we can compute the Ray and then call rayColorUsingInterval() to compute the color of the pixel. So, we implement the render8_Interval(int, int) in the Camera class.