Home   Donators   Contact Us       

<< Previous Tutorial     Next Tutorial >>

Tutorial 8 - Materials that shine

Theory

It is recommended that you first work through Tutorial 4 - Switch on the lights, to get a better understanding of ambient, diffuse and specular values.

Same as with light source settings, material properties consists of ambient, diffuse and specular values. There is also an additional shininess value that comes into play with materials, which determines the width of the specular peak of the material. You use the shininess value to control the brightness and size of the reflection on your material. A higher shininess value results in a more focused (smaller and brighter) highlight. Your shininess value can be any floating point value between (and including) 0 and 128.

Except for the shininess value, which is a single floating point value, each one of the ambient, diffuse and specular components is broken down into red, green, blue and alpha (RGBA) values. The color values is self-explanatory (e.g. the red components of a red plastic will be greater than the blue components), but now would be a good time to look into what exactly the alpha value represents. The alpha value determines the opacity of the RGB color. The lower the alpha value, the easier it is to "see through" the color. Imagine glass as being white with a very low alpha value, because it is very easy to see through glass. A material such as wood is opaque (difficult the see through) and might be a brown color with a very high alpha value. Alpha values can be any floating point value between (and including) 0 and 1, with 0 being completely transparent and 1 being completely opaque. The images below illustrate how the alpha value might affect a color.

The breakdown of material properties into color components, give us the ability to fine tune the material settings for each individual color and alpha channel. For example, it is as easy for us to specify what the red-ambient value of the material should be, as it is to specify the green-diffuse value.

Configuring properties to represent real materials accurately, such as metals or colored plastics, is a true art and science. To get you started on materials, and for your convenience, the table below provides you with settings that can be used for some of the more common materials.

MaterialAmbientDiffuseSpecularShininess
RedGreenBlueAlphaRedGreenBlueAlphaRedGreenBlueAlpha
Brass0.3294120.2235290.02745110.7803920.5686270.11372510.9921570.9411760.807843127.89743616
Bronze0.21250.12750.05410.7140.42840.1814410.3935480.2719060.166721125.6
Chrome0.250.250.2510.40.40.410.7745970.7745970.774597176.8
Copper0.191250.07350.022510.70380.270480.082810.2567770.1376220.086014112.8
Emerald0.02150.17450.021510.075680.614240.0756810.6330.7278110.633176.8
Gold0.247250.19950.074510.751640.606480.2264810.6282810.5558020.366065151.2
Jade0.1350.22250.157510.540.890.6310.3162280.3162280.316228112.8
Obsidian0.053750.050.0662510.182750.170.2252510.3327410.3286340.346435138.4
Pearl0.250.207250.20725110.8290.82910.2966480.2966480.296648111.264
Plastic (Black)00010.010.010.0110.500.500.50132
Plastic (Cyan)00.10.06100.509803920.5098039210.501960780.501960780.50196078132
Plastic (Green)00010.10.350.110.450.550.45132
Plastic (Red)00010.50010.70.60.6132
Plastic (White)00010.550.550.5510.70.70.7132
Plastic (Yellow)00010.50.5010.60.60.5132
Rubber (Black)0.020.020.0210.010.010.0110.40.40.4110
Rubber (Cyan)00.050.0510.40.50.510.040.70.7110
Rubber (Green)00.05010.40.50.410.040.70.04110
Rubber (Red)0.050010.50.40.410.70.040.04110
Rubber (White)0.050.050.0510.50.50.510.70.70.7110
Rubber (Yellow)0.050.05010.50.50.410.70.70.04110
Ruby0.17450.011750.0117510.614240.041360.0413610.7278110.6269590.626959176.8
Silver0.192250.192250.1922510.507540.507540.5075410.5082730.5082730.508273151.2
Turquoise0.10.187250.174510.3960.741510.6910210.2972540.308290.306678112.8

Tutorial Steps
Tutorial created with Real Studio 2011 Release 4.3.
1. Open Real Studio.
2. Choose the "Desktop" project template.
3. Add an OpenGLSurface control to Window1.
4. Resize and position OpenGLSurface1 to fill the whole form.
5. Tick the LockRight and LockBottom properties of OpenGLSurface1.
6. Add a Timer control to Window1.
7. Change the Period property of Timer1 from 1000 to 200.
8. Add a property named "RotAngle" of type Double, with a default value of 0, to Window1. (Double click the titlebar of Window1 and select "Add Property")
9. Add a method named "R3DT_SetMaterial" to Window1. (Double click the titlebar of Window1 and select "Add Method")
10. Add "ambR As Double, ambG As Double, ambB As Double, ambA As Double, diffR As Double, diffG As Double, diffB As Double, diffA As Double, specR As Double, specG As Double, specB As Double, specA As Double, shininess As Double" to the parameter list of method Window1.R3DT_SetMaterial.
11. Add the following code to Window1.R3DT_SetMaterial:
Dim matMb As new MemoryBlock(16) ' memory block used to set up material

matMb.SingleValue(0) = ambR ' red ambience
matMb.SingleValue(4) = ambG ' green ambience
matMb.SingleValue(8) = ambB ' blue ambience
matMb.SingleValue(12) = ambA ' ambience alpha
OpenGL.glMaterialfv(OpenGL.GL_FRONT, OpenGL.GL_AMBIENT, matMb) ' set ambience values

matMb.SingleValue(0) = diffR ' red diffuse
matMb.SingleValue(4) = diffG ' green diffuse
matMb.SingleValue(8) = diffB ' blue diffuse
matMb.SingleValue(12) = diffA ' alpha diffuse
OpenGL.glMaterialfv(OpenGL.GL_FRONT, OpenGL.GL_DIFFUSE, matMb) ' set diffuse values

matMb.SingleValue(0) = specR ' red specular
matMb.SingleValue(4) = specG ' green specular
matMb.SingleValue(8) = specB ' blue specular
matMb.SingleValue(12) = specA ' alpha specular
OpenGL.glMaterialfv(OpenGL.GL_FRONT, OpenGL.GL_SPECULAR, matMb) ' set specular values

OpenGL.glMaterialf(OpenGL.GL_FRONT, OpenGL.GL_SHININESS, shininess) ' set shininess value
12. Add the following code to the Open event of OpenGLSurface1 (You can access the Open event by double clicking on OpenGLSurface1 and then selecting the event from the list):
' make sure only back faces are culled and enable culling

OpenGL.glCullFace OpenGL.GL_BACK
OpenGL.glEnable OpenGL.GL_CULL_FACE

' instantiate memory blocks used to configure our light with

Dim light_position As new MemoryBlock(16)
Dim light_ambience As new MemoryBlock(16)
Dim light_diffANDspec As new MemoryBlock(16)

' define position of the light

light_position.SingleValue(0) = 0.0
light_position.SingleValue(4) = 0.0
light_position.SingleValue(8) = 1.0
light_position.SingleValue(12) = 0.0

' define ambience of the light

light_ambience.SingleValue(0) = 0.5
light_ambience.SingleValue(4) = 0.5
light_ambience.SingleValue(8) = 0.5
light_ambience.SingleValue(12) = 1.0

' define diffuse and specular of the light

light_diffANDspec.SingleValue(0) = 1.0
light_diffANDspec.SingleValue(4) = 1.0
light_diffANDspec.SingleValue(8) = 1.0
light_diffANDspec.SingleValue(12) = 1.0

' apply light settings

OpenGL.glLightfv OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, light_position ' set position
OpenGL.glLightfv OpenGL.GL_LIGHT0, OpenGL.GL_AMBIENT, light_ambience ' set ambience
OpenGL.glLightfv OpenGL.GL_LIGHT0, OpenGL.GL_DIFFUSE, light_diffANDspec ' set diffuse
OpenGL.glLightfv OpenGL.GL_LIGHT0, OpenGL.GL_SPECULAR, light_diffANDspec ' set specular

' enable our light

OpenGL.glEnable OpenGL.GL_LIGHT0

' enable lighting

OpenGL.glEnable OpenGL.GL_LIGHTING

' disable overwriting of material properties with vertex colors

OpenGL.glDisable OpenGL.GL_COLOR_MATERIAL
13. Add the following code to the Render event of OpenGLSurface1 (You can access the Render event by double clicking on OpenGLSurface1 and then selecting the event from the list):
  
OpenGL.glPushMatrix ' save matrix

' clear the background

OpenGL.glClearColor(0, 0, 0, 1)
OpenGL.glClear(OpenGL.GL_COLOR_BUFFER_BIT)

' move back a bit so that we can see the object

OpenGL.glTranslatef 0.0, 0.0, -8.0

' draw the gold bar

OpenGL.glPushMatrix ' save matrix before drawing bar

' set material to gold

R3DT_SetMaterial 0.24725, 0.1995, 0.0745, 1, 0.75164, 0.60648, 0.22648, 1, 0.628281, 0.555802, 0.366065, 1, 51.2

' move the gold bar to the left

OpenGL.glTranslatef -3, 0, 0 

' rotate the gold bar

OpenGL.glRotated RotAngle, 1, 0, 0 // rotate cube 20 degrees around x-axis
OpenGL.glRotated -RotAngle * 1.5, 0, 1, 0 // rotate cube around y-axis

' draw the gold bar with the current material settings

OpenGL.glNormal3d 0, 0, 1 ' front polygon normal
OpenGL.glBegin OpenGL.GL_POLYGON ' front polygon
OpenGL.glVertex3d 2.2, 0.5, 0.5
OpenGL.glVertex3d -2.2, 0.5, 0.5
OpenGL.glVertex3d -2.5, -0.5, 1
OpenGL.glVertex3d 2.5, -0.5, 1
OpenGL.glEnd
OpenGL.glNormal3d 1, 0, 0 ' right polygon normal
OpenGL.glBegin OpenGL.GL_POLYGON ' right polygon
OpenGL.glVertex3d 2.2, 0.5, 0.5
OpenGL.glVertex3d 2.5, -0.5, 1
OpenGL.glVertex3d 2.5, -0.5, -1
OpenGL.glVertex3d 2.2, 0.5, -0.5
OpenGL.glEnd
OpenGL.glNormal3d -1, 0, 0 ' left polygon normal
OpenGL.glBegin OpenGL.GL_POLYGON ' left polygon
OpenGL.glVertex3d -2.2, 0.5, 0.5
OpenGL.glVertex3d -2.2, 0.5, -0.5
OpenGL.glVertex3d -2.5, -0.5, -1
OpenGL.glVertex3d -2.5, -0.5, 1
OpenGL.glEnd
OpenGL.glNormal3d 0, 0, -1 ' back polygon normal
OpenGL.glBegin OpenGL.GL_POLYGON ' back polygon
OpenGL.glVertex3d 2.2, 0.5, -0.5
OpenGL.glVertex3d 2.5, -0.5, -1
OpenGL.glVertex3d -2.5, -0.5, -1
OpenGL.glVertex3d -2.2, 0.5, -0.5
OpenGL.glEnd
OpenGL.glNormal3d 0, 1, 0 ' top polygon normal
OpenGL.glBegin OpenGL.GL_POLYGON ' top polygon
OpenGL.glVertex3d 2.2, 0.5, 0.5
OpenGL.glVertex3d 2.2, 0.5, -0.5
OpenGL.glVertex3d -2.2, 0.5, -0.5
OpenGL.glVertex3d -2.2, 0.5, 0.5
OpenGL.glEnd
OpenGL.glNormal3d 0, -1, 0 ' bottom polygon normal
OpenGL.glBegin OpenGL.GL_POLYGON ' bottom polygon
OpenGL.glVertex3d 2.5, -0.5, 1
OpenGL.glVertex3d -2.5, -0.5, 1
OpenGL.glVertex3d -2.5, -0.5, -1
OpenGL.glVertex3d 2.5, -0.5, -1
OpenGL.glEnd

OpenGL.glPopMatrix ' restore matrix after drawing bar

' draw the cube

OpenGL.glPushMatrix ' save matrix before drawing cube

' set material to yellow plastic

R3DT_SetMaterial 0, 0, 0, 1, 0.8, 0.8, 0, 1, 0.6, 0.6, 0.5, 1, 32

OpenGL.glTranslatef 3.5, 0, 0 // move cube to the right

OpenGL.glRotated RotAngle, 1, 0, 0 // rotate cube 20 degrees around x-axis
OpenGL.glRotated -RotAngle * 1.5, 0, 1, 0 // rotate cube around y-axis

OpenGL.glNormal3d 0, 0, 1 ' front polygon normal
OpenGL.glBegin OpenGL.GL_POLYGON ' front polygon
OpenGL.glVertex3d 1, 1, 1
OpenGL.glVertex3d -1, 1, 1
OpenGL.glVertex3d -1, -1, 1
OpenGL.glVertex3d 1, -1, 1
OpenGL.glEnd
OpenGL.glNormal3d 1, 0, 0 ' right polygon normal
OpenGL.glBegin OpenGL.GL_POLYGON ' right polygon
OpenGL.glVertex3d 1, 1, 1
OpenGL.glVertex3d 1, -1, 1
OpenGL.glVertex3d 1, -1, -1
OpenGL.glVertex3d 1, 1, -1
OpenGL.glEnd
OpenGL.glNormal3d -1, 0, 0 ' left polygon normal
OpenGL.glBegin OpenGL.GL_POLYGON ' left polygon
OpenGL.glVertex3d -1, 1, 1
OpenGL.glVertex3d -1, 1, -1
OpenGL.glVertex3d -1, -1, -1
OpenGL.glVertex3d -1, -1, 1
OpenGL.glEnd
OpenGL.glNormal3d 0, 0, -1 ' back polygon normal
OpenGL.glBegin OpenGL.GL_POLYGON ' back polygon
OpenGL.glVertex3d 1, 1, -1
OpenGL.glVertex3d 1, -1, -1
OpenGL.glVertex3d -1, -1, -1
OpenGL.glVertex3d -1, 1, -1
OpenGL.glEnd
OpenGL.glNormal3d 0, 1, 0 ' top polygon normal
OpenGL.glBegin OpenGL.GL_POLYGON ' top polygon
OpenGL.glVertex3d 1, 1, 1
OpenGL.glVertex3d 1, 1, -1
OpenGL.glVertex3d -1, 1, -1
OpenGL.glVertex3d -1, 1, 1
OpenGL.glEnd
OpenGL.glNormal3d 0, -1, 0 ' bottom polygon normal
OpenGL.glBegin OpenGL.GL_POLYGON ' bottom polygon
OpenGL.glVertex3d 1, -1, 1
OpenGL.glVertex3d -1, -1, 1
OpenGL.glVertex3d -1, -1, -1
OpenGL.glVertex3d 1, -1, -1
OpenGL.glEnd

OpenGL.glPopMatrix ' restore matrix after drawing cube

OpenGL.glPopMatrix ' restore matrix
14. Add the following code to the Resized event of OpenGLSurface1 (You can access the Resized event by double clicking on OpenGLSurface1 and then selecting the event from the list):
' 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
15. Add the following code to the Paint event of Window1 (You can access the Paint event by double clicking on the titlebar of Window1 and then selecting the event from the list):
' refresh the OpenGL surface

OpenGLSurface1.Render
16. Add the following code to the Action event of Timer1 (You can access the Action event by double clicking on Timer1):
RotAngle = RotAngle + 10 ' increase angle of rotation

if RotAngle > 359 then ' have we reached 360 degrees				  
  RotAngle = 0 ' yes, so reset angle to zero
end if

OpenGLSurface1.Render ' refresh the OpenGL surface
17. Save and run the project.

Code Analysis

The R3DT_SetMaterial method added to Window1 is a helper method that we use to configure a particular material. When you look at the method signature of Window1.R3DT_SetMaterial, you will notice that there is a parameter for each one of the ambient, diffuse, specular and shininess components. In the method we use the matMb MemoryBlock to convert our material values into a format that OpenGL understands. A call to glMaterialfv is used to apply our desired material settings to all the front facing polygons. The GL_FRONT constant indicates that our values should only be applied to front-facing polygons. We use the respective GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR and GL_SHININESS constants to indicate to the glMaterialfv function whether we want to apply the ambient, diffuse, specular or shininess values of our material.

In our drawing routine (line 18 and line 82 in the OpenGLSurface1.Render event), selecting a material to draw our polygons with, is done by simply making a call to R3DT_SetMaterial and passing it our desired material values. Note that the individual red, green, blue and alpha values are supplied for each one of the ambient, diffuse and specular properties.

Compare the values supplied on line 18 with the values given in the material table for the "Gold" material. You will see they are an exact match. Similarly the values on line 82, just before drawing the cube, is a match for the "Yellow plastic" material.

One last important thing to note is that we make a call to glDisable using the GL_COLOR_MATERIAL constant, on line 50 in the OpenGLSurface1.Open event. This is different than when we drew our polygons with colors in Tutorial 3 - A splash of color, where we enabled GL_COLOR_MATERIAL. This is a key difference between working with colors and materials. With colors we need to enable GL_COLOR_MATERIAL, and with materials we need to disable GL_COLOR_MATERIAL.

By making use of materials you can create exciting and realistic 3D models and objects. See if you can change the material of the cube to "Pearl"?

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.