Math 155A - Introduction to Computer Graphics – Fall 2022
Instructor: Sam Buss,  Univ. of California, San Diego

Project #4 – Build a ground plane and surface of rotation with normals.
Due date: Thursday, November 3, 2022, 11:59pm. (Note Thursday is the due date.)

Goals: Create a parametric surface (namely, 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. 
    This project is based on Project #3. In addition, it will be used as the basis for Project #5, which will add materials and lighting to the scene.

What to hand in:  

·       Upload to gradescope, your main source files and PDF report of your project, all placed together in a zip file. For most people, there will be three files uploaded, two source (.cpp) files and one PDF file.

o   The source files are the main project source files MySurfaces.cpp and MyInitial.cpp.  Also include MySurfaces.h and MyInitial.h if they were changed. Please use exactly these names for your main files and place them in a zip file to upload.

o   A PDF file with a report of your work. See the instructions below. This will include your name, but not your student ID.  This should include primarily an image of your surface with the normal vectors shown.

·       Get an individual zoom grading session with Professor Buss or a TA. If you have not already had Project 3 graded, get it graded at the same time.  The grading rubric (preliminary form) can be found atRubric_Project4_Fall2022.pdf


1.     Make sure to save copies of all your files from Project 3.  This is VERY IMPORTANT! When you start a new project in Step 6 below, be sure to make **copies** of your source files first. And afterwards, add the copies into the new project. (If you do lose your Project 3 files, they should still be in your uploaded gradescope zip file, but it will take extra work to get them running again, e.g. for grading.)

2.     Download the file from the web.  This zip file contains four (4) C++ source files and a file of shaders (SurfaceProj.glsl).  It also contains an executable Project4Demo_Fall2022.exe.  

3.     Run the executable on a PC (or Cloudlabs) with the .glsl file in the same directory.  You will see a scene with a surface of rotation and a letter "X".  Start by pressing capital “M” a few to increase the mesh resolution so that the surface of rotation looks decent. Note the following commands act on the scene

a.      Pressing the arrow keys changes the view position

b.     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).

c.      Pressing the “C” or “c” key toggles culling of back faces. 

d.     Pressing the “M” or “m” key increases or decreases the mesh resolution on the spheres (ellipsoids) and cylinders. It also increases the resolution of the ground plane and the surface of rotation.

e.      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).

f.      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.)

g.     The “Home” and “End” keys move the view a little closer or a little farther away.

4.     Your job is to re-create this program -- sort of!!  However, you continue to use your own initial from Project 3 instead using of the “X” in the Demo program.   The main work for Project 4 is re-create the surface of revolution as exactly as you can. You will also add surface normals. 

5.     Form a NEW project and solution; integrate your project 4 code into the new project. Include the of all supplied source files in the new project. (Again, save copies of your old source files!  Do not just include your Project 3 files in Project 4.)  The supplied source code handles all the keystroke commands, and draws a fixed 4x4 flat base plane, and a fixed, low resolution surface of rotation.   It has routines that need to be written for your Project 4 to form the surface of rotation and the ground plane.
The supplied source code should compile and run and show a non-meshable version of the scene once you get your Project 3 files integrated into the new project.  To integrate your Project 3 code into the new project

a.      Include most of the Project 3 files into your new Project 4. But do NOT include InitialProj.h, InitialProj.cpp or InitialProj.glsl.  (These are replaced by the three SurfaceProj files.)

b.     You should still include all the extra downloaded source code, including the GlLinearMath files (MathMisc and LinearR3 and LinearR4 source and header files), GlShaderMgr files, and GlGeom… files.

c.      Replace the supplied MyInitial.cpp with your own version of this file from Project 3. 

d.     Include the four new C++ files in the .zip file, SurfaceProj.cpp, SurfaceProj.h, MySurfaces.cpp and MySurfaces.h into the new project.

e.      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.

f.      Integrate your old MyInitial.cpp into the new code..  For this to work in the new project, you will need to make at least one change in your MyInitial.cpp:            

                                               i.     Replace the line  #include "InitialProj.h" with the line
#include "SurfaceProj.h"

g.     Make any other changes necessary to get the code to work. If you made changes to MyInitial.h in your Project #3, please bring them into the new Project 4. (E.g., if you added extern statements.)

h.     If you made changes during Project 3 to InitialProj.cpp or any other source files, also integrate those into SurfaceProj.cpp in the new project. This might happen, for instance, if you changed the controls for the animation. (If necessary, you can use a “diff” program to compare your MyInitial.cpp file with the original one supplied with Project 3.)

i.      If you have to make changes for parts g. and h., make a note of them, as you may need to do this again for Project 5.

6.     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)  This file *replaced* InitialProj.cpp as the new main file in the project.

7.     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 resolutions.  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.

8.     Examine the “Demo” code that generates the ground plane as a 4x4 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. This is described in Chapter 1 and you may also look up online how this works, and it will be discussed in class and is discussed in a prerecorded video. 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(vNormal_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.

9.     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.

10.  Write code that generates the ground plane so that it can be dynamically re-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 already defined in SurfaceProj.h and SurfaceProj.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 (this is necessary only if you used new or malloc, it is not necessary if you use std.::vector).

                                            vi.     A common bug: In the Demo code, sizeof(floorverts) is used as a parameter to glBindBufferData to specify the number of bytes to upload to the VBO. If floorverts is replaced by a pointer floorVertsPtr to an array, the size(floorVertsPtr) will equal either 4 or 8 (for 32-bit or 64-bit systems) instead of the size of the array contents. This will need to be replaced with the correct size when you write your code.  Similar comments apply to the EBO buffer and to the surface of rotation.

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 glDrawElements 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. There is code commented out in the supplied source code that does this  “printf” debugging.

11.  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 y = 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 the triangle strips form a surface of rotation and you must also calculate and store a surface normal for each vertex.

12.  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.    

13.  Your x*sin(x)/(x+1) surface should be well-formed: It should not have missing triangles, degenerate triangles or duplicate triangles. It should have the front faces facing upward.  It should not have pixel-sized misalignments due to floating point round-off error.  For the last point, please be aware that in C++ code, sin(2π) or sin(PI2) will probably not evaluate to exactly zero!

14.  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

15.  Examine your normals carefully, using the “N” keystroke command. (See item 3.f above.) 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.

16.  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.

17.  Write a PDF report. Call it “Project4report.pdf” (This name exactly, same capitalization!) It must have:

a.     Your name on the first page, near the upper left corner. If you use different versions of your name, it will help with grading to use the same version in the PDF and on the in-person grading sheet. Please do not include your student ID (for privacy).

b.     Add a picture (or at most two pictures) showing your system in wireframe mode with normal vectors shown. Try to choose a view that shows the normal vectors.

18.  Place the PDF file in a zip file along with your main changed source files (and no other files). This will be onePDF file and one or two .cpp files and possibly one or two .h files. Upload the zip file to gradescope.

Program grading: Scale of 0 to 20.  Zoom grading session with a TA or Professor Sam Buss. The PDF report can later somewhat increase or decrease your project score.

Suggestions on the x*sin(x)/(x+1) surface of rotation.  The best way to form this surface is to express it as a parametric function f(θ,r), where θ (theta) 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 x*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 directly in your data that is loaded into the VBO?)

For the nested for-loops that form the VBO data for the surface of rotation, your for-loops should be controlled with integers, not floats or doubles. For more information, see the handout on floating point perils available from the course web page.

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.)