Math 155B – Topics in Computer Graphics – Spring 2019
 

Project #2 – Shader-based double 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.  See the final page below for sample images.

Due date: Friday, April 19, 9:00pm.  Upload to gradescope, and get graded in-person.

Download a sample executable, and starter code from:

http://www.math.ucsd.edu/~sbuss/CourseWeb/Math155B_2019Spring/Project_2/GlslWaves_Spring2019.zip

Your program should support the following major features:

·        In the first mode, your program will display with one sine wave, with normal, and Phong lighting.

·        In the second mode, your program will render the combination of two sine wave curves, superimposed.

·        You will modify the Phong lighting vertex shader to set the positions of the vertices.

·        You will modify the Phong lighting fragment shader to set the normal vectors to the surface. (This is not Gouraud shading or Phong shading. Instead, since we have mathematical formulas for the sine waves, your shader code calculates the exact normal vector.)

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

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_2019Spring/Project_2/GlslWaves_Spring2019.zip

2.      This contains a set of some core source files. GlslWaves.[cpp,h], WaterPlane.[cpp,h], and WavePhongData.[cpp,h]. Download in addition, from the textbook’s web page of software: EduPhong.[cpp,h] and EduPhong.glsl, GlShaderMgr.[cpp,h], LinearR3.[cpp,h], LinearR4.[cpp,h], MathMisc.h, and GlGeomSphere.[cpp,h]. Put all these files into a single Visual Studio project.

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

4.      This has the same keyboard controls as last quarter. (Re)familiarize yourself with them; for this see them listed in the stdout window.

5.      Your project will add waves to this ground plane by programming a vertex shader and a fragment shader.

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

a.      GlslWaves.cpp – Main program.  You will make minor changes to this file for your project.

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 – 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.      EduPhong.glsl – the “EduPhong” shaders doing the Phong lighting. The core of Project 2 involves modifying these shaders.

7.      Side comment: The remaining steps 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!). 

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

a.      Start a new .glsl file.  Create copies (with new names!) of the “PhongPhong” versions of the vertex shader and fragment shader from EduPhong.glsl.    Put them in the new file.

b.      Change GlslWaves.cpp to read both EduPhong.glsl and your new .GLSL file, and to compile using the new copies of the shaders (which you will need to modify).

c.      Make sure everything still works. 

9.      Modify the vertex shader to do the following:

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

b.      Similarly add a new integer uniform variable waveMode. The intent is that if it zero, one sine wave is generated. If it is one, then two are generated.

c.      Examine the GlslWaves.cpp code.  Check how it determines and use the locations of the projectionMatrix and modelviewMatrix are used. Similar code already tracks and sets the curTime and the waveMode values.  Values are set with glUniform* commands. Please understand how all this works.

d.      Change the vertex shader, so that when it receives a vertex at position vertPos, it modifies the y  coordinate to be the appropriate height for the sine wave(s). (See math formulas below.)  Keep the x and z coordinates the same. The waves should look as good as in the demo shown in class (or better!). I suggest making the point where waves are centered lie somewhere outside the ground plane.

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

f.       Test that everything works well before proceeding further.  You should see the surface with travelling sine waves if you render in wireframe mode.  Adjust the frequency and wavelength, and the center of the wave generator. The positions of vertices should be good, lights should work etc. However, the normals are not correct yet. (Congratulations, you are through the first major part of the project!)

g.      Ignore the input vertNormal.

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!

10.   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 “B” command should toggle between rendering a single wave or two superimposed waves.

11.   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, so 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!)

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

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

14.   Hints:

a.      The fragment shader must compute the normal in modelview coordinates (not affected by the projection matrix). Don’t forget to use the inverse transpose. This is needed the Phong lighting calculation works in (orthogonal) modelview coordinates.

b.      The fragment shader will need to know the original vertPos values in order to compute the normals.

c.      There will be duplicate code in the two shaders. You can either write the code twice and make sure it the same in both shaders, or you can write a new function.  (The former is probably easier.)

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

Hand in procedure:   FIRST: As usual, be ready for an in-person grading session on a basement computer lab computer.  SECOND: Upload your shader file (.glsl file) to gradescope.

Grading:  Grading is an individual session with Nick Sieger or Professor Buss. 

SEE NEXT PAGE FOR SAMPLE IMAGES