CS 455 Lecture 23 – Water
- what ?s
- homework 4
- forward differencing
As a lab exercise:
- Sync with the class repository to get the
waterstarter project. Run it to find some very disappointing water. We’re going to do a couple of things to make it look better: 1) add environment mapping to make it reflect the skybox and 2) perturb its normals using a 3D noise texture.
- Let’s start with environment mapping. Recall the concepts behind this technique: in world space, we shoot a vector from the eye to the vertex, and reflect that vector around the vertex’s normal. That reflected vector serves as a texture coordinate into a cube map. Last time, we implemented the reflection in the vertex shader. This time, our normals are going to be retrieved from a noise texture in the fragment shader. In the vertex, however, we’ll need to output the vertex’s world position. Add a varying for
fposition_world. Compute its value in the vertex shader.
- In the fragment shader, add a
uniformfor the camera’s world position. Upload it in
OnDraw. Compute the incident vector.
- Compute the reflection vector by reflecting the incident vector about the water’s normal. For now, assume the normal is the y-axis. This will change soon.
- Add a
uniformfor the skybox texture in the fragment shader and in
OnDraw. A skybox texture has already been made; it’s called
- Look up the color in the skybox using the reflection vector and the
textureCubefunction. Assign this color to the fragment. How do things look?
- Now let’s perturb the surface. We’re not going to actually move any geometry. We’re simply going to derive the normals across the water’s surface from a slice of a 3D noise texture. As time passes, we’ll read different slices of the texture, producing a rippling effect. Start by adding a
uniformfor the noise texture to the fragment shader and
OnDraw. A texture object has already been made; it’s called
- For looking up noise intensities, we’ll need a 3D texture coordinate. Two of these we can get from the 2D texture coordinate vertex attribute. Add a
varyingto get these values in the fragment shader. The third we can get from a clock reading. Add a
timeuniform in the fragment shader and in
- We are not using the noise texture for color. We are using it as a heightmap; specifically, we are using it to calculate normals. How do we determine the normal at a given location? Find two tangent vectors and then take their cross product. How do we find two tangent vectors? Recall that a tangent vector lies across a surface, running parallel to the surface’s general orientation. We can find these parallel vectors by a technique called forward differencing. First, take three intensity readings:
here = lookup height at texture coordinates right = lookup height at here + nudge right above = lookup height at here + nudge up
- With these three values in hand, we can determine the tangent vectors by computing their differences on all three dimensions:
tangentRight = [1, right - here, 0] tangentAbove = [0, above - here, 1]
vec3s. Compute their cross product to produce
- Alter the reflection vector calculate to use
normal_worldinstead of the fixed y-axis.
- How does it look? Try some different heightmap series:
- Send me a screenshot.