Java 3D Coordinate System and Creating Faceted Shapes Using TriangleArray

Java 3D uses the usual coordinate system where the 'x' coordinate grows to the right, 'y' grows upwards and 'z' grows in the direction of the virtual world's viewer for its default position.


The default view graph is taken care of by the SimpleUniverse class, if the programmer doesn't want to bother himself with specifying the position and orientation.

As with JavaFX (see previous post), creating a shape in Java 3D is not only inherently complicated given the many vertices usually involved and the order that defines the direction of each face, but the API is not very intuitive nor well documented. That's the reason behind this post, which I hope will provide some clarification.

Let's explore how it all works with a small program that demonstrates a few different concepts.

Here I present the structure of the program and a few snippets. The full example is linked at the bottom of this article.

1. Create four small spheres. One at the origin point (0, 0, 0) and others at a fixed distance along the positive part of every axis. Color each sphere differently. This will demonstrate Java3D's coordinate system.
 float sphereRadius = 0.05f;  
   
 Vector3f translation = new Vector3f(0, 0, 0);  
 TransformGroup tgzero = createTransformGroupWithColorSphere(sphereRadius, translation, new Color3f(Color.yellow));  
 group.addChild(tgzero);  
   
 translation = new Vector3f(1, 0, 0);  
 TransformGroup tgx = createTransformGroupWithColorSphere(sphereRadius, translation, new Color3f(Color.red));  
 group.addChild(tgx);  
   
 translation = new Vector3f(0, 1, 0);  
 TransformGroup tgy = createTransformGroupWithColorSphere(sphereRadius, translation, new Color3f(Color.green));  
 group.addChild(tgy);  
   
 translation = new Vector3f(0, 0, 1);  
 TransformGroup tgz = createTransformGroupWithColorSphere(sphereRadius, translation, new Color3f(Color.magenta));  
 group.addChild(tgz);  


2. Create a surface using a point along 'y', which we will call 'top'. Another point along 'z' which we will call 'front' and a third at the origin point of coordinates 0, 0, 0.

With this surface we will demonstrate face culling and how the order of indices determines the direction of the face.
 Point3f zero = new Point3f(0, 0, 0);  
 Point3f front = new Point3f(0, 0, 1);  
 Point3f top = new Point3f(0, 1, 0);  
   
 TriangleArray surface = new TriangleArray(3, GeometryArray.COORDINATES);  
   
 surface.setCoordinate(0, zero);  
 surface.setCoordinate(1, top);  
 surface.setCoordinate(2, front);  


3. Define two transforms for the universe's view platform. Each transform is composed of another two, the first of which is a simple translation along the 'z' axis to gain some distance from the objects and a small one along 'y' to gain some perspective.

The second is a rotation along the 'y' axis. What this accomplishes is being able to see the surface previously created from one side or another. This new viewpoint also allows us to see the four spheres created earlier.

Here is an example of one of these transforms. Notice that the rotation is 7% of a full rotation around 'y'. Just enough to gain perspective.

 Transform3D viewTransform = new Transform3D();  
 viewTransform.setTranslation(new Vector3f(0f, 1f, 4f));  
 Transform3D rotationTransform = new Transform3D();  
 rotationTransform.rotY((Math.PI * 2) * 0.07);  
 rotationTransform.mul(viewTransform);  
   
 universe.getViewingPlatform().getViewPlatformTransform().setTransform(rotationTransform);  
   

4. Added lights so that the objects will be visible from the two viewpoints created earlier. I will not include the snippet here since it's irrelevant to the topic.

5. Play around with culling, order of vertices and viewpoint.

Go to the code linked at the bottom of the page. I define three class variables for each of the previous things. Change the values, execute the program and observe what is displayed.

Here is a diagram of the whole setup:

Observations:

1. A surface is visible from the side in which the vertices were added in counter-clockwise order.

2. The back side of a surface is culled by default. If we don't cull it we can see both sides, which look the same, as one would expect. 

If you remember from the JavaFX article, this does not happen with the JavaFX culling. When no face is culled in JavaFX, it looks unsightly. In general JavaFX meshes are simply very ugly unless carefully crafted. So much so that that alone is a valid reason to avoid using them in favor of a different Java 3D library.

Full example:

You won't find this is particularly good code, but it does the job.
https://gist.github.com/anonymous/90b7e08a6abbdb69b6b24ec8d1a78648

https://gist.github.com/anonymous/1b8341990c7106d5e6d2b99b0ecbef4d

Comments