Home   Donators   Contact Us       

<< Previous Tutorial     Next Tutorial >>

Tutorial 15 - Textures revisited


If you are new to material settings and texture mapping techniques used in 3D programming, we recommend that you first read through Tutorial 5 - Texture mapping and Tutorial 8 - Materials that shine.

To enhance our models with material settings, we first need to design a material class that is capable of storing the ambient, diffuse and specular values of a material. This material object then needs to be "linked" to the individual polygons in your model, so that these polygons can be rendered with the correct material settings.

Similarly, we will design a texture class that is instantiated with a picture object, and that handles all the OpenGL technical details automatically. This way we only have to concentrate on how to map textures to polygons, rather than dealing with the technical management of your texture assets during rendering.

To assist with the texture mapping, we will implement an UV-Coordinate class that will store the UV-coordinates required for each vertex in a polygon, when mapping a texture to a given polygon.

In the following tutorial we will take a basic cube, map four sides of the cube with a texture, the top polygon with a chrome material, and the bottom polygon with a standard blue color. This will illustrate how you can use textures, materials and colors simultaneously on the different polygons of a single model.

The image below is the texture that we will map to the four sides of the cube:

If the vertices of the front polygon of the cube is given in an anti-clockwise order as shown below, it is easy to determine how the UV-coordinates of the texture maps to the polygon vertices. If you are unsure about the details of UV-coordinates, have a look at Tutorial 5 - Texture mapping.

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 files and save them next to your project file:
9. Import the classes and modules into your new project file. (Select File > Import... from the main menu)
10. Download map.png and save it next to your project file.
11. Import the picture into your project file. (Select "File > Import..." from the main menu)
12. On the Project tab, select the imported picture and change its name to "imgA1B2".
13. Add a property named "MousePrevX" of type Integer to Window1.
14. Add a property named "MousePrevY" of type Integer to Window1.
15. Add a property named "Scene" of type R3Scene to Window1.
16. Add the following code to the Open event of Window1:
Dim model As R3Model ' tempory model object
Dim light As R3LightSource  ' light source
Dim cam As R3Camera ' camera used in our scene
Dim poly As R3Polygon ' temporay polygon object

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

' instantiate the Scene object

Scene = new R3Scene
Scene.BackgroundColor.SetValue(1, 1, 1) ' white background

' add front light source

light = new R3LightSource
light.Position.SetValue(1, 0, 3)
Scene.LightSource.Append light

' add top light source

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

' add camera

cam = new R3Camera
cam.DollyOut 5 ' 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 a new cube model

model = R3_Model_Cube 

' load textures used by model

model.Texture.Append new R3Texture(imgA1B2)

' set up the UV maps of polygons

poly = model.Polygon(0) ' font polygon
poly.TextureIndex = 0 ' point to first texture in our texture array
poly.UVMap.Append (new R3UVCoordinate(0.5, 0))
poly.UVMap.Append (new R3UVCoordinate(0, 0))
poly.UVMap.Append (new R3UVCoordinate(0, 0.5))
poly.UVMap.Append (new R3UVCoordinate(0.5, 0.5))

poly = model.Polygon(1) ' right polygon
poly.TextureIndex = 0 ' point to first texture in our texture array
poly.UVMap.Append (new R3UVCoordinate(0.5, 0))
poly.UVMap.Append (new R3UVCoordinate(0.5, 0.5))
poly.UVMap.Append (new R3UVCoordinate(1, 0.5))
poly.UVMap.Append (new R3UVCoordinate(1, 0))

poly = model.Polygon(2) ' left polygon
poly.TextureIndex = 0 ' point to first texture in our texture array
poly.UVMap.Append (new R3UVCoordinate(1, 0.5))
poly.UVMap.Append (new R3UVCoordinate(0.5, 0.5))
poly.UVMap.Append (new R3UVCoordinate(0.5, 1))
poly.UVMap.Append (new R3UVCoordinate(1, 1))

poly = model.Polygon(3) ' back polygon
poly.TextureIndex = 0 ' point to first texture in our texture array
poly.UVMap.Append (new R3UVCoordinate(0, 0.5))
poly.UVMap.Append (new R3UVCoordinate(0, 1))
poly.UVMap.Append (new R3UVCoordinate(0.5, 1))
poly.UVMap.Append (new R3UVCoordinate(0.5, 0.5))

' add material and colors to our cube model

model.Material.Append new R3Material(0.25, 0.25, 0.25, 1, 0.4, 0.4, 0.4, 1, 0.774597, 0.774597, 0.774597, 1, 76.8) ' add pearl material to model
model.SurfaceColor.Append new R3Color(0, 0, 0.7) ' add a blue color to the model

model.Polygon(4).MaterialIndex = 0 ' top polygon of cube uses pearl material
model.Polygon(5).SurfaceColorIndex = 1 ' bottom polygon of cube uses blue color

' add the model to our scene

Scene.Model.Append model

OpenGLSurface1.Render ' refresh OpenGL surface
17. Add the following code to the Paint event of Window1:
OpenGLSurface1.Render ' refresh the OpenGL surface
18. Add the following code to the Close event of Window1:
Scene = nil ' remove the scene object from memory
19. Add the following code to the Open event of OpenGLSurface1:
R3_OGLInitialize ' initalize OpenGL environment
20. 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
21. 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.gluPerspective 60.0, OpenGLSurface1.Width / OpenGLSurface1.Height, 1, 100.0

' select and reset the modelview matrix

OpenGL.glMatrixMode OpenGL.GL_MODELVIEW
22. Add the following code to the MouseDown event of OpenGLSurface1:
' save the mouse position

MousePrevX = x
MousePrevY = y

return true
23. 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
24. Save and run the project.
25. Click and drag on the white background to rotate the cube. Observe the different textures, materials and colors used on the cube.

Code Analysis

If you worked through the previous tutorials, the first important change you will notice is in the R3Polygon class. The color of the polygon is no longer stored as an R3Color instance and is replaced with a property named SurfaceColorIndex of type Integer. All colors are now stored in the R3Model object's SurfaceColor() array property. R3Polygon.SurfaceColorIndex is an index into this array. This change improves performance by creating color objects once, and then accessing these color objects through indexes.

Similar to the R3Polygon.SurfaceColorIndex property, the new R3Polygon.MaterialIndex and R3Polygon.TextureIndex properties serve exactly the same purpose. They are indexes into material and texture arrays stored in R3Model.

So how does the rendering algorithm R3_OGLRenderModel decide if a polygon should be rendered with a color, material settings or a texture? If the R3Polygon.TextureIndex is a valid index (e.g. equal or greater than zero), it will render the polygon with the texture. It algorithm then checks if R3Polygon.MaterialIndex is a valid index. If so it will render the polygon with the material properties, else it will use the color pointed to by R3Polygon.SurfaceColorIndex.

On line 74 and 75 in the Window1.Open event, we add a new material and color respectively to our model.

On line 77 we set polygon(4) to use the new material we've added and on line 78 we set polygon(5) to use the new color.

On line 40 in the Window1.Open event we instantiate our texture and append it to our model's texture array. Line 44 to 70 is responsible for mapping some of our model's polygons to the texture we've added.

See if you can add more materials, colors or even your own textures, and link them to different polygons in the cube model.

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.