Water ripple normal map

Water ripple normal map

Tutorial 16: Small Body Water

This DirectX 10 terrain tutorial will cover how to implement small body water using HLSL and C++. The code in this tutorial builds on the previous terrain tutorials.

To implement small body water (lakes, rivers, ponds, swamps, and anything else that doesn’t have big waves) we use a refractive and reflective rendering system. We render a refraction (everything under the water) and render a reflection (everything above the water) and then combine the results. If you have gone over the water tutorial in the DirectX tutorial section then you will understand these concepts. If you haven’t read that tutorial then I suggest you review it first before proceeding as we simply expand on it here and add more features.

We will begin with a basic terrain scene. We require terrain for the refraction and something such as sky for the reflection.

We will also need a normal map for the water ripple effect. A gaussian blurred height map and the Nvidia normal map filter for Photoshop can create something like the following:

We then create a single quad with a radius large enough to cover the area of the water. We will be tiling the normal map texture over the quad so we don’t need it subdivided.

Next we will render the scene using the reflection shader but use an inverted clip plane so we are rendering everything underneath the water to create a refraction. This is all rendered to a render to texture so we can then apply it to the water quad using projective texturing based on the view point of the camera. We also perturb the refraction texture sampling by the water normal map to give us the ripple effect.

As well when we tile the normal map over the water quad we do it two separate times using different texture coordinates. For example we may tile it ten times over the water and then tile it again but just five times. We then combine the two separately tiled normal map results to give an animated look to the ripples instead of just a single rotating texture.

And finally we add a tint color to the refraction so that it looks like colored water instead of purely clear water with ripples. The following image is what the water refraction ends up looking like:

Note that a lot of engines will stop at that point. It is very expensive to render the scene to texture since we basically are rendering the scene twice. This cuts the fps in half whenever water needs to be drawn! There aren’t really a lot of techniques other than to not render to texture when the water isn’t visible that can speed this up unfortunately.

However we are going to proceed to make the effect look better. We will now render the scene yet again using the reflection shader but using a clip plane that renders everything above the water to give us a reflection of our scene. We render the reflection to a render to texture object and then project it onto the water quad from the view point of the camera. We also perturb the sampling of the render to texture by the water normal map. Rendering just the reflection looks like the following:

With the refraction, reflection, and the regular 3D scene we have now ended up drawing the scene three times per frame. This cuts your fps down to one third of the original speed. Some optimizations are that you can render a reflection twice a second instead of every frame, but it depends on the maximum speed that you will ever move at over the water. Some engines also use just a single texture of a sky that never changes. There are different things you can do but it depends on how important the reflection is to the scene.

With both the refraction and the reflection rendered to textures we can now combine them. One of the nice ways to combine the two textures is to use what is known as the Fresnel factor. This is the effect that as you get closer to the water it becomes more transparent (refraction is rendered more), and as you get further away the reflection becomes stronger and it is no longer as easy to see into the water (reflection is rendered more). In this tutorial I have created a simple fresnel factor that is based only on height. So the higher up you are the water is more reflective, and the closer you get to the water it becomes more refractive. Some engines will use a far more sophisticated frensel calculation and take into account the distance from the water, the depth of the water at each pixel, and so forth. It just depends how realistic you want to make the effect look.

The combined result with the fresnel factor looks like the following:

As you can see the reflection added a lot of color to the result as well as the reflected clouds and pieces of the terrain.

The final addition to the water effect is adding specular reflection for where the directional sun light reflects off the water. We will calculate the specular against the dual tiled water normal map so that the specular comes off just the animated water ripples. Doing so gives us the final resulting scene:

Once again this is a fairly expensive effect, you may want to just stop at the refraction point. But if you can spare the extra cycles then the full effect is nice.

To begin the code section we will start by looking at the modified CameraClass.

Читайте также:  Хочу инвестировать деньги с чего начать

The CameraClass has been modified so that it can now generate reflection view matrices.

We have added functions to generate and retrieve the reflection view matrix.

There is also an additional matrix for the reflection view.

This is the new function that is used for generating the reflection view matrix. The only difference between the regular view matrix and the reflection one is that we invert the Y position based on the height of the plane, and we also invert the pitch.

There is also a new function to retrieve the reflection view matrix.

The reflection HLSL shader is just the terrain HLSL shader with a clip plane added, otherwise it is identical.

The ReflectionShaderClass is also the same as the TerrainShaderClass except that it has clip plane related settings.

WaterClass is a new class that is used to hold the geometry for the water quad and the shader related settings and files.

The Initialize function takes as inputs the DX10 device, the file name of the water normal map, the height of the water, and the radius of the water.

First we store the water height. After that we create the geometry for the water quad and then load the normal map for the water.

Next we set all the shader related settings. These should actually be input parameters but I have placed them here for now so that they are straight forward for editing as you learn how each of them affects the shader effect.

Each frame we will animate the rotation of the water normal map to simulate moving water ripples.

We manually create a quad here. It doesn’t need to be a high poly object since we are going to tile the water normal map over the surface of the quad.

The texture that is loaded here is the normal map for the water.

The HLSL water shader here is very similar to the one in the DirectX tutorials section. All we have done is add some additional effects.

Calculate the vertex position as usual.

Calculate the refraction and reflection view matrices the same as before also.

Calculate the camera’s view direction for fresnel and specular calculations.

Calculate two different tiling texture coordinates for the water normal map.

Translate the two texture coordinates by the water translation amount.

Sample the water normal map two times using the two different texture sampling coordinates.

Now combine the two normal map results to get an animated water ripple effect instead of just a single rotated normal map ripple.

Calculate the sampling coordinates for the refraction and reflection and then sample the textures as we did previously.

Add a water color tint to the refraction.

Create just a height based vector for the fresnel calculation.

Calculate the fresnel factor and then combine the refraction and reflection values based on the fresnel factor.

Finally do a specular light calculation using the water normals and add it to the final color result to get the specular effect on just the water ripples.

The WaterShaderClass is the same as it was in the DirectX water tutorial except that it contains variables for the new settings such as specular, texture tiling, and refraction tint.

Add headers for the render to texture, reflection shader, water, and water shader.

There are new objects for the water related rendering.

Setup render to textures for the refraction and reflection of the scene.

Create the reflection shader for rendering the refraction and the reflection.

Setup the WaterClass and WaterShaderClass objects.

The WaterClass object requires frame processing to translate the water normal map sampling.

There are three render steps. First render the refraction of the scene to a texture. Next render the reflection of the scene to a texture. And then finally render the entire scene using the refraction and reflection textures.

Here is where we render the refraction of the scene to a render to texture object. Note we only need to render the terrain as nothing else is below the water other than terrain. We use the clipping plane and then render a refraction of everything under the water using the reflection shader. Note also that we have to offset the sampling of the refraction otherwise we get black spots along the sides of the refraction from sampling outside of the texture.

Here is where we render the reflection of the scene to a texture. We render everything above the water to a texture.

Now we render the scene to the back buffer. Everything is rendered as normal except for the water which uses the refraction and reflection render to texture objects as well as the other water related shader parameters.

We can now render a fairly realistic water effect for small body water that doesn’t require any large waves.

To Do Exercises

1. Compile and run the program. Move around using the arrow keys, A, Z, and PgUp and PgDn. Press escape to quit.

2. Modify the shader input values (such as the refraction tint) to see how they change the water effect.

3. Modify the water shader to see each piece of the effect output by itself. For example return only the refraction color, and then return only the reflection color.

4. Optimize the reflection portion using one of the methods described (such as updating the reflection once a second only).

5. Combine this tutorial with the Glass and Ice DirectX tutorial. Render a snowy terrain and change the water to be ice instead.

Source Code and Data Files: terdx10src16.zip

Читайте также:  Майнинг с обычного компьютера

Источник

Water ripple normal map

Tutorial 16: Small Body Water

This DirectX 11 terrain tutorial will cover how to implement small body water using HLSL and C++. The code in this tutorial builds on the previous terrain tutorials.

To implement small body water (lakes, rivers, ponds, swamps, and anything else that doesn’t have big waves) we use a refractive and reflective rendering system. We render a refraction (everything under the water) and render a reflection (everything above the water) and then combine the results. If you have gone over the water tutorial in the DirectX tutorial section then you will understand these concepts. If you haven’t read that tutorial then I suggest you review it first before proceeding as we simply expand on it here and add more features.

We will begin with a basic terrain scene. We require terrain for the refraction and something such as sky for the reflection.

We will also need a normal map for the water ripple effect. A gaussian blurred height map and the Nvidia normal map filter for Photoshop can create something like the following:

We then create a single quad with a radius large enough to cover the area of the water. We will be tiling the normal map texture over the quad so we don’t need it subdivided.

Next we will render the scene using the reflection shader but use an inverted clip plane so we are rendering everything underneath the water to create a refraction. This is all rendered to a render to texture so we can then apply it to the water quad using projective texturing based on the view point of the camera. We also perturb the refraction texture sampling by the water normal map to give us the ripple effect.

As well when we tile the normal map over the water quad we do it two separate times using different texture coordinates. For example we may tile it ten times over the water and then tile it again but just five times. We then combine the two separately tiled normal map results to give an animated look to the ripples instead of just a single rotating texture.

And finally we add a tint color to the refraction so that it looks like colored water instead of purely clear water with ripples. The following image is what the water refraction ends up looking like:

Note that a lot of engines will stop at that point. It is very expensive to render the scene to texture since we basically are rendering the scene twice. This cuts the fps in half whenever water needs to be drawn! There aren’t really a lot of techniques other than to not render to texture when the water isn’t visible that can speed this up unfortunately.

However we are going to proceed to make the effect look better. We will now render the scene yet again using the reflection shader but using a clip plane that renders everything above the water to give us a reflection of our scene. We render the reflection to a render to texture object and then project it onto the water quad from the view point of the camera. We also perturb the sampling of the render to texture by the water normal map. Rendering just the reflection looks like the following:

With the refraction, reflection, and the regular 3D scene we have now ended up drawing the scene three times per frame. This cuts your fps down to one third of the original speed. Some optimizations are that you can render a reflection twice a second instead of every frame, but it depends on the maximum speed that you will ever move at over the water. Some engines also use just a single texture of a sky that never changes. There are different things you can do but it depends on how important the reflection is to the scene.

With both the refraction and the reflection rendered to textures we can now combine them. One of the nice ways to combine the two textures is to use what is known as the Fresnel factor. This is the effect that as you get closer to the water it becomes more transparent (refraction is rendered more), and as you get further away the reflection becomes stronger and it is no longer as easy to see into the water (reflection is rendered more). In this tutorial I have created a simple fresnel factor that is based only on height. So the higher up you are the water is more reflective, and the closer you get to the water it becomes more refractive. Some engines will use a far more sophisticated frensel calculation and take into account the distance from the water, the depth of the water at each pixel, and so forth. It just depends how realistic you want to make the effect look.

The combined result with the fresnel factor looks like the following:

As you can see the reflection added a lot of color to the result as well as the reflected clouds and pieces of the terrain.

The final addition to the water effect is adding specular reflection for where the directional sun light reflects off the water. We will calculate the specular against the dual tiled water normal map so that the specular comes off just the animated water ripples. Doing so gives us the final resulting scene:

Once again this is a fairly expensive effect, you may want to just stop at the refraction point. But if you can spare the extra cycles then the full effect is nice.

Читайте также:  Финансовая структура центра инвестиций

To begin the code section we will start by looking at the modified CameraClass.

The CameraClass has been modified so that it can now generate reflection view matrices.

We have added functions to generate and retrieve the reflection view matrix.

There is also an additional matrix for the reflection view.

This is the new function that is used for generating the reflection view matrix. The only difference between the regular view matrix and the reflection one is that we invert the Y position based on the height of the plane, and we also invert the pitch.

There is also a new function to retrieve the reflection view matrix.

The reflection HLSL shaders are just the terrain HLSL shaders with a clip plane added, otherwise they are identical.

The ReflectionShaderClass is also the same as the TerrainShaderClass except that it has clip plane related settings.

WaterClass is a new class that is used to hold the geometry for the water quad and the shader related settings and files.

The Initialize function takes as inputs the DX11 device, the file name of the water normal map, the height of the water, and the radius of the water.

First we store the water height. After that we create the geometry for the water quad and then load the normal map for the water.

Next we set all the shader related settings. These should actually be input parameters but I have placed them here for now so that they are straight forward for editing as you learn how each of them affects the shader effect.

Each frame we will animate the rotation of the water normal map to simulate moving water ripples.

We manually create a quad here. It doesn’t need to be a high poly object since we are going to tile the water normal map over the surface of the quad.

The texture that is loaded here is the normal map for the water.

The HLSL water shaders here are very similar to the one in the DirectX tutorials section. All we have done is add some additional effects.

Calculate the vertex position as usual.

Calculate the refraction and reflection view matrices the same as before also.

Calculate the camera’s view direction for fresnel and specular calculations.

Calculate two different tiling texture coordinates for the water normal map.

Translate the two texture coordinates by the water translation amount.

Sample the water normal map two times using the two different texture sampling coordinates.

Now combine the two normal map results to get an animated water ripple effect instead of just a single rotated normal map ripple.

Calculate the sampling coordinates for the refraction and reflection and then sample the textures as we did previously.

Add a water color tint to the refraction.

Create just a height based vector for the fresnel calculation.

Calculate the fresnel factor and then combine the refraction and reflection values based on the fresnel factor.

Finally do a specular light calculation using the water normals and add it to the final color result to get the specular effect on just the water ripples.

The WaterShaderClass is the same as it was in the DirectX water tutorial except that it contains variables for the new settings such as specular, texture tiling, and refraction tint.

Add headers for the render to texture, reflection shader, water, and water shader.

There are new objects for the water related rendering.

Setup render to textures for the refraction and reflection of the scene.

Create the reflection shader for rendering the refraction and the reflection.

Setup the WaterClass and WaterShaderClass objects.

The WaterClass object requires frame processing to translate the water normal map sampling.

There are three render steps. First render the refraction of the scene to a texture. Next render the reflection of the scene to a texture. And then finally render the entire scene using the refraction and reflection textures.

Here is where we render the refraction of the scene to a render to texture object. Note we only need to render the terrain as nothing else is below the water other than terrain. We use the clipping plane and then render a refraction of everything under the water using the reflection shader. Note also that we have to offset the sampling of the refraction otherwise we get black spots along the sides of the refraction from sampling outside of the texture.

Here is where we render the reflection of the scene to a texture. We render everything above the water to a texture.

Now we render the scene to the back buffer. Everything is rendered as normal except for the water which uses the refraction and reflection render to texture objects as well as the other water related shader parameters.

We can now render a fairly realistic water effect for small body water that doesn’t require any large waves.

To Do Exercises

1. Compile and run the program. Move around using the arrow keys, A, Z, and PgUp and PgDn. Press escape to quit.

2. Modify the shader input values (such as the refraction tint) to see how they change the water effect.

3. Modify the water shader to see each piece of the effect output by itself. For example return only the refraction color, and then return only the reflection color.

4. Optimize the reflection portion using one of the methods described (such as updating the reflection once a second only).

5. Combine this tutorial with the Glass and Ice DirectX tutorial. Render a snowy terrain and change the water to be ice instead.

Источник

Оцените статью
Adblock
detector