Summary: Learn how to update the game-math library to support 3D math, how to program the equations for projecting a 3D world onto a 2D plane, and how to add vectors in 3D. Also learn about scaling, translation, and rotation of a point in both 2D and 3D, about the rotation equations and how to implement them in both 2D and 3D, and much more.
This module is one in a collection of modules designed for teaching GAME2302 Mathematical Applications for Game Development at Austin Community College in Austin, TX.
What you have learned
In a previous module, I presented and explained four programs that used the game-math library named GM2D04 . One of those programs taught you how to use the addVectorToPoint method of the GM2D04.Point class to translate a geometric object from one location in space to a different location in space.
Another program taught you how to do the same thing but in a possibly more efficient manner.
The third program taught you how to do rudimentary animation using the game-math library.
The fourth program taught you how to use methods of the game-math library to produce relatively complex drawings.
All of the programs were interactive in that they provide a GUI that allows the user to modify certain aspects of the behavior of the program.
What you will learn
The most important thing that you will learn in this module is how to update the game-math library to support 3D math and how to produce 3D images similar to that shown in Image 1 .
| Image 1: A 3D image produced using the game-math library. |
|---|
![]() |
And a whole lot more...
You will learn much more than that however. Some highlights of the things you will learn are:
I recommend that you open another copy of this module in a separate browser window and use the following links to easily find and view the Images and Listings while you are reading about them.
In case you are wondering where we are heading as we go down this path, I recommend that you skip ahead to the modules titled Our First 3D Game Program and A First-Person Shooter Game . Copy, compile and run the 3D game programs named GM01Test08 and Cannonball01 along with the required game-math libraries.
While the graphics and the story lines for those two game programs are rudimentary, the mathematics involved are significant. (After all, this is a course in game math and not a course in game design or high-quality graphics.)
I will present and explain a significantly updated game-math library in this module.
I will also present and explain six different sample programs that show how to use the new features in the updated library.
By studying the library and the sample programs, you will learn
I will also provide exercises for you to complete on your own at the end of the module. The exercises will concentrate on the material that you have learned in this and previous modules.
In this section, I will present and explain a significantly updated version of the game-math library named GM01 .
In addition, I will present and explain the following programs that use the update game-math library.
A complete listing of the updated game-math library named GM01 is provided in Listing 26 near the end of the module.
A major update to add 3D capability
This is a major update to the game-math library. This version updates the earlier version named GM2D04 to a new version named simply GM01 . The primary purpose of the update was to add 3D capability for all of the 2D features provided by the previous version. Because both 2D and 3D capabilities are now included in the library, it is no longer necessary to differentiate between the two in the name of the class. Therefore, this version is simply named GM01 .
3D to 2D projections
Adding 3D capability was tedious, but not particularly difficult in most areas of the library. However, adding 3D capability entailed major complexity in one particular area: drawing the objects. It is difficult to draw a 3D object on a 2D screen and have the drawing appear to be 3D. This requires a projection process to project each point in the 3D object onto the correct location on a 2D screen. There are a variety of ways to do this. This 3D library uses an approach often referred to as an oblique parallel projection . You can Google that name to learn more about the technical details of the process.
Eliminating the y-axis confusion
In addition to adding 3D capability, this version of the game library also eliminates the confusion surrounding the fact that the default direction of the positive y-axis is down the screen instead of up the screen as viewers have become accustomed to. If you funnel all of your drawing tasks through the library and don't draw directly on the screen, you can program under the assumption that the positive direction of the y-axis is up.
The name of the library
The name GM01 is an abbreviation for GameMath01 . See the file named GM2D01 from an earlier module for a general description of the game-math library. The library has been updated several times. This version updates the file named GM2D04 .
Improving efficiency
In addition to the updates mentioned above, this update cleaned up some lingering areas of code inefficiency by using the simplest available method to draw on an off-screen image.
New static methods
Also, the following new static methods were added to the class named GM01 . The first method in the following list deals with the problem of displaying a 3D image on a 2D screen. The last five methods in the list wrap around the standard graphics methods for the purpose of eliminating the issue of the direction of the positive Y-axis.
It will probably be necessary for me to add more wrapper methods to the library in future modules. With the exception of the first method in the above list, the coding of these methods was straightforward and explanations of that code are not warranted. Note, however, that it is the wrapper methods that resolve the issue regarding the direction of the positive y-axis. You will see comments in this regard if you examine the source code for the wrapper methods in Listing 27 . I will explain the code for the method named GM01.convert3Dto2D shortly.
Other new methods
In addition to the new static methods listed above, a number of new methods were added to the existing static top-level 2D classes and also included in the new static top-level 3D classes. A list of those new methods follows:
With the exception of the two rotate methods, the coding of the methods in the above list was also straightforward and an explanation of that code is not warranted. You can view all of the new code in Listing 26 .
The two rotate methods are not straightforward at all. They are quite complicated (particularly the 3D method) and require quite a lot of background information to understand. I will dedicate a large portion of a future module to the task of rotating geometric objects in 2D and 3D worlds and will defer an explanation of the two rotate methods until that module.
The static method named GM01convert3Dto2D
Note first that this is a static method of the class named GM01 . Among other things, this means that the method can be called simply by joining the name of the method to the name of the class. In other words, an object of the class named GM01 is not necessary to make the method accessible.
A complete listing of the method is provided in Listing 1 .
| Listing 1: The static method named convert3Dto2D. |
|---|
|
As you can see, the method is quite short, and once you know how it is required to behave , coding the method is not difficult. The complexity comes in understanding the required behavior.
All of the static top-level 2D classes in the existing game-math library were renamed with a suffix of 2D to distinguish them from the new top-level 3D classes. All of the new top-level 3D class names have a 3D suffix.
The ColMatrix2D and ColMatrix3D classes
From the very beginning, the game-math library has contained a static top-level class named ColMatrix . In the updated version of the library, that class has been renamed ColMatrix2D .
Basically, the ColMatrix2D class provides a container for a pair of values of type double with appropriate methods for accessing those values. (I explained the original ColMatrix class in detail in an earlier module.) Similarly, the new ColMatrix3D class provides a container for three values of type double with appropriate methods for accessing those values.
Objects of the ColMatrix2D class are the fundamental building blocks for several of the other 2D classes in the library, and objects of the ColMatrix3D class are the fundamental building blocks for several of the other 3D classes in the library.
Behavior of the GM01.convert3Dto2D method
The convert3Dto2D method converts a ColMatrix3D object that represents a point in 3D space into a ColMatrix2D object that represents the projection of that 3D point onto a 2D plane .
The purpose of the method is to accept x, y, and z coordinate values describing a point in 3D space and to transform those values into a pair of coordinate values suitable for being displayed in two dimensions. The math that is implemented by this method to do the projection is described on a web page that seems to move around a bit but the last time I checked, it was located at http://paulbourke.net/geometry/transformationprojection/ If you don't find it there, try http://paulbourke.net/geometry/ In any event, a Google search should expose numerous pages that explain the math for projections of this type.
The transform equations
I won't attempt to justify or to explain the transform equations that are used to accomplish the projection in this module. Rather, I will simply use them as presented in the above resource. In the meantime, if you are interested in more information on the topic, you will find a wealth of information on 3D to 2D projections by performing a Google search for the topic.
The transform equations along with some of the assumptions that I made in the use of the equations are shown in Listing 2 .
| Listing 2: Transform equations for an oblique parallel projection from 3D to 2D. |
|---|
|
The terms in the equations
In Listing 2 , the terms x2d and y2d refer to drawing coordinates on the 2D screen, while x3d , y3d , and z3d refer to the coordinates of a point in 3D space. Obviously, sin , cos , and tan refer to the sine, cosine, and tangent of angles named alpha and theta .
Output in two dimensions
These equations and the assumptions that I made in using them produce displays such as the one shown in Image 1 . In that image, the red horizontal line is the x-axis with the positive direction to the right. The green vertical line is the y-axis with the positive direction pointing up. The blue sloping line is the z-axis with the positive direction protruding from the screen towards and to the left of the viewer. The three axes intersect at the origin in 3D space.
(The sloping magenta line going from the corner of the box to the origin is a 3D vector. I will have more to say about the projections of 3D vectors later.)
No perspective in this projection
The sloping black lines in Image 1 represent the edges of a rectangular box projected onto the 2D screen. Note in particular that there is no perspective in this type of projection. In other words, lines that are parallel in the 3D space remain parallel in the projection of those lines onto the 2D screen. (Hence the word parallel in the name oblique parallel projection.) Objects don't appear to be smaller simply because they are further away from the viewer.
(The application of perspective would add another layer of complexity to the game math library. I will leave that as an exercise for the student to accomplish.)
Options involving the angles
I could have produced a somewhat different display by assuming different values for the angles named alpha and theta . However, the values chosen are commonly used values that produce reasonably good results, so I decided to use them. You may find it interesting to experiment with other values for one or both angles to see the results produced by those other values.
The proper algebraic signs
Note in particular that the proper signs for the equations in Listing 2 depend on the assumed positive directions of the angles as well as the assumed positive directions of the axes. The signs used in the method make the assumptions shown in Listing 2 . (These assumptions will be particularly important in future modules where we will be rotating objects in 3D space.)
The viewing position
Also as indicated in Listing 2 and shown in Image 1 , the viewing position is above the x-axis and to the right of the z-y plane.
Typically, a game math library would provide the capability to modify the viewing position. That capability is not supported directly by this library. However, that capability can be approximated by the rotation capability discussed later. (Another exercise for the student to accomplish.)
The code in the method is straightforward
As I mentioned earlier, once you understand the requirements, the code for the method named convert3Dto2D (see Listing 1 ) is relatively straightforward. If you have studied the code in the previous modules in this series, the code in Listing 1 shouldn't require further explanation.
Because I made some changes to the existing 2D classes in the game-math library and added some new methods to some of the existing 2D classes, I felt the need to write a program that would step through and test the behavior of most of the 2D methods in the library. That was the purpose of the program named GM01test02 .
This program produces both a graphic screen output and lots of text on the command-line screen. The graphic output is shown in Image 2 .
| Image 2: Graphics output from the program named GM01test02. |
|---|
![]() |
Command-line output from the program named GM01test02
The command-line output is shown in Image 3 .
| Image 3: Command-line output from the program named GM01test02. | |
|---|---|
|
Not too exciting
Neither the graphics output in Image 2 nor the command-line output in Image 3 are terribly exciting, and neither will mean much to you unless you are willing to examine the code and compare the output with the code.
Source code for the program named GM01test02
A complete listing of the program named GM01test02 is shown in Listing 27 near the end of the module.
Listing 3 shows two of the statements in the constructor for the GUI class in the program named GM01test02 . The call to the method named testUsingText produces the command-line output shown in Image 3 , while the call to the method named drawOffScreen produces the graphic output shown in Image 2 .
| Listing 3: Code in the constructor for the GUI class in the program named GM01test02. |
|---|
|
If you examine the source code for those two methods in Listing 27 , you will see that each of the methods contains calls to library methods for the purpose of confirming that the library methods behave as expected. The code in most of those methods is straightforward and should not require further explanation beyond the embedded comments in Listing 27 .
End of the discussion for the program named GM01test02
That concludes the discussion of the program named GM01test02 . You will find a complete listing of this program in Listing 27 .
Code in the program named GM01test01 makes calls to library methods, which in turn make calls to the method named convert3Dto2D shown in Listing 1 . Because of the complexity of projecting 3D points onto a 2D screen for display, it will be useful to discuss the three library methods that make calls to the library method named convert3Dto2D . Those three methods are shown in the following list :
Recall that a point simply represents a location in space and has no width, height, or depth. Therefore a point is not visible to the human eye. However, it is sometimes useful to draw a small circle around a point to mark its location for human consumption. That is the purpose of the draw method of the GM01.Point3D class, which is shown in its entirety in Listing 4 .
| Listing 4: The method named GM01.Point3D.draw. |
|---|
|
Purpose of the method
This method draws a small circle around the location of a point in 3D space. The 3D location of the circle is projected onto the 2D plane of the specified graphics context for display later on a 2D screen. The code in Listing 4 projects that location in 3D space onto the 2D plane by calling the static method named convert3Dto2D .
Behavior of the GM01.Point3D.draw method
The location of a point in 3D space, as represented by an object of the GM01.Point3D class, is actually stored in an object of the GM01.ColMatrix3D class. A reference to that ColMatrix3D object is stored in the instance variable named point belonging to the Point3D object. This reference is passed as a parameter to the convert3Dto2D method in Listing 4 .
Recall from Listing 1 that the convert3Dto2D method receives an incoming reference to an object of the class GM01.ColMatrix3D and returns a reference to an object of the class GM01.ColMatrix2D , which contains the horizontal and vertical components of the projection of the 3D point onto a 2D plane.
Using the returned GM01.ColMatrix2D object
Listing 4 uses the horizontal and vertical components stored in the returned ColMatrix2D object to construct the proper parameters and call the wrapper method named GM01.drawOval . This wrapper method doesn't know that it is receiving parameters that were originally derived from an object in 3D space. The world of the wrapper method is confined to 2D space. The wrapper method named GM01.drawOval performs the following actions:
The small circle is not converted to an ellipse
Note that even though the location of the point in 3D space is projected onto the 2D plane, the shape of the small circle is not converted to an ellipse to reflect the 3D to 2D conversion nature of the operation. Thus, if the circle were large, it wouldn't necessarily look right. However, in this case, the only purpose of the circle is to mark the location of a point in 3D space. Therefore, I didn't consider the actual shape of the marker to be too important. Image 1 shows examples of circles marking points in 3D space at the corners of the box and at the ends of the axes.
The behavior described above for the method named GM01.Point3D.draw is somewhat indicative of the manner in which 3D geometric objects are projected onto a 2D plane and the manner in which the issue regarding the positive direction of the y-axis is resolved by the code in the updated game-math library.
The behavior of the three draw methods
Each of the three draw methods listed earlier needs the ability to project a Point3D object, a Vector3D object, or a Line3D object onto a 2D pane. In each case, the object to be drawn is built up using one or more ColMatrix3D objects as fundamental building blocks.
For the case of the GM01.Point3D.draw method discussed above, the draw method calls the convert3Dto2D method directly to convert the 3D coordinate values of the point to the 2D coordinate values required for the display.
A similar approach for the GM01.Vector3D.draw method
A similar approach is used for the GM01.Vector3D.draw method, which is shown in Listing 5 .
| Listing 5: The method named GM01.Vector3D.draw. |
|---|
|
This method draws the 2D visual manifestation of a GM01.Vector3D object on the specified 2D graphics context. Recall that a vector has no location property. Therefore, it can be correctly drawn anywhere. The GM01.Vector3D.draw method requires the drawing location of the tail to be specified by a reference to a GM01.Point3D object received as an incoming parameter.
A small filled circle is drawn at the head of the vector as shown by the magenta filled circle at the origin in Image 1 . (Note that the other circles in Image 1 are not filled.)
Two calls to the convert3Dto2D method
Two calls are made to the convert3Dto2D method in Listing 5 . The first call gets a 2D projection of the 3D location of the tail of the vector. The second call gets a 2D projection of the 3D location of the head of the vector. In both cases, the projected location in 2D space is returned as a reference to an object of the GM01.ColMatrix2D class.
Draw the vector on the specified drawing context
The reference returned by the first call to the convert3Dto2D method is used to call the static GM01.drawLine wrapper method to
The reference returned by the second call to the convert3Dto2D method is used to call the static GM01.fillOval wrapper method to
The GM01.Line3D.draw method is shown in Listing 6 .
| Listing 6: The GM01.Line3D.draw method. |
|---|
|
The code in Listing 6 is so similar to the code in Listing 5 that no further explanation should be required.
Now back to the program named GM01test01
A complete listing of the program named GM01test01 is provided in Listing 28 near the end of the module.
Because all of the 3D classes in the game-math library are new to this update, I felt the need to write a program that would step through and test the behavior of most of the 3D methods in the library. That was the purpose of the program named GM01test01 .
Like the program named GM01test02 discussed earlier, this program produces both a graphic screen output and lots of text on the command-line screen. The graphic output is shown in Image 1 . I won't waste space printing the command-line output in this tutorial. If you want to see it, you can copy, compile, and run the program from Listing 28 and produce that output yourself.
The graphic output
The graphic output shown in Image 1 is produced by the method named drawOffScreen , which begins in Listing 7 . I will briefly walk you through this method because everything in it is new. However, much of the code is very similar to 2D code that I have explained before.
| Listing 7: Beginning of the drawOffScreen method in GM01test01. |
|---|
|
After translating the origin to the center of the off-screen image, Listing 7 instantiates eight GM01Point3D objects that define the corners of the 3D box shown in Image 1 . References to the eight objects are stored in the elements of an array object referred to by the variable named points . Although this code uses three coordinate values instead of two coordinate values to instantiate the objects, the syntax should be very familiar to you by now.
Project eight points onto the 2D plane and draw them
Listing 8 calls the GM01.Point3D.draw method eight times in succession to cause the locations of the eight points in 3D space to be projected onto the 2D off-screen image and to draw the points as small circles on that image. This is the first draw method from the earlier list that I explained above.
| Listing 8: Project eight points onto the 2D plane and draw them. |
|---|
|
Seven of the points are drawn in BLACK and one is drawn in RED. The eight small circles appear at the corners of the box in Image 1 .
As indicated in the comments, the RED point is drawn at the right top front corner of the box to help you get the orientation of the box correct in your mind's eye.
Draw twelve lines that connect the corners of the box
Listing 9 calls the GM01.Line3D.draw method twelve times in succession to project the lines that connect the corners of the 3D box onto the 2D off-screen image and to draw those lines on that image. This is the second draw method from the earlier list that I explained above.
| Listing 9: Draw twelve lines that connect the corners of the box. |
|---|
|
Instantiate and draw a GM01.Vector3D object onto the 2D off-screen image
Listing 10 instantiates an object of the GM01.Vector3D class and calls the draw method of that class to draw the magenta vector shown in Image 1 .
| Listing 10: Instantiate and draw a GM01.Vector3D object onto the 2D off-screen image. |
|---|
|
This is the third and final draw method from the earlier list that I explained above. The vector was drawn with its tail at the upper left corner of the box. The length and direction of the vector were such as to cause the head of the vector to be at the origin in 3D space.
Draw the 3D axes
The red, green, and blue 3D axes shown in Image 1 were produced by the call to the setCoordinateFrame method early in Listing 7 . The setCoordinateFrame method is shown in Listing 11 .
| Listing 11: The setCoordinateFrame method. |
|---|
|
This method is used to set the origin of the off-screen image. It also projects orthogonal 3D axes onto the 2D off-screen image and draws the projected axes on that image. The axes intersect at the origin in 3D space.
The lengths of the axes are set so as to match the interior dimensions of the box shown in Image 1 and points are drawn where the axes intersect the surfaces of the box. That was done to enhance the optical illusion of a 3D object on a 2D plane.
There is nothing in Listing 11 that you haven's seen before, so further explanation should not be required.
End of discussion
That concludes the discussion of the program named GM01test01 . You can view the code that was not discussed here in Listing 28 near the end of the module.
In an earlier module, you learned how to add two or more vectors in 2D. This program will show you how to use the updated game-math library to add vectors in 3D. You also learned about the 2D parallelogram rule and the 2D head-to-tail rule in the earlier module. This program will illustrate that those rules also apply to the addition of 3D vectors.
Image 4 shows the graphic output produced by this program.
| Image 4: Graphic output from the program named GM01test05. |
|---|
![]() |
This output shows the addition of a magenta vector to a light gray vector to produce a black vector as the sum of the other two vectors. As you can see, both the parallelogram rule and the head-to-tail rule are illustrated by the graphic output in Image 4 .
Very familiar code
Most of the code in this program will be very familiar to you by now. The new code is mostly contained in the method named drawOffScreen , which is shown in Listing 12 . A complete listing of this program is provided in Listing 29 near the end of the module.
| Listing 12: The drawOffScreen method of the program named GM01test05. |
|---|
|
At this point, you should not find any code in Listing 12 that you don't understand. I have explained the code in Listing 12 earlier in this module or in an earlier module, so I won't repeat that explanation here.
End of discussion .
That concludes the discussion of the program named GM01test05 . You will find a complete listing of this program in Listing 29 .
Scaling, translation, and rotation of a point
Three of the most common and important operations that you will encounter in game programming will be to scale, translate, and/or rotate a geometric object.
Since all geometric objects are composed of points that define the vertices, possibly embellished with lines, shading, lighting, etc., if you know how to scale, translate, and/or rotate a point, you also know how to scale, translate, and/or rotate the entire geometric object. You simply apply the required operation to all of the points that comprise the object and you will have applied the operation to the object as a whole.
However, there are some complex issues associated with hiding the back faces of a rotated object, which will be addressed in a future module under the general topic of backface culling . Backface culling is a process by which you prevent 3D objects from appearing to be transparent.
In a future module, we will learn about a mathematical trick commonly known as homogeneous coordinates that can simplify the scaling, translation, and rotation of a point. However, that will have to wait until we have a better grasp of matrix arithmetic.
In a previous module, you learned how to translate a geometric object. In this program, you will learn how to scale a geometric object. In the next two programs, you will learn how to rotate geometric objects.
The new scaling methods
The additions to the game-math library included the following two methods:
As the names imply, these two methods can be used to scale a point in either 2D or 3D.
The game-math library method named GM01.Point3D.scale
This method is shown in Listing 13 .
| Listing 13: The game-math library method named GM01.Point3D.scale. |
|---|
|
This method multiplies each coordinate value of the Point3D object on which the method is called by the corresponding values in an incoming ColMatrix3D object to produce and return a new Point3D object. This makes it possible to scale each coordinate value that defines the location in space by a different scale factor.
If a scale factor for a particular coordinate is less than 1.0 but greater than 0.0, the location of the new point will be closer to the origin along that axis than was the location of the original point. If a scale factor is greater than 1.0, the new point will be further from the origin along that axis. If the scale factor is negative, the location of the new point will be on the other side of the origin along the same axis.
Graphic output from the program named GM01test06
The graphic output from the program named GM01test06 is shown in Image 5 . Compare this with the graphic output from the program named GM01test01 shown in Image 1 .
| Image 5: Graphic output from the program named GM01test06. |
|---|
![]() |
Modifications to the original program
The program named GM01test06 , shown in Listing 30 , modifies the earlier program named GM01test01 in three different ways to demonstrate the effects of scaling points in 3D.
These modifications are so straightforward that no explanation of the actual code is justified. You can view the modifications in Listing 30 .
End of discussion .
That concludes the discussion of the program named GM01test06 . You will find a complete listing of this program in Listing 30 .
Things are about to get a lot more interesting. This program and the one following it both deal with the rotation of geometric objects, which is a relatively complex topic.
In this program, I will teach you how to use the new GM01.Point2D.rotate method to rotate objects in 2D space. In the next program, I will teach you how to use the new GM01.Point3D.rotate method to rotate objects in 3D space.
Rotation is 3D space is much more complicated than rotation in 2D space, so I will begin my explanation of this topic with the simpler of the two programs.
Equations for rotating an object in 2D space
Once again, we have some equations to deal with, and once we understand the equations, the required code is tedious, but not terribly difficult to write. The new game-math library method named GM01.Point2D.rotate , which begins in Listing 14 , implements the required equations for rotating an object in 2D space.
| Listing 14: Beginning of the game-math library method named GM01.Point2D.rotate. |
|---|
|
The purpose of the GM01.Point2D.rotate method is to rotate a point around a specified anchor point in the x-y plane. The location of the anchor point is passed in as a reference to an object of the class GM01.Point2D . The rotation angle is passed in as a double value in degrees with the positive angle of rotation being counter-clockwise.
Does not modify the original Point 2D object
This method does not modify the contents of the original Point2D object on which the method is called. Rather, it uses the contents of that object to instantiate, rotate, and return a new Point2D object, leaving the original object intact.
Equations for rotating an object in 2D space
By using the information on the Spatial transformations web page along with other information on the web, we can conclude that the equations required to rotate a point around the origin in 2D space are shown in Image 6 .
| Image 6: Rotation equations for a point in 2D space. |
|---|
|
I won't attempt to derive or justify these equations. I will simply use them. If you need more information on the topic, simply Google 2D transform s and you will probably find more information than you have the time to read.
In Image 6 , the coordinates of the original point are given by x1 and y1 , and the coordinates of the rotated point are given by x2 and y2 . The angle alpha is a counter-clockwise angle around the origin.
Houston, we have a problem
We still have a problem however. The equations in Image 6 are for rotating a point around the origin. Our objective is to rotate a point around any arbitrary anchor point in 2D space.
We could probably modify the equations in Image 6 to accomplish this. However, there is another way, which is easier to implement. It can be shown that the same objective can be achieved by translating the anchor point to the origin, rotating the object around the origin, and then translating the rotated object back to the anchor point. Since we already know how to translate a point in 2D space, this is the approach that we will use.
You must be very careful
I do want to point out, however, that you really have to think about what you are doing when you rotate geometric objects, particularly when you combine rotation with translation. For example, rotating an object around the origin and then translating it does not produce the same result as translating the object and then rotating the translated object around the origin.
Clone the original Point2D object
Listing 14 begins by calling the new GM01.Point2D.clone method to create a clone of the object on which the rotate method was called. The clone, referred to by newPoint , will be rotated and returned, thus preserving the original object.
Following that, Listing 14 declares working variables that will be used later.
Incoming parameters
The GM01.Point2D.rotate method in Listing 14 requires two incoming parameters. The first parameter is a reference to a GM01.Point2D object that specifies the anchor point around which the geometric object is to be rotated. The second parameter is the rotation angle in degrees, counter-clockwise around the origin.
Translate the anchor point to the origin
Listing 15 gets a Vector2D object that represents the displacement vector from the origin to the anchor point.
| Listing 15: Translate the anchor point to the origin. |
|---|
|
The negative of the displacement vector is used to translate the clone ( newPoint ) object, thus translating the anchor point to the origin.
Rotate the translated newPoint object around the origin
Listing 16 implements the two rotation equations shown in Image 6 to rotate the translated newPoint object around the origin.
| Listing 16: Rotate the translated newPoint object around the origin. |
|---|
|
Note that the rotation angle is converted from degrees to radians to make it compatible with the sin and cos functions from the standard Java Math library.
Translate the rotated newPoint object back to the anchor point
Finally, Listing 17 uses the displacement vector that was created and saved earlier to translate the rotated newPoint object back to the anchor point.
| Listing 17: Translate the rotated newPoint object back to the anchor point. |
|---|
|
Then Listing 17 returns a reference to the rotated newPoint object.
Now back to the program named StringArt02
This is a 2D version of a string art program that supports rotation in two dimensions. This program produces a 2D string art image by connecting various points that are equally spaced on the circumference of a circle as shown in Image 7 .
| Image 7: Initial graphic output from the program named StringArt02. |
|---|
![]() |
Initial conditions
Initially, the circle is centered on the origin and there are six points on the circle connected by lines forming a hexagon. The lines that connect the points are different colors. The radius of the circle is 50 units. The points at the vertices of the hexagon are not drawn, but the lines that connect the vertices are drawn. The anchor point is drawn in black, resulting in the small black circle at the origin in Image 7 .
A graphical user interface
A GUI is provided that allows the user to specify the following items and click a Replot button to cause the drawing to change:
Changing the number of points causes the number of vertices that describe the geometric object to change. Changing the number of loops causes the number of lines that are drawn to connect the vertices to change.
For a value of 1, each vertex is connected to the one next to it. For a value of 2, additional lines are drawn connecting every other vertex. For a value of 3, additional lines are drawn connecting every third vertex as shown in Image 8 .
| Image 8: Graphic output from the program named StringArt02 with Loops set to 3. |
|---|
![]() |
Rotating the geometric object around the origin
The geometric object can be rotated around an anchor point. Entering a non-zero value in the Rotation field causes the geometric object to be rotated by the specified angle around the anchor point.
The anchor point is initially located at the origin, but the location of the anchor point can be changed by the user. If the anchor point is at the origin, the geometric object is rotated around the origin as shown in Image 9 . (Compare the colors and the locations of the vertices in Image 8 and Image 9 to discern the result of the rotation in Image 9 .)
| Image 9: Rotation by 30 degrees around the origin. |
|---|
![]() |
Rotating the geometric object around an anchor point away from the origin
Image 10 shows the result of rotating the geometric object by 90 degrees around an anchor point that is not located at the origin.
| Image 10: Rotation around an anchor point that is not at the origin. |
|---|
![]() |
The rotation angle is specified in degrees with a positive angle being counter-clockwise. For Image 10 , I purposely located the anchor point at the upper-right vertex in Image 8 and rotated the geometric object by 90 degrees around that anchor point. Compare Image 10 with Image 8 to see the result of rotating the geometric object around the anchor point.
Rotating around an anchor point further out in space
In Image 11 , I moved the anchor point further out in space, but still on a line that runs through the origin and the upper-right vertex in Image 8 . Then I rotated the geometric object by 30 degrees around the anchor point.
(Note that the rotation examples in these images are not cumulative. In other words, each rotation is relative to an un-rotated object at the origin.)
| Image 11: Rotation around a point further out in space. |
|---|
![]() |
By now, you should have been able to predict in advance what you would see when the program was run with these parameters.
Let's see some code
Given what you have already learned, the only interesting new code in this program is in the drawOffScreen method. An abbreviated listing of that method is shown in Listing 18 . A complete listing of the StringArt02 program is provided in Listing 31 near the end of the module.
| Listing 18: Abbreviated listing of the drawOffScreen method. |
|---|
|
Within the method named drawOffScreen , the only really interesting code is the statement that calls the rotate method of the game-math library on each Point2D object inside a for loop. Knowing what you do about the rotate method, you should have no problem understanding the code in Listing 18 .
End of the discussion
That concludes the discussion of the program named StringArt02 . You will find a complete listing of this program in Listing 31 .
I saved the best for last, or at least I saved the most difficult program until last. In this program, I will teach you how to use the new GM01.Point3D.rotate method to rotate objects in 3D space.
Not only is the code for doing rotations in 3D space much more complicated than the rotation code in 2D, it is also more difficult to examine the graphic output produced by rotating an object in 3D space and be certain that the program is working as it should. Therefore, we need to start this discussion with an explanation of the game-math library method named GM01.Point3D.rotate . Before we can get to that method, however, we must deal with the rotation equations for rotation of a point in 3D space.
The six 3D rotation equations
Unlike with 2D rotation where things were less complicated, we now have to deal with three coordinate values, three rotation angles, and six equations. Using the Spatial Transformations webpage and other online material as well, we can conclude that our 3D rotation method must implement the six equations shown in Image 12 .
| Image 12: The six 3D rotation equations. |
|---|
|
Also, as before, these six equations are only good for rotation around the origin, but our objective is to be able to rotate a point about any arbitrary anchor point in 3D space. Once again, we will use the trick of translating the anchor point to the origin, rotating the object around the origin, and then translating the object back to the anchor point.
Beginning of the method named GM01.Point3D.rotate
The method named GM01.Point3D.rotate begins in Listing 19 .
| Listing 19: Beginning of the method named GM01.Point3D.rotate. |
|---|
|
The purpose of this method is to rotate a point around a specified anchor point in 3D space in the following order:
A useful upgrade to the game-math library might be to write three separate rotation methods, each designed to rotate a Point3D object around only one of the three axes.
It is very important to understand that the order of the rotations is critical. You cannot change the order of rotations and expect to end up with the same results. This method is designed to allow you to rotate an object around all three axes with a single method call in the order given above. If you need to rotate your object in some different order, you should call the method up to three times in succession, rotating around only one axis with each call to the method.
Incoming parameters
The anchor point is passed in as a reference to an object of the GM01.Point3D class.
The rotation angles are passed in as double values in degrees (based on the right-hand rule ) in the order given above, packaged in an object of the class GM01.ColMatrix3D .
(Note that in this case, the ColMatrix3D object is simply a convenient container for the three double angle values and it has no significance from a matrix arithmetic viewpoint. Also pay attention to the order of the three values and the rotation axes associated with those values. See Listing 20 . It is z, x, y, and not x, y, z as you might assume.)
The right-hand rule
The right-hand rule states that if you point the thumb of your right hand in the positive direction of an axis and curl your fingers to make a fist, the direction of positive rotation around that axis is given by the direction that your fingers will be pointing.
I will refer back to this rule later when describing rotations around various axes.
Original object is not modified
This method does not modify the contents of the Point3D object on which the method is called. Rather, it uses the contents of that object to instantiate, rotate, and return a new Point3D object.
Rotation around the anchor point
For simplicity, this method translates the anchor point to the origin, rotates around the origin, and then translates the object back to the anchor point.
Very familiar code
The code in Listing 19 is very similar to the code that I explained earlier beginning in Listing 14 . Therefore, this code should not require an explanation beyond the embedded comments.
Get the rotation angle values
Listing 20 extracts the rotation angle values from the GM01.ColMatrix3D object in which they are contained.
| Listing 20: Get the rotation angle values. |
|---|
|
Rotate the Point3D object around the z-axis
By this point in the execution of the method, the object has been translated to the origin using the negative of the anchor-point displacement vector. The object will be rotated around the origin and will then be translated back to the anchor point.
Listing 21 implements the first two equations from Image 12 to rotate the Point3D object around the z-axis. By this, I mean that the object is rotated in a plane that is perpendicular to the z-axis modifying only x and y coordinate values from the object being rotated.
| Listing 21: Rotate the Point3D object around the z-axis. |
|---|
|
This is the only rotation possibility in 2D rotation and the code in Listing 21 is essentially the same as the code in Listing 16 for 2D rotation.
Rotate the Point 3D object around the x-axis
Before translating the partially rotated object back to the anchor point, it must still be rotated around the x and y-axes. Listing 22 implements the middle two equations in Image 12 to rotate the Point3D object in a plane that is perpendicular to the x-axis, modifying only the y and z coordinate values.
| Listing 22: Rotate the Point3D object around the x-axis. |
|---|
|
Rotate the Point3D object around the y-axis
Listing 23 implements the last two equations in Image 12 to rotate the Point3D object in a plane that is perpendicular to the y-axis, modifying only the x and z coordinate values.
| Listing 23: Rotate the Point3D object around the y-axis. |
|---|
|
Translate the object back to the anchor point
Listing 24 translates the rotated object back to the anchor point, thus completing the 3D rotation of a single GM01.Point3D object.
| Listing 24: Translate the object back to the anchor point. |
|---|
|
In order to rotate an entire 3D geometric object, such as the hexagon in Image 13 , every point that comprises the geometric object must be rotated using the same set of rotation angles and the same anchor point.
Now back to the program named StringArt03
This is a 3D version of a string art program that demonstrates rotation in three dimensions. This program produces a 3D string-art image by connecting various points that are equally spaced on the circumference of a circle. Initially, the circle is on the x-y plane centered on the origin as shown in Image 13 .
| Image 13: Graphic output from the program named StringArt03 at startup. |
|---|
![]() |
At startup, there are six points (vertices) on the circle connected by lines forming a hexagon. The lines that connect the points are different colors. The radius of the circle is 50 units. The points at the vertices of the hexagon are not drawn, but the lines that connect the vertices are drawn.
You may have noticed that the startup graphic output in Image 13 looks a lot like the startup graphic output of the 2D program in Image 7 . There is a significant difference however. Image 7 shows only two orthogonal axes whereas Image 13 shows three orthogonal axes using oblique parallel projection to transform the 3D image to a 2D display plane.
A graphical user interface
A GUI is provided that allows the user to specify the following items and click a Replot button to cause the drawing to change:
Again, the 3D GUI in Image 13 looks similar to the 2D GUI in Image 7 . The big difference is that the 2D GUI in Image 7 allows only for rotation around one axis, and only two coordinate values can be specified for the location of the anchor point.
As before, changing the number of points causes the number of vertices that describe the geometric object to change. Changing the number of loops causes the number of lines that are drawn to connect the vertices to change.
The geometric object can be rotated in any or all of three dimensions around an anchor point. Entering a non-zero value in one or more of the Rotate fields causes the object to be rotated by the specified angle or angles around the anchor point.
The anchor point is initially specified to be at the origin, but the location of the anchor point can be changed by the user. If the anchor point is at the origin, the image is rotated around the origin.
Geometric object with 12 vertices, 4 loops, and no rotations
As a baseline case, Image 14 shows the string-art geometric object with 12 vertices, 4 loops, and no rotations. At this point, the geometric object is an infinitely thin disk in the x-y plane centered on the origin. Note the break in color between yellow and blue that occurs where the circle crosses the positive x-axis.
| Image 14: Geometric object with 12 vertices, 4 loops, and no rotations. |
|---|
![]() |
The rotation angle must be specified in degrees with a positive angle being given by the right-hand rule as applied to the axis around which the image is being rotated.
Rotation around one axis only
Image 15 , Image 16 , and Image 17 show the results of rotating the object around only one axis at a time with the anchor point at the origin.
Image 15 shows the result of rotating the object around the z-axis only by an angle of 60 degrees.
| Image 15: Rotation around the z-axis only. |
|---|
![]() |
This results in the object still being in the x-y plane, but it has been rotated counter-clockwise by 60 degrees. Compare Image 15 with Image 14 and note how the color break between yellow and blue has moved around to be near the intersection of the circle and the positive y-axis.
Rotation around the x-axis only
Image 16 shows the result of rotating the object around only the x-axis with a rotation angle of -60 degrees.
| Image 16: Rotation around the x-axis only. |
|---|
![]() |
The object is still a disk, but that disk is no longer in the x-y plane. Instead, it has been tilted so that it is now closer to the x-z plane than to the x-y plane. Unfortunately, the oblique parallel projection does not make it practical to do any quantitative measurements on the image.
Rotation around the y-axis only
Image 17 shows the result of rotating the object around only the y-axis with a rotation angle of -60 degrees.
| Image 17: Rotation around the y-axis only. |
|---|
![]() |
I will let you interpret what you see there.
Rotation around all three axes with the anchor point at the origin
When more than one rotation angle has a non-zero value, the rotational effects are cumulative. The object is first rotated around the anchor point in a direction consistent with rotation around the z-axis (rotation in the x-y plane) . Then that rotated object is rotated in a direction consistent with rotation around the x-axis (rotation in the y-z plane) . Finally, the previously rotated object is rotated in a direction consistent with rotation around the y-axis (rotation in the x-z plane) . It is important to note, however, that the actual rotation is around the anchor point and not around the origin unless the anchor point is at the origin.
Image 18 shows the result of applying all three of the rotations described above with the anchor point at the origin.
| Image 18: Rotation around all three axes with the anchor point at the origin. |
|---|
![]() |
Once again, I will let you interpret what you see there.
Perform all three rotations with the anchor point away from the origin
Image 19 performs the same three rotations as were performed in Image 18 . However, in Image 19 , the anchor point was at a location defined by the coordinate values (50,50,50).
| Image 19: Perform all three rotations with the anchor point away from the origin. |
|---|
![]() |
At the risk of being boring, I will state once again that I will let you interpret what you see there.
Will animate the process later
For me, at least, it isn't easy to visualize the process of rotating around an arbitrary anchor point in 3D. In a future module, I will animate the rotation process and run it in slow motion so that you can see the progress of each individual rotation from the beginning until the point where all three rotations are complete. Hopefully, that will make it easier to visualize rotation around an arbitrary anchor point in 3D. As a bonus, it will also give you some experience in using the game-math library for a non-trivial animation project.
Let's see some code
As was the case with the previous program, given what you have already learned, the only interesting new code in this program is in the drawOffScreen method. Furthermore, only a small portion of the code in that method is new and interesting. Listing 25 contains some code that was extracted from the drawOffScreen method.
A complete listing of the program named StringArt03 is provided in Listing 32 .
| Listing 25: Interesting code from the drawOffScreen method. |
|---|
|
The only really interesting code in Listing 25 is the statement that calls the rotate method of the game-math library on each Point3D object inside a for loop near the bottom of the listing. Knowing what you do about the rotate method, you should have no problem understanding the code in Listing 25 .
End of the discussion
That concludes the discussion of the program named StringArt03 . You will find a complete listing of this program in Listing 32 .
Click here to download a zip file containing standard javadoc documentation for the library named GM01 . Extract the contents of the zip file into an empty folder and open the file named index.html in your browser to view the documentation.
Although the documentation doesn't provide much in the way of explanatory text (see Listing 26 and the explanations given above) , the documentation does provide a good overview of the organization and structure of the library. You may find it helpful in that regard.
The homework assignment for this module was to study the Kjell tutorial through Chapter6 - Scaling and Unit Vectors .
The homework assignment for the next module is to continue studying the same material.
In addition to studying the Kjell material, you should read at least the next two modules in this collection and bring your questions about that material to the next classroom session.
Finally, you should have begun studying the physics material at the beginning of the semester and you should continue studying one physics module per week thereafter. You should also feel free to bring your questions about that material to the classroom for discussion.
I encourage you to copy the code from Listing 26 through Listing 32 . Compile the code and execute it in conjunction with the game-math library provided in Listing 26 . Experiment with the code, making changes, and observing the results of your changes. Make certain that you can explain why your changes behave as they do.
The most important thing that you learned in this module was how to update the game-math library to support 3D math and how to produce 3D images similar to that shown in Image 1 . You learned much more than that however. Some highlights of the things you learned are:
In the next module in this collection, you will learn how to write your first interactive 3D game using the game-math library. You will also learn how to write a Java program that simulates flocking behavior such as that exhibited by birds and fish and how to incorporate that behavior into a game.
This section contains a variety of miscellaneous information.
Financial : Although the Connexions site makes it possible for you to download a PDF file for this module at no charge, and also makes it possible for you to purchase a pre-printed version of the PDF file, you should be aware that some of the HTML elements in this module may not translate well into PDF.
I also want you to know that, I receive no financial compensation from the Connexions website even if you purchase the PDF version of the module.
In the past, unknown individuals have copied my modules from cnx.org, converted them to Kindle books, and placed them for sale on Amazon.com showing me as the author. I neither receive compensation for those sales nor do I know who does receive compensation. If you purchase such a book, please be aware that it is a copy of a module that is freely available on cnx.org and that it was made and published without my prior knowledge.
Affiliation : I am a professor of Computer Information Technology at Austin Community College in Austin, TX.
Complete listings of the programs discussed in this module are shown in Listing 26 through Listing 32 below.
| Listing 26: Source code for the updated game-math library named GM01. |
|---|
|
.
| Listing 27: Source code for the program named GM01test02. |
|---|
|
.
| Listing 28: Source code for the program named GM01test01. |
|---|
|
.
| Listing 29: Source code for the program named GM01test05. |
|---|
|
.
| Listing 30: Source code for the program named GM01test06. |
|---|
|
.
| Listing 31: Source code for the program named StringArt02. |
|---|
|
.
| Listing 32: Source code for the program named StringArt03. |
|---|
|
Using Java and the game-math library named GM01 , or using a different programming environment of your choice, write a program that creates and draws a 20-level stepped pyramid as shown in Image 20 .
Each level is a box. The dimensions of the bottom box are:
The height of each box is the same. The decrease in the width and depth dimensions of the boxes is linear going from the largest box at the bottom to the smallest box at the top.
The sides of the pyramid may be transparent or opaque - your choice.
The bottom box sits on the x-z plane, is centered on the vertical axis, and the sides are parallel with the x and z axes.
Draw the axes in the approximate location shown in Image 20 in red, green, and blue.
The positive direction for x is to the right. The positive direction for y is up, and the positive direction for z protrudes from the screen (down and to the left).
Display your name in the drawing in some manner.
| Image 20: Screen output from Exercise 1. |
|---|
![]() |
Beginning with the pyramid that you created in Exercise 1 , create a replica of that pyramid positioned at a point that is twice the width of the bottom box from the origin in the positive x direction.
Draw that pyramid in red as shown in Image 21 .
| Image 21: Screen output from Exercise 2. |
|---|
![]() |
Beginning with the two pyramids that you created in Exercise 2 , rotate the red pyramid by -30 degrees around an imaginary vertical line at the center of the pyramid as shown in Image 22 .
| Image 22: Screen output from Exercise 3. |
|---|
![]() |
Beginning with the two pyramids that you created in Exercise 2 , rotate each box around an imaginary vertical line at the center of the pyramid by a negative angle with a progressively greater magnitude so that the rotation of the bottom box is zero and the rotation of the top box is approximately -85 degrees as shown in Image 23 . This produces a 3D object similar to a spiral staircase with the length of each step being less than the length of the step below it.
| Image 23: Screen output from Exercise 4. |
|---|
![]() |
Beginning with the two pyramids that you created in Exercise 2 , rotate each box in the red pyramid around an imaginary line that is parallel to the z-axis and lies in the x-z plane at the center of the bottom box as shown in Image 24 .
Make the rotation angles for each box progressively larger in such a way that the rotation of the bottom box is zero and the rotation of the top box is approximately 28 degrees.
| Image 24: Screen output from Exercise 5. |
|---|
![]() |
Beginning with the two pyramids that you created in Exercise 2 , rotate each box in the red pyramid around the z-axis as shown in Image 25 .
Make the rotation angles for each box progressively larger in such a way that the rotation of the bottom box is zero and the rotation of the top box is approximately 28 degrees.
| Image 25: Screen output from Exercise 6. |
|---|
![]() |
-end-