Difference between revisions of "Project4Fall13"

From Immersive Visualization Lab Wiki
Jump to: navigation, search
(1. OpenGL Lighting and Shading (50 points))
m (3. GLSL Shader Programs (40 Points))
 
(38 intermediate revisions by one user not shown)
Line 7: Line 7:
 
Note that GLSL shaders, which are needed for part 2 of the assignment, will be covered in class on Tuesday, October 22nd.
 
Note that GLSL shaders, which are needed for part 2 of the assignment, will be covered in class on Tuesday, October 22nd.
  
==1. OpenGL Lighting and Shading (50 points)==
+
==1. Mouse Control (20 Points)==
  
Start by reviving your application from assignment 2: you will need to be able to load each of the five 3D models into your application and display them at reasonable sizes, so that they are about screen filling. The function keys should switch between the models.  
+
Start by reviving your application from assignment 2: you will need to be able to display the cube, as well as the following three 3D models into your application and display them at reasonable sizes (screen filling). The function keys should switch between the models.  
  
a) You are welcome but not required to support the keyboard commands from assignment 2 to move around the models. However, you will need to add mouse control, which will allow rotating the model about the center of your OpenGL window, as well as scaling the model up and down. The '''left mouse button should be used for rotation''', the '''right mouse button should zoom in and out''' when the mouse is moved up or down while it is pressed. [[Media:cube.mpg|This video]] shows how the trackball-like rotation should work. We provide [[Media:trackball-code.txt|sample code for the trackball rotation.]] You will need to adapt it to the syntax of your matrix and vector classes and get it to work within your application. To access the mouse x and y coordinates, you will need to use GLUT's callback functions [http://www.opengl.org/resources/libraries/glut/spec3/node50.html glutMouseFunc()], which gets called when you press a mouse button, and [http://www.opengl.org/resources/libraries/glut/spec3/node51.html glutMotionFunc()], which gets called constantly while you hold the button down and move the mouse. Note that successive trackball rotations must build on previous ones; at no point should the model snap back to a previous or default position. ('''10 points''')
+
These are the models you need to be able to load, you will have to unzip them to get at the OBJ files. Note that some of them are different files than before, as we now need files with normals. The OBJ reader we gave you in project 2 already parses normals.
  
<!--
+
* [[Media:dragon.zip|Dragon (same as before)]]
 +
* [[Media:bunny_n.zip|Bunny (new)]]
 +
* [[Media:sandal.zip|Sandal (new)]]
  
Then you should write classes to manage light and material properties (<tt>Light</tt> and <tt>Material</tt>). As a starting point, refer to the relevant sections in [http://www.glprogramming.com/red/chapter05.html Chapter 5 of the OpenGL Programming Guide], as well as the [http://www.opengl.org/archives/resources/faq/technical/lights.htm OpenGL Lighting FAQ].
+
Note: Prior to Oct 29, there were bunny and head files which did not work with your obj reader. Please replace those with the files above.
  
Then you need to do the following things:
+
You are welcome but not required to support the keyboard commands from assignment 2 to move around the models. However, you will need to add mouse control, which will allow rotating the model about the center of your OpenGL window, as well as scaling the model up and down. The '''left mouse button should be used for rotation''', the '''right mouse button should zoom in and out''' when the mouse is moved up or down while it is pressed.
  
* Display the two spheres from the starter code and and modify their material properties: one of them should be shiny and diffuse, the other only diffuse. They should both be white. ('''5 points''')
+
[[Media:cube.mpg|This video]] shows how the trackball-like rotation should work. We provide [[Media:trackball-code.txt|sample code for the trackball rotation.]] You will need to adapt it to the syntax of your matrix and vector classes and get it to work within your application.
* Your mouse control routines from Project 3 need to allow the user to modify the coordinate system of the spheres. The spheres should move together, they should always remain fixed with respect to one another. In this mode, the mouse control routines should not move the light sources. ('''5 points''')
+
 
* Change the directional light from the starter code to a '''red''' point light. ('''10 points''').
+
If you cannot get the sample trackball code to work, the following description of the algorithm might help you.
* Create a '''green''' spot light with a relatively narrow spot. In its initial position it should point to at least one of the spheres. The spot diameter should be smaller than that sphere so that the outline of the spot can be seen on the sphere, as well as the brightness gradient at the edge of it. ('''15 points''')
+
 
* Support two keyboard keys: '1' and '2': The '1' key turns the point light on and off, the '2' key turns the spot light on and off, so that you can demonstrate the functionality of each light individually, as well as their combination. ('''5 points''')
+
The figure below illustrates how to translate mouse movement into a rotation axis and angle. m0 and m1 are consecutive 2D mouse positions. These positions define two locations v and w on a 3D virtual sphere that fills the rendering window. Use their cross product as the rotation axis a = v x w, and the angle between v and w as the rotation angle.
* Allow the user to move the light sources by applying your mouse control routines to them: whichever light source is enabled with the '1' and '2' keys should be affected by the mouse, which means affect their coordinate systems as if they were data models. If no light source is enabled, the mouse should move the spheres. Similar to Project 3, the 'r' key should reset the positions of all spheres and light sources. ('''10 points''')
+
 
 +
[[Image:Trackball.jpg]]
 +
 
 +
Horizontal mouse movement exactly in the middle of the window should result in a rotation just around the y-axis. Vertical mouse movement exactly in the middle of the window should result in a rotation just around the x-axis. Mouse movements in other areas and directions should result in rotations about an axis a which is not parallel to any single coordinate axis, and is determined by the direction the mouse is moved in.
 +
 
 +
Once you have calculated the trackball rotation matrix for a mouse drag, you will need to multiply it with the object to world transformation matrix for the model or the light source you are moving.
 +
 
 +
To access the mouse x and y coordinates, you will need to use GLUT's callback functions [http://www.opengl.org/resources/libraries/glut/spec3/node50.html glutMouseFunc()], which gets called when you press a mouse button, and [http://www.opengl.org/resources/libraries/glut/spec3/node51.html glutMotionFunc()], which gets called constantly while you hold the button down and move the mouse. Note that successive trackball rotations must build on previous ones; at no point should the model snap back to a previous or default position.
 +
 
 +
==2. OpenGL Lighting and Shading (40 points)==
 +
 
 +
Write classes to manage light and material properties (<tt>Light</tt> and <tt>Material</tt>). As a starting point, refer to the relevant sections in [http://www.glprogramming.com/red/chapter05.html Chapter 5 of the OpenGL Programming Guide], as well as the [http://www.opengl.org/archives/resources/faq/technical/lights.htm OpenGL Lighting FAQ].
 +
 
 +
Associate material properties with each of the four 3D model files: two of them should be shiny, and the other two should be shiny and diffuse - you choose which. Use colors other than white. ('''10 points''')
 +
 
 +
Create three light sources: one directional light, one point light and one spot light. The spot light should always point towards the center of the OpenGL window. Give them initial positions and colors. Each of them must have a different position and color. The spot light should have a spot width narrow enough so that it only illuminates a small part of the surface of the models. Toggle each of them on and off with one of the number keys: 1, 2, and 3. Rotate those light sources which are on with the 3D model.  
 +
 
 +
Add a freeze mode for the 3D model and toggle it with the 'm' key: when it is enabled, the model will not respond to mouse control commands and instead stay in its last orientation and size. In this mode only the enabled light sources rotate and zoom in and out.
  
 
'''Notes:'''  
 
'''Notes:'''  
  
 
* OpenGL multiplies light position and direction with the Modelview matrix when they are set. Therefore, you need to modify the Modelview matrix with your mouse control routines to rotate the light sources, independently for each light source.
 
* OpenGL multiplies light position and direction with the Modelview matrix when they are set. Therefore, you need to modify the Modelview matrix with your mouse control routines to rotate the light sources, independently for each light source.
* The spheres are generated by the <tt>glutSolidSphere</tt> routine, which automatically generates normal vectors. To ascertain that these normals will survive scale operations correctly, you should use the following OpenGL command: <tt>glEnable(GL_NORMALIZE)</tt>.
+
* To ascertain that the normals of your 3D models will survive zoom operations correctly, you should use the following OpenGL command: <tt>glEnable(GL_NORMALIZE)</tt>.
 
* By default, OpenGL uses a simplified model for the calculation of the highlights. For a more realistic model add this command to your code: <tt>glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE)</tt>.
 
* By default, OpenGL uses a simplified model for the calculation of the highlights. For a more realistic model add this command to your code: <tt>glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE)</tt>.
* In this (and all following) homework projects, there are no longer any restrictions on which OpenGL routines you are allowed to use.
 
  
==2. Shader Programs (50 points)==
+
==3. GLSL Shader Programs (40 Points)==
  
In this part of the project, you will need to add support for per-pixel shading of the effect of your light sources from part 1 on the spheres, which will significantly improve the visual appearance of the light reflections on the spheres.
+
Imagine that each of your light sources has a force field, which attracts or repulses the vertices of your geometry, and shifts their color.  
  
For Windows and Linux users, in order to expose OpenGL extensions, you need to [http://elf-stone.com/glee.php download GLee] and add the glee.h and glee.c files to your project files, or tell the linker to link with the GLee library (glee.lib or glee.dll for Windows, or libglee.a/libglee.so for Linux). OSX users will not need GLee, as OpenGL extensions are available by default.
+
* The directional light should repulse the vertices, and do not cause a color shift.  
 +
* The point light should repulse the vertices as well, and shift their color towards red.
 +
* The spot light should attract the vertices, but only if they fall within its spot, and shift their color towards green.
  
If the above link doesn't work, we've uploaded GLee [http://dl.dropbox.com/u/46823168/glee_stuff.zip here].
+
In each case, the attraction or repulsion should happen in the direction of the light (using the light vector), and should attenuate with the square distance from the light source, so that those vertices closer to the light source are affected more than those farther away. Note that the directional light does not have a position - implement the effect so that only polygons facing the light source are affected by it (by comparing the surface normals to the incoming light vector). Implement this effect as a GLSL vertex shader.
  
We provide a [[Media:shader-class.zip|sample shader class]] and [[Media:shaders.zip|three sample combinations of vertex and fragment shaders]] for you to familiarize yourself with GLSL shader programming. For this part of the project, extend the <tt>diffuse_shading</tt> shader to perform per-pixel Phong shading. The shader should use the properties of your light sources and materials. These properties can be accessed in the shader through the predefined <tt>gl_LightSource</tt> and <tt>gl_FrontMaterial</tt> variables.
+
The color shift should be done by about 10%, and must be strong enough so that it is obvious. The color shift '''must''' be implemented on a per pixel basis, which means that you will need to implement it as a GLSL fragment shader.  
  
* Create GLSL vertex and fragment shaders for the point light from Part 1 ('''15 points''').
+
You will need to demonstrate the described effect for the 3D objects you used in the prior homework projects: specifically: cube, dragon, bunny and head. Be sure to make your objects big enough that they almost fill the OpenGL window, either by using your code from project 2, or by using fixed scale factors.
* Create GLSL vertex and fragment shaders for the spot light from Part 1 ('''15 points''').
+
* Create GLSL vertex and fragment shaders with support for both light sources concurrently ('''10 points'''). For this you will have to merge the code of the two shader programs into one shader program. You would determine the final color by averaging the contributions of the light sources (cumulative_light = (light_a + light_b)/2).
+
* Demonstrate the scene with the two spheres from Part 1 with optional per-pixel shading: add support for the 'g' key to toggle your GLSL shaders on or off, to demonstrate the difference between OpenGL's built-in (per vertex) shading and your custom per-pixel shading. ('''10 points''')
+
  
'''Notes'''
+
For Windows and Linux users, in order to use OpenGL extensions, you should [http://elf-stone.com/glee.php download GLee] and add the glee.h and glee.c files to your project files, or tell the linker to link with the GLee library (glee.lib or glee.dll for Windows, or libglee.a/libglee.so for Linux). OSX users will not need GLee, as OpenGL extensions are available by default. Note: The link on the website seems to be down, so you can download glee.h and glee.c from [https://www.dropbox.com/sh/de5yhhoq7nccxm9/wMVYsKwqRu/glee here].
* While most CSE lab computers do, some older computers or simpler graphics cards do not support GLSL. Be aware that this might be a problem with your personal computer.
+
* It is more efficient to compute the reflection vector in the vertex shader. Then you pass it to the fragment shader as a <tt>varying</tt> parameter. OpenGL will automatically interpolate the vector at each pixel. However, you will have to re-normalize it in the fragment shader to make sure it is a unit vector.
+
  
Here are a few URLs with tutorials on how to write GLSL shader code. The tutorial at the first URL contains detailed instructions for how to do per-pixel shading for point and spot lights, including sample shader code.
+
We provide a [[Media:shader-class.zip|sample shader class]] and [[Media:shaders.zip|three sample combinations of vertex and fragment shaders]] for you to familiarize yourself with GLSL shader programming. For this exercise, extend the <tt>diffuse_shading</tt> shader to implement the desired effects.  
  
* [http://www.lighthouse3d.com/opengl/glsl/ Lighthouse3D GLSL tutorials]
+
If the respective light is off, the attraction/repulsion and color shifting effects need to stop.
* [http://www.clockworkcoders.com/oglsl/tutorials.html Clockworkcoders GLSL tutorials]
+
* [http://www.khronos.org/files/opengl43-quick-reference-card.pdf GLSL quick reference]
+
* [http://www.opengl.org/documentation/glsl/ GLSL reference documentation]
+
  
==4. Extra Credit: Disco Dragon (10 Points)==
+
Support a so far unused keyboard key to toggle the functionality of this part of the assignment on/off.
 +
 
 +
You will get points for the following things:
 +
 
 +
* A GLSL vertex shader with at least one attraction/repulsion effect ('''10 points''').
 +
* A GLSL fragment shader with at least one color shifting effect ('''10 points''').
 +
* Correct effect of the directional light ('''5 points''').
 +
* Correct effect of the point light ('''5 points''').
 +
* Correct effect of the spot light. The spot needs to be narrow enough to only affect a small part of the surface of the models ('''5 points''').
 +
* Each of the 6 3D models needs to work with the shaders and you will need to be able to switch between the models with the keyboard. The models need to be big enough to roughly fill the OpenGL window. The light sources need to rotate like in exercise 2. ('''5 points''')
 +
 
 +
'''Notes'''
 +
* While most CSE lab computers do, some older computers or simpler graphics cards do not support GLSL. Be aware that this might be a problem with your personal computer.
 +
* Here are a few URLs with tutorials on how to write GLSL shader code.
 +
** [http://www.lighthouse3d.com/opengl/glsl/ Lighthouse3D GLSL tutorials]
 +
** [http://www.clockworkcoders.com/oglsl/tutorials.html Clockworkcoders GLSL tutorials]
 +
** [http://www.khronos.org/files/opengl44-quick-reference-card.pdf GLSL quick reference]
 +
** [http://www.opengl.org/documentation/glsl/ GLSL reference documentation]
  
Create a 3D scene with a dragon which is illuminated by colorful lights.
+
==4. Extra Credit (10 Points)==
  
Load [[media:dragon.zip | this OBJ file with the Stanford Dragon]], which contains normals in addition to vertex coordinates and triangle connectivity, into your software program from parts 1 and 2. The [http://en.wikipedia.org/wiki/Wavefront_.obj_file Wikipedia page for OBJ files] describes the data format. Modify your OBJ reader from homework assignment 2 to parse this file '''(2 points)'''. If you are curious about the Stanford 3D model repository, you will find more information about it [http://graphics.stanford.edu/data/3Dscanrep/ here].
+
Create a simple water reflection effect for your 3D models, similar to that in the picture below:
  
Take a close look at the lighting of the dragon's surface to make sure that you read in the normals correctly:
+
[[Image:water-reflection.jpg]]
  
<center>
+
This effect does not need to be demonstrated concurrently with the shader effect from part 3, but it would be great if you could switch to it with a keyboard key.
[[image:dragon.jpg]]
+
</center>
+
  
Add keyboard support to switch between the spheres and the dragon by putting the spheres on the 's' key, and the dragon on 'd'. Both lighting approaches (fixed function and shader-based) need to work with the dragon. '''(2 point)'''
+
You will need to split the OpenGL window in two halves: the upper half shows the 3D model as you normally do, the lower half shows the same model, mirrored along the y axis and with a water-like reflection effect. You can constrain rendering for each of the halves of the screen by calling glViewPort before rendering each of the images, with different y coordinates and half the usual height.
  
Add a large, flat ground plane to the scene by creating a large OpenGL quad, and place it under the dragon's feet in its coordinate system, so that it looks like the dragon sits on it. '''(1 point)'''
+
The approach for the effect is to write a vertex shader, which (pseudo-)randomly offsets each vertex in an oscillating way using sin curves, shifting the vertices around the screen plane. Alternatively, you can use a different approach if you prefer, even frame-buffer based approaches which are vertex agnostic are acceptable.
  
Add at least one additional light source to the scene. Add on/off toggle support for each additional light with the number keys ('3', '4', '5', etc.), and support them with your mouse control routines like the lights in part 1. '''(2 points)'''
+
You need to be able to rotate the 3D model as usual, and the water effect must constantly update the screen with slightly different offsets so that it looks like the water's ripples cause the effect.
  
Modify the light and material parameters of the scene to illuminate the dragon in an interesting way. At least one of your spot lights needs to automatically move around the dragon, creating a moving light spot on its surface. The light can move in a circle, or any other way of your choice. Add keyboard support for the 'a' key to toggle the animation on or off. '''(3 points)'''
+
GLSL does not have a native random function, but you can use the following popular pseudo-random number generator, which generates numbers based on two input values. The same input values yield the same random numbers, so you should seed the function with something like the current time, which you pass into the shader via a uniform variable, which your GLUT program updates with every frame.
  
-->
+
<pre>
 +
float rand(vec2 co)
 +
{
 +
  return fract(sin(dot(co.xy,vec2(12.9898,78.233))) * 43758.5453);
 +
}
 +
</pre>

Latest revision as of 23:39, 30 October 2013

Contents

Project 4: Light and Shade

This project is on OpenGL lighting and shading, and includes GLSL shader programs.

This project is due on Friday, November 1st at 1:30pm. It will be discussed in Center Hall 105 on Monday, October 28th at 3:00pm.

Note that GLSL shaders, which are needed for part 2 of the assignment, will be covered in class on Tuesday, October 22nd.

1. Mouse Control (20 Points)

Start by reviving your application from assignment 2: you will need to be able to display the cube, as well as the following three 3D models into your application and display them at reasonable sizes (screen filling). The function keys should switch between the models.

These are the models you need to be able to load, you will have to unzip them to get at the OBJ files. Note that some of them are different files than before, as we now need files with normals. The OBJ reader we gave you in project 2 already parses normals.

Note: Prior to Oct 29, there were bunny and head files which did not work with your obj reader. Please replace those with the files above.

You are welcome but not required to support the keyboard commands from assignment 2 to move around the models. However, you will need to add mouse control, which will allow rotating the model about the center of your OpenGL window, as well as scaling the model up and down. The left mouse button should be used for rotation, the right mouse button should zoom in and out when the mouse is moved up or down while it is pressed.

This video shows how the trackball-like rotation should work. We provide sample code for the trackball rotation. You will need to adapt it to the syntax of your matrix and vector classes and get it to work within your application.

If you cannot get the sample trackball code to work, the following description of the algorithm might help you.

The figure below illustrates how to translate mouse movement into a rotation axis and angle. m0 and m1 are consecutive 2D mouse positions. These positions define two locations v and w on a 3D virtual sphere that fills the rendering window. Use their cross product as the rotation axis a = v x w, and the angle between v and w as the rotation angle.

Trackball.jpg

Horizontal mouse movement exactly in the middle of the window should result in a rotation just around the y-axis. Vertical mouse movement exactly in the middle of the window should result in a rotation just around the x-axis. Mouse movements in other areas and directions should result in rotations about an axis a which is not parallel to any single coordinate axis, and is determined by the direction the mouse is moved in.

Once you have calculated the trackball rotation matrix for a mouse drag, you will need to multiply it with the object to world transformation matrix for the model or the light source you are moving.

To access the mouse x and y coordinates, you will need to use GLUT's callback functions glutMouseFunc(), which gets called when you press a mouse button, and glutMotionFunc(), which gets called constantly while you hold the button down and move the mouse. Note that successive trackball rotations must build on previous ones; at no point should the model snap back to a previous or default position.

2. OpenGL Lighting and Shading (40 points)

Write classes to manage light and material properties (Light and Material). As a starting point, refer to the relevant sections in Chapter 5 of the OpenGL Programming Guide, as well as the OpenGL Lighting FAQ.

Associate material properties with each of the four 3D model files: two of them should be shiny, and the other two should be shiny and diffuse - you choose which. Use colors other than white. (10 points)

Create three light sources: one directional light, one point light and one spot light. The spot light should always point towards the center of the OpenGL window. Give them initial positions and colors. Each of them must have a different position and color. The spot light should have a spot width narrow enough so that it only illuminates a small part of the surface of the models. Toggle each of them on and off with one of the number keys: 1, 2, and 3. Rotate those light sources which are on with the 3D model.

Add a freeze mode for the 3D model and toggle it with the 'm' key: when it is enabled, the model will not respond to mouse control commands and instead stay in its last orientation and size. In this mode only the enabled light sources rotate and zoom in and out.

Notes:

  • OpenGL multiplies light position and direction with the Modelview matrix when they are set. Therefore, you need to modify the Modelview matrix with your mouse control routines to rotate the light sources, independently for each light source.
  • To ascertain that the normals of your 3D models will survive zoom operations correctly, you should use the following OpenGL command: glEnable(GL_NORMALIZE).
  • By default, OpenGL uses a simplified model for the calculation of the highlights. For a more realistic model add this command to your code: glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE).

3. GLSL Shader Programs (40 Points)

Imagine that each of your light sources has a force field, which attracts or repulses the vertices of your geometry, and shifts their color.

  • The directional light should repulse the vertices, and do not cause a color shift.
  • The point light should repulse the vertices as well, and shift their color towards red.
  • The spot light should attract the vertices, but only if they fall within its spot, and shift their color towards green.

In each case, the attraction or repulsion should happen in the direction of the light (using the light vector), and should attenuate with the square distance from the light source, so that those vertices closer to the light source are affected more than those farther away. Note that the directional light does not have a position - implement the effect so that only polygons facing the light source are affected by it (by comparing the surface normals to the incoming light vector). Implement this effect as a GLSL vertex shader.

The color shift should be done by about 10%, and must be strong enough so that it is obvious. The color shift must be implemented on a per pixel basis, which means that you will need to implement it as a GLSL fragment shader.

You will need to demonstrate the described effect for the 3D objects you used in the prior homework projects: specifically: cube, dragon, bunny and head. Be sure to make your objects big enough that they almost fill the OpenGL window, either by using your code from project 2, or by using fixed scale factors.

For Windows and Linux users, in order to use OpenGL extensions, you should download GLee and add the glee.h and glee.c files to your project files, or tell the linker to link with the GLee library (glee.lib or glee.dll for Windows, or libglee.a/libglee.so for Linux). OSX users will not need GLee, as OpenGL extensions are available by default. Note: The link on the website seems to be down, so you can download glee.h and glee.c from here.

We provide a sample shader class and three sample combinations of vertex and fragment shaders for you to familiarize yourself with GLSL shader programming. For this exercise, extend the diffuse_shading shader to implement the desired effects.

If the respective light is off, the attraction/repulsion and color shifting effects need to stop.

Support a so far unused keyboard key to toggle the functionality of this part of the assignment on/off.

You will get points for the following things:

  • A GLSL vertex shader with at least one attraction/repulsion effect (10 points).
  • A GLSL fragment shader with at least one color shifting effect (10 points).
  • Correct effect of the directional light (5 points).
  • Correct effect of the point light (5 points).
  • Correct effect of the spot light. The spot needs to be narrow enough to only affect a small part of the surface of the models (5 points).
  • Each of the 6 3D models needs to work with the shaders and you will need to be able to switch between the models with the keyboard. The models need to be big enough to roughly fill the OpenGL window. The light sources need to rotate like in exercise 2. (5 points)

Notes

4. Extra Credit (10 Points)

Create a simple water reflection effect for your 3D models, similar to that in the picture below:

Water-reflection.jpg

This effect does not need to be demonstrated concurrently with the shader effect from part 3, but it would be great if you could switch to it with a keyboard key.

You will need to split the OpenGL window in two halves: the upper half shows the 3D model as you normally do, the lower half shows the same model, mirrored along the y axis and with a water-like reflection effect. You can constrain rendering for each of the halves of the screen by calling glViewPort before rendering each of the images, with different y coordinates and half the usual height.

The approach for the effect is to write a vertex shader, which (pseudo-)randomly offsets each vertex in an oscillating way using sin curves, shifting the vertices around the screen plane. Alternatively, you can use a different approach if you prefer, even frame-buffer based approaches which are vertex agnostic are acceptable.

You need to be able to rotate the 3D model as usual, and the water effect must constantly update the screen with slightly different offsets so that it looks like the water's ripples cause the effect.

GLSL does not have a native random function, but you can use the following popular pseudo-random number generator, which generates numbers based on two input values. The same input values yield the same random numbers, so you should seed the function with something like the current time, which you pass into the shader via a uniform variable, which your GLUT program updates with every frame.

float rand(vec2 co)
{
  return fract(sin(dot(co.xy,vec2(12.9898,78.233))) * 43758.5453);
}