Home   Donators   Contact Us       

<< Previous Tutorial     Next Tutorial >>

Tutorial 18 - Bump mapping
Textures courtesy of JHT's Planetary Pixel Emporium.
www.planetpixelemporium.com



Theory

There are many different approaches towards bump mapping that can be used to give your textures depth. In this introduction tutorial to bump mapping, we will use height maps to pre-emboss your texture with bumps. Once your texture is embossed with a height map, the embossed texture can be used like a normal texture map, without requiring any additional processing time during rendering.

For more information on texture mapping, have a look at Tutorial 5 - Texture mapping and Tutorial 15 - Textures revisited.

Pre-emboss bump mapping is easy to implement, provides fast rendering and gives a very realistic end result. Pre-emboss bump mapping do not take light source positions and parameters into account during real-time rendering, and are therefore, not 100% correct from a lighting perspective. The additional rendering speed that is obtained with this rendering technique however, more than compensates for the compromise on technical correctness.

To apply emboss bump mapping to a texture we need two images, a texture bitmap and a height map. The texture bitmap defines the RGBA colors of the texture and the height map specifies the height of each pixel in the texture. The images below respectively illustrates a possible texture bitmap and height map that can be used for an earth model.

    

On the height map, white colors indicate high positions and black indicates low positions. E.g. Mount Everest is represented by a white color, while the sea level is represented by a black color.

IMPORTANT: It is best practice is to ensure that your height map has the exact same dimensions (e.g. width and height) as the texture bitmap.

To emboss our texture bitmap with a given height map is very straightforward. We simply scan the bitmap pixels from left-to-right, top-to-bottom. At each pixel, we calculate its new color using by using the height map pixel colors directly to the right and bottom of the current pixel coordinate. To illustrate the algorithm, imagine our texture bitmap and height map is the 5x5 pixel bitmaps as shown below.

Using the above images as reference, our emboss algorithm starts at pixel t0 and reads the pixel color values in the height map at (x,y) and (x+1,y+1), that would be pixels h0 and h6 respectively.

The color of pixel t0 is now adjusted with the following formula:

t0 = t0 + [ (h0 - h6) × 2 ]

if (t0 > 1) then t0 = 1
if (t0 < 0) then t0 = 0

Let's inspect the above pseudo algorithm more closely. t0, h0 and h6 can be any value between 0 (black) and 1 (white). (h0 - h6) calculates the difference in height between the two pixels in the height map. This difference is then multiplied by 2 to give it a larger weight. We now simply add the weighted height difference to the texture bitmap's pixel. The "if" statements clamps our new pixel color value between 0 and 1.

The process above is repeated for each pixel in the texture bitmap. When we reach a border, we simple wrap pixels (e.g. for t4, the corresponding height map pixels to use are h4 and h5). The final embossed texture bitmap is shown below.

The simple pseudo algorithm described above is an easy and fast way to apply bump mapping to textures, by using height maps and an embossing technique. When working with textures and height maps, the separate colors, red, green and blue, need to be taken into account when calculating new pixel color values.

Tutorial Steps
Tutorial created with Real Studio 2011 Release 4.3.
1. Open Real Studio.
2. Choose the "Desktop" project template.
3. Tick the MaximizeButton property of Window1.
4. Add an OpenGLSurface control to Window1.
5. Resize and position OpenGLSurface1 to fill the whole form.
6. Tick the LockRight and LockBottom properties of OpenGLSurface1.
7. Save your project.
8. Download the following file and extract the content next to your project file:
9. Import the classes and modules contained in the archive file into your new project file. (Select File > Import... from the main menu)
10. Download the following file and extract the content next to your project file:
11. Import the bitmap textures into your new project file and rename the images as follow:
  • earthtext.png: imgEarthText
  • earthbump.png: imgEarthBump
12. Add a property named "MousePrevX" of type Integer to Window1.
13. Add a property named "MousePrevY" of type Integer to Window1.
14. Add a property named "Scene" of type R3Scene to Window1.
15. Add the following code to the Open event of Window1:
Dim model As R3Model ' temporary model object
Dim light As R3LightSource  ' light source
Dim cam As R3Camera ' camera used in our scene

me.Maximize ' maximize the window
me.MouseCursor = REALbasic.System.Cursors.StandardPointer ' set mouse cursor

' instantiate the Scene object

Scene = new R3Scene
Scene.BackgroundColor.SetValue(0, 0, 0) ' set background color

' load textures used in scene

Scene.Texture.Append new R3Texture(imgEarthText, imgEarthBump) ' earth texture with bump map
Scene.Texture.Append new R3Texture(imgEarthText) ' earth texture with bump map

' add sun

light = new R3LightSource
light.Position.SetValue(-10, 0, 3)
light.Ambient.SetValue(0, 0, 0, 1)
light.Diffuse.SetValue(1, 1, 1, 1)
light.Specular.SetValue(1, 1, 1, 1)
Scene.LightSource.Append light

' add camera

cam = new R3Camera
cam.DollyOut 3 ' move back so that we can get the model in our view
Scene.Camera.Append cam

Scene.ActiveCamera = 0 ' set the index of the active camera

' instantiate earth model

model = R3_Tut00018Earth
model.Scale.SetValue 1, 0.9, 1
model.Rotation.Rotate(20, 0, 0)
model.Rotation.Rotate(0, -95, 0)
Scene.AppendModel model 

OpenGLSurface1.Render ' refresh OpenGL surface
16. Add the following code to the Paint event of Window1:
OpenGLSurface1.Render ' refresh the OpenGL surface
17. Add the following code to the Close event of Window1:
Scene = nil ' remove the scene object from memory
18. Add the following code to the Open event of OpenGLSurface1:
R3_OGLInitialize ' initalize OpenGL environment
19. Add the following code to the Render event of OpenGLSurface1:
' is the scene object instantiated?
if Scene <> nil then

' render the modal normally
R3_OGLRenderScene Scene

end if
20. Add the following code to the Resized event of OpenGLSurface1:
' set the viewport rectangle

OpenGL.glViewport 0, 0, OpenGLSurface1.Width, OpenGLSurface1.Height

' set up the perspective projection settings

OpenGL.glMatrixMode OpenGL.GL_PROJECTION
OpenGL.glLoadIdentity
OpenGL.gluPerspective 60.0, OpenGLSurface1.Width / OpenGLSurface1.Height, 1, 100.0

' select and reset the modelview matrix

OpenGL.glMatrixMode OpenGL.GL_MODELVIEW
OpenGL.glLoadIdentity
21. Add the following code to the MouseDown event of OpenGLSurface1:
Dim model As R3Model

' select model at mouse coordinates

model = R3_OGLPickModel(scene, x, OpenGLSurface1.Height - y)

' did the user click on a model?
if model <> nil then

  ' yes, toggle bump map texture on/off

  if model.Polygon(0).TextureIndex = 0 then
    model.SetTextureIndex 1 ' flat earth texture
  else
    model.SetTextureIndex 0 ' bump mapped earth texture
  end if

  OpenGLSurface1.Render ' refresh the OpenGL surface

else

  ' no, so start the rotation action of the earth

  MousePrevX = x
  MousePrevY = y

  return true ' only start the mouse drag operation if the user did not select a model

end if
22. Add the following code to the MouseDrag event of OpenGLSurface1:
Dim model As R3Model ' temporary model object

model = Scene.Model(0) ' get the first model in the scene

' apply a pitch and yaw rotation using the mouse x and y movement

model.Rotation.RotateProjection((y - MousePrevY), (x - MousePrevX))

OpenGLSurface1.Render ' refresh the OpenGL surface

' save the mouse position

MousePrevX = x
MousePrevY = y
23. Save and run the project.
  • Click and drag on the black background to rotate the earth.
  • Click on the earth to toggle bump mapping on/off.
  • Note the difference between a bump mapped texture and normal texture.
Code Analysis

On line 15 in the Window1.Open event you can see how a height map is applied to a texture image. When you instantiate a new texture, you simply pass the bump map image as the second parameter to the R3Texture constructor. Note that the colors of height maps are ignored, so make sure your height map is saved as a grey scale image.

On line 16 we instantiate another texture, but this time without a height map.

To get a better understanding of how the pre-emboss bump mapping algorithm is implemented, have a look at the R3Texture.LoadTextureWithHeightMap method.

Now it's time to have some fun. Edit the height map with your favorite 2D editor, and see what happens. E.g. write your name at the center of the height map in a white color and run the project again.

Project Downloads

<< Previous Tutorial     Next Tutorial >>


 
All the content on Real 3D Tutorials, with the exception of the SyntaxHighlighter which is licensed under the MIT License, is provided to the public domain and everyone is free to use, modify, republish, sell or give away this work without prior consent from anybody. Content is provided without warranty of any kind. Under no circumstances shall the author(s) or contributor(s) be liable for damages resulting directly or indirectly from the use or non-use of the content.
Should you find the content useful and would like to make a contribution, you can show your support by making a donation.