To become more comfortable with lighting, and to deal with picking and interactivity.
You will start with the solution to the previous assignment (if you are not happy with your own, you may use one of the sample solutions we will provide). Enhance this Java program, that reads in a file describing a graphical scene (see below for the format), to allow you to interact with it more directly.
You program should include the features of the first (reading the file, turning on and off the elements using the AWT or Swing window).
The changes you must implement include the following:
Your program should consist of a set of java files which should be commented with your name (the name you are registered under!) and ID number. One of the java files should implement a class "A3" (so the TA can execute it using the command "java A3".) The files should be emailed as attachments to a single email message to firstname.lastname@example.org.
The time the mail is received will be used to determine whether or not the program is late, so be sure to allow a couple of minutes for the mail system to transmit your file if you are working right up to the deadline.
IMPORTANT: If the TA has to edit your files you will lose points. Similarly, the TA should be able to execute the class "A3", so using any other class as your main class will result in lost points.
This program is due on or before Monday, October 18th. This means it must be received by 11:59pm EDT on Wednesday to not be considered late.
You program should read and create elements as before. However, for this assignment, you need to modify the objects slightly. In particular, each object needs to have an arbitrary transformation associated with it (which is what is manipulated with the mouse). To handle this, please do the following:
Depending on your program structure, adding these elements to your graph may cause them to appear in the list of nodes in the AWT/Swing window. Ideally, we would like it if they didn't, but it is ok if they do.
To compute the vertex normals, you must compute the polygon normal for each polygon in the mesh, and then determine for each vertex which polygons are adjacent to it. There are a number of ways to do this, depending on how you store the data in memory (the guest lecture spoke on this, and the book describes different data structures). Whichever approach you use, it should compute the normals once when the mesh is loaded and then use them when the mesh is rendered.
The format of the input file is as follows. Changes are in bold.
The possible elements are:
The possible transformations that can be specified on a group element are:
Consider again the example file from A2, that creates a cross with a red verticle axis and a blue horizonatal axis:
cube topbottom .8 .2 .2 cube leftright .2 .2 .8 group top translate 0 1 0 topbottom group bottom translate 0 -1 0 topbottom group left translate -1 0 0 leftright group right translate 1 0 0 leftright group grid scale 2 2 2 left right top bottom window fourcubes size 300 300 lookat 2 2 -10 0 0 0 perspective 30 1 20 grid
This example creates a hierarchical set of coordinate systems as follows:
grid |______________ | \ \ \ | \ \ \ left right top bottom | | | | \ / \ / leftright topbottom
With the new set of intermediate group nodes, we now have a graph that looks like this:
t0 | grid |______________ | \ \ \ | \ \ \ t1 t2 t3 t4 | | | | left right top bottom | | | | t5 t6 t7 t8 | | | | \ / \ / leftright topbottom
The t# nodes are the new groups. If you wanted to manipulate the position of "top", you would apply the transformations to "t3". If you wanted to manipulate the position of one of the two visible instances of the "topbottom" node, you place the transformation in "t7" or "t8".
The interaction you will support is the following.
At any time there is a "currently selected object". Clicking in the world with the CONTROL key down will change the selection (you should use picking with a pickwidth and pickheight of 4 pixels). If there is no object hit (ie. the user clicks in the background) the rootnode is selected. At the start, the rootnode should be selected. When the user clicks, you should print out the names of all objects under the cursor.
If there are multiple nodes hit, you should choose the one closest to the front. However, if the one of the objects hit is the currently selected object, you should instead select the one that is next farthest away. This allows you to toggle between the selected objects. You must keep track of which instance of an object is selected if it is displayed multiple times.
You should provide feedback of two forms. The first is to visually highlight the object. If an object other than the root is selected, you should render it a second time after the full scene is rendered, with the following difference: you should use make the object white and mostly transparent (try different alpha values to see which one you like) and apply a scale of (1.1, 1.1, 1.1) before rendering the object. The effect should be to create a translucent halo around the selected object.
The second is to display, in the upper right corner of the OpenGL window, the select node's path to the root. If the "left leftright" node was selected in the above example program, the following text would be displayed in the upper right corner:
grid -> left -> leftright
Once the user has selected the node, the leaf node (the visible object), should be "selected" ("leftright", in this case). It should be displayed in green, and the other ones in white. You should then allow the user to move the selection in this list using the "<" and ">" keys. Whichever node is selected, the transformations will be applied to the intermediate nodes you inserted between the groups and their children: specifically, you will apply it to the intermediate node above the selected node.
We will use a simple interaction in this assignment. You want to be able to do three things:
If the root is selected it will change the whole world.
If the user presses the "r" key, you should reset the transformation on the currently selected node to the identity matrix.
As described in class, for each click-drag-release sequence, the motion should be relative to the point at which you clicked. Once the mouse is released, the final transformation will be composed with the current transformation stored in the intermediate node above the selected node. Therefore, the transformations are saved until you reset the node with the "r" key.
Note that the only time you modify the transformation stored in the intermediate node is when the mouse is released: during a drag, you can simply keep track of the (start x, start y) and (current x, current y) values and compute the drag transformation in the display routine. In order to correctly and cleanly implement the interaction where you can do multiple transformations on the same node, with separate click-drag-release sequences, you need to do things this way. If you compose a new small transformation for each drag of the mouse, the composition of lots of small transformations (potentially hundreds or thousands, depending on how long you drag the mouse) will cause floating point error problems in the resulting transform matrix. Think about why you need to store the composite transformation matrix (and not, for example, a value for xrotation, yrotation, zrotation, translation and scale).
There are two extra credit options on this assignment. You may do one or both, and each is worth a possible one point.