Math 155B – Topics in Computer Graphics – Spring 2018
 

Project #2 – Shader-based sine-wave water surface

Overview:  For this assignment, you will write a program that uses shaders to generate water waves, calculating both the water height and the surface normals in shaders. 

Due date: Friday, April 27, 9:00pm. (EXTENDED)  Upload to gradescope, and get graded in-person.

Download a sample executable, and starter code from:

http://www.math.ucsd.edu/~sbuss/CourseWeb/Math155B_2018Spring/Project2/GlslWaves_Spring2018.zip

Your program should support the following two major features:

·        One shader will use a modified vertex shader to set both vertex positions and vertex normals to form travelling sine waves coming *circularly* from some central point slightly outside the rendered mesh.  These per-vertex values will feed to a fragment shader that does Phong lighting calculations (using Phong shading, i.e., Phong interpolation of normals).

·        A second shader will use a (different) modified vertex shader to set vertex positions for the same sine waves, and then use a modified fragment shader to calculate exactly the fragment normal (pixel normal) instead of using a Phong interpolated value. The fragment shader uses this for its Phong lighting calculation.

·        These should render similar to the example demo’ed in class Wednesday and Friday.

Suggested steps for completing the project.

1.      Download, as starter code, the files from (same link is above)
 
http://www.math.ucsd.edu/~sbuss/CourseWeb/Math155B_2018Spring/Project2/GlslWaves_Spring2018.zip

2.      This contains a set of source files, plus a “.glsl” file with shader source code.  If you compile and run the file, you will find it renders a re-meshable flat ground plane (the water surface), and some Phong lights, and Phong materials.  (This is a stripped down version of projects from last quarter.)  For this, make sure the .glsl file is in the current directory (usually, the one with your C++ project files).

3.      Create a new Visual C++ project, including all the source code (not the .glsl file). Make sure it compiles and runs, showing a fixed ground plane. It has the same keyboard controls as last quarter. (Re)familiarize yourself with them; for this see them listed in the stdout window.

4.      Look through the code to see what is present:

a.      GlslWaves.cpp – main program.

b.      WaterPlane.cpp – defines the ground plane (water surface) with all points at height y=0.

c.      DemoPhongData.cpp – definitions of Phong materials and lights’ properties

d.      EduPhong.cpp – reads the Phong lighting shader code from the .glsl file.  Also handles loading material properties and light properties into the shaders.

e.      GlShaderMgr.cpp – new code to facilitate reading shader source code from a file.  Used by EduPhong.cpp.

f.       GlGeomSphere – renders spheres. (Used to show position of lights.)

g.      LinearR4, etc.  Linear algebra and math routines.

h.      EduPhongBase.glsl – the “EduPhong” shaders doing the Phong lighting. The core of Project 2 involves modifying these.

5.      Side comment: The remaining steps involve a lot a new things and may be confusing at times. PLEASE: if the instructions are unclear, or you are stuck, post questions to piazza.  (And, if you know the answer to a piazza question, please answer it!). 

6.      Initial steps to get the .glsl file (shader source) ready to modify.

a.      First rename the EduPhongBase.glsl file to something more appropriate to avoid confusion with the usual EduPhong shaders.  (I called mine WavePhong.glsl.) 
Special lines in this file start with #beginglsl and #endglsl to mark the beginning and end of the shaders.

b.      Examine the routine loadcompilelink_twoshaders()  in EduPhong.cpp to see how these are loaded and compiled into shaders. Your project will modify the “PhongPhong” versions of the shaders.  The “PhongGouraud” versions will not be used.  In the shader source code, discard the two “PhongGouraud” shaders.  Then make two copies of the “PhongPhong” shaders: They need distinct names. Chose some reasonable names.  (You will now have five distinct blocks of code in the .glsl file: Two vertex shaders, two fragment shaders, and one “CodeBlock” that has the reusable Phong lighting calculations.)

c.      After you have made the changes from step 5.b, make the corresponding changes to EduPhong: Fix the .glsl file name, and the names of the shaders passed to GlShaderMgr routines.  Also, both shaders are loaded and compiled the same way as “PhongPhong” shader: namely, the shaderCalcPhong is part of both the fragment shaders, not part of the vertex shader.

d.      You probably also want to change variable names in EduPhong to not use “PhongPhong” and “PP” and “PhongGouraud” and “PG”. Choose something that makes sense to you. (I used “WaveOne” and “Wone” and “WaveTwo” and “Wtwo”.) This will involve changing the names of a number of variables. It is easy to change names globally throughout the project by using the “Find” icon at the top of the Visual Studio window.

e.      Make sure everything still works.  Both shaders should do the identical thing: Phong lighting with Phong shading --- that is, at first, the “P” command just swaps two identical shaders.

7.      Modify the first vertex shader to do the following:

a.      Add a new uniform input named time, of type float.  This can be done right after the lines declaring projectionMatrix and modelviewMatrix.

b.      In the EduPhong and GlslWaves, find every  place where the locations of the projectionMatrix and modelviewMatrix are used.  Add to these code for keeping track of the time location in the shaders.

c.      When a vertex with vertPos as its position is received by the first shader, modify the y  coordinate to be the appropriate height for a the sine wave. (See math formulas below.)  Keep the x and z coordinates the same. The glsl code will not let you modify the input variable vertPos, so you will need to make another vec3 variable and use it instead.  Let mvPos4 and gl_Position and mvPos be computed with the new y height.

d.      In GlslWaves.cpp, add a new global variable to keep track of the current time. Increment the time by a fixed value (1.0/60.0) each render call, and set its value as a uniform variable for the shader in every render call (using glUniform1f.)

e.      Test that everything works well before proceeding further.  You should see the surface with travelling sine waves. The positions of vertices should be good, lights should work etc. However, the normal are not correct yet. (Congratulations, you are through the first major part of the project!)

f.       Ignore the input vertNormal. Instead compute mathematically the normal at the vertex from the x and z.  (See math hints below, and in lecture.)  Use this to compute mvFrontNormal which is an output from the vertex shader.

g.      Verify everything runs well:  Check normals: First, using one light at time and only diffuse light (disabling ambient and specular), and seeing if the correct sides of waves are lit. Second turn on specular lighting, with one light at a time, and seeing if specular highlights work correctly.

h.      Adjust colors of lights and the material properties of the water plane to get something that looks somewhat like water.

i.       Look at how lighting responds to changes in mesh resolution.

j.       Congratulations you are done with the first shader!

8.      Now work on the second shader.

a.      You will borrow a fair amount of code that you wrote for the first shader. But now, the normal calculation is done at each pixel by the fragment shader. This will require knowing the x and z coordinates of the point in local coordinates (not modelview coordinates): these need to be output from the vertex shader (use a new “out” variable or variables), and received in averaged form as “in” variable(s) by the fragment shader.

b.      Calculate the mvNormalFront with a mathematically correct formula in the fragment shader. (It is no longer an “out” / “in” variable for the shaders.

c.      The “P” command should toggle between the two shaders. Compare the results of the second shader with the first shader. You should see the same kind of improvement as we saw in the demo program in class.

9.      A problem with using a fixed 1/60 time increment is that when the cursor moves across the screen, the glfw routines return more frequently, to time “goes faster”.  Fix this by using glfwSetTime (once during initial setup), and using glfwGetTime every time a render occurs.  (Google for how to do this. It is simple!)

10.   Try adding Multisample Antialiasing (MSAA). For the commands, see the sample program SimpleAnimModern at the course page with sample OpenGL programs.  (It is glfwWindowHint(GLFW_SAMPLES, 4);)  Can you see any differences with MSAA turned on?

11.   Math formulas. Fix values for (a) wavelength (lambda), frequency (freq), and amplitude (amp).  (b) a center point c where waves emanate.  These can be hardwired into the shader programs, but make them separate variables in the shader programs so they are easy to modify.  Let d be the distance from the center.  Then the wave height is given by

      height = amp * cos( 2*pi*( d / lambda – freq*t ) ).

The speed of the wave will be lambda*freq.  (Google “travelling wave formula” for other discussions of this; they do not always use the same variable conventions!)  You should understand why this works as the formula for a travelling wave.
Calculating the normal vector: Do this similar to the method used last quarter for the surface of rotation project.  I suggest finding the derivative with respect to d, and then using (-d.x,1,-d.z) where d.x and d.z represent x and z components of d appropriately rotated relative to the direction from the center of the waves. (We will discuss this in class.)

12.   You will see the light spheres are affected by the shader program (waving as flat pieces). You could fix this by swapping in a third shader, but it is not required for this project.

Hand in procedure:   FIRST: As usual, create a directory called Project2. As for past projects have things ready for an in-person grading session.  SECOND: Upload your shader file (.glsl file) to gradescope.

Grading:  Grading is an individual session with Jonathan Conder or Professor Buss.