Project #4 – Build a ground plane and surface of rotation with normals.
Goals: Create a parametric surface (namely, a portion of a surface of rotation) using triangle strips. Create a rectangular mesh for the ground plane using triangle strips. Dynamically change the resolution of the surface of rotation and the ground plane. Correctly calculate normal for both objects. Discover that wireframe objects, especially when combined with animation can look very three-dimensional. Discover, however, that flat, solidly colored objects look much too flat and non-three-dimensional.
3. Run the executable on a PC. You will see a scene with a surface of rotation and a letter “X”. Note the following commands act on the scene:
4. Pressing the arrow keys changes the view position.
a. Pressing the “W” or “w” key toggles wire frame mode. Note how flat and non-three-dimensional the objects look when filled in. (We will fix this in project 5, when we add material properties and lights to the scene).
b. Pressing the “C” or “c” key toggles culling of back faces.
c. Pressing the “M” or “m” key increases or decreases the mesh resolution on the spheres (ellipsoids) and cylinders. It also inceases the resolution of the ground plane and the surface of rotation.
d. The animation can be turned off and on by pressing “R” or “r”. It can be put into single step mode by pressing “S” or “s”. The animation can be made to run faster or slower by pressing “F” (faster) or “f” (slower).
e. NEW: Pressing “N” or “n” cycles through three modes of visualizing surface normals. The first mode shows no surface normals. The second mode shows normal and wireframe mesh. The third mode shows surface normals on top of the surface. (Try this last one in non-wireframe mode to see the difference.)
5. Your job is to re-create this program — sort of!! However, you continue to use your own initial Project 3 instead using of the “S” in the Demo program. You will re-create the surface of revolution as exactly as you can.
6. Form a NEW project and solution.
d. Add the SurfaceProj.glsl to the project.
IMPORTANT: Place an extra copy of SurfaceProj.glsl in the same folder as your Visual Studio project file if needed.
7. There is a new source file: MySurfaces.cpp and the associated header file. This is the source file you will update for your Project 4 work. (Steps 8-16)
8. The routine MyRemeshSurfaces() currently calls “Demo” routines that set the vertex information and element array information for rendering a ground plane and a circular surface of fixed mesh resolution. The routine MyRenderSurfaces() currently calls “Demo” rendering routines to render these “Demo” versions of the ground plane and circular surface of fixed size. You will replace these “Demo” routines with your own routines that generates a ground plane and a surface of rotation of variable mesh resolution.
9. Examine the “Demo” code that generates the ground plane as a 4×4 mesh. It uses a new method of drawing with the glDrawElements command, which specifies a triangle strip by specifying the indices (called “elements”) of the vertices that belong to the triangle strip. You may look up online how this works, and we will discuss it in class on Friday. The vertex data is stored a VBO as before. The lists of elements are stored in a buffer called the “Element Array Buffer Object”, or EBO for short. The surface normal for the ground plane is set to the constant vector <0,1,0> by calling
glVertexAttrib3f(aNormal_loc, 0.0, 1.0, 0.0);
in the routine that renders the ground plane (the “floor”). Find these things in the code, and understand how it all works.
10. Examine the “Demo” code that generates the circular surface as a small mesh of triangle strips. It uses the same kind of construction to use glDrawElements, but now the surface normals are also stored in the array with the vertex positions, and are loaded with the vertex positions into the VBO. These surface normals are different for each vertex.
11. Write code that generates the ground plane so that is can be dynamically meshed. This will be the two routines MyRemeshFloor and MyRenderFloor().
a. MyRemeshFloor must
i. Allocate two arrays of the correct sizes using the C++ new operator. (Optional: you may instead use std::vector if you prefer.)
ii. The global variable meshRes is defined in LetterProj.h and LetterProj.cpp, and it controls the mesh resolution.
iii. Fill the two arrays with the correct vertex positions in the array floorVerts and elements (vertex indices) in the array floorElements. These will vary in size and contents based on the mesh resolution as specified by meshRes.
iv. Load the two arrays into the correct VBO and EBO.
v. Delete the two arrays to avoid memory leaks.
b. MyRenderFloor must
i. Bind the vertex array for the floor
ii. Set all uniform variables and vertex attributes (color, normal, and modelview matrix) needed by the shader program.
iii. Loop to issue glDrawElement commands, one for each triangle strip.
c. Hints for step a.iii.: To set the values in the array floorVerts of vertex positions you will want to use a nested pair of for loops to range over all the rectangularly-arranged vertices. Then, to set the values the array floorElements, you will again want to use a nested pair of for loops: the outer loop iterates over the triangle strips, and the inner one over elements within the triangle strip. If you have problems getting this code to work correctly, it is suggested to set meshRes to a small value (such as 3) and render only the first triangles of the first triangle strip. Once this works, you can try rendering more. It is also suggested to use the debugger in single-step mode to see what is happening. You can examine individual values using the “Local” variables in the debugging window. Alternately, you can use “printf” to print part of the arrays to the console window.
12. Write code that generates the surface of rotation. Place the surface of rotation in the front right quadrant of the ground plane, slightly above the ground plane. The surface is a surface of rotation formed from the curve x*sin(x)/(x+1) for 0 ≤ x ≤ 2.7π, that is, x in [0, 2.7π]. You should scale and position the surface of rotation so that it looks approximately like the one in the supplied executable. It should be about the same size, and it should be above the base plane. It should be constructed from triangle strips. The general strategy to form this surface is the same as for the ground plane; however, now you must calculate and store a surface normal for each vertex.
13. Keep your initial and its animation exactly the same as in Project 3! Please do not change it, but if you do, you must let the grader know ahead of time.
14. Your x*sin(x)/(x+1) surface should be well-formed: It should not have missing quads or triangles. It should not have triangles that are drawn twice. It should have the front faces facing upward. It should not have pixel-sized misalignments due to floating point round-off error.
15. The keyboard controls that toggle back face culling and wireframe mode, and the mesh controls, should apply to all shapes in the scene. Check them carefully to make sure everything is OK
16. Examine your normals carefully, using the “N” keystroke command. They should be pointing orthogonally out from the surface, and in the upward direction. Examine this also at different mesh resolutions. Make sure the central normal on the surface of rotation is correct. Look at them in both wireframe mode and non-wireframe mode.
17. Your finished program should look the similar to the supplied demo executable, except the “X” is replaced by your own creation and with animation from Project 3. It should support all the keystroke commands listed above including the ‘M’ and ‘N’ commands.
Suggestions on the x*sin(x)/(x+1) surface surface of rotation. The best way to form this surface is to express it as a parametric function f(θ,r), where θ and r are scalar parameters. The parameter r will control the radial distance from the center, the parameter θ will determine the rotation around the center of the surface of rotation. The function r*sin(r)/(r+1) gives the height of the parametric surface, but this should be appropriately scaled to more-or-less match the shape in the demo program. The scaling is best done with Mult_glScale commands. (Why? What happens to normals if you do the scaling in your to fill the VBO?)
The mesh detail for your surface must be controlled by the “m” and “M” commands as in the sample program supplied with the assignment. (Unfortunately, the “Shift Lock” key is not effective when capturing keystrokes by the method used in the code.)