Home     Tutorials     X3 Downloads     Contact Us    

Tutorial 16: Materials

Different types of materials reflects differently in light, and by applying material properties to your models you can greatly enhance the aesthetics of your scenes. In this tutorial we explore materials, how materials reacts to light, and how to use this knowledge in the programming of your applications.
Windows Binary  OS X Binary (Cocoa)  Linux Binary (32 bit) 
Download Tutorial PDF  Download Source Code

Theory

Similar to light sources, a material has ambient, diffuse and specular properties. There is also an additional shininess value that comes into play with materials, which determines the width of the specular peak of the material. This effectively determines the brightness and size of the reflection on a material. A higher shininess value results in a more focused (smaller and brighter) highlight.


The shininess value is a floating point value between (and including) 0 and 128. The ambient, diffuse and specular components of the material are each broken down into red, green, blue and alpha (RGBA) values. These material properties determines how light affects the surface of a polygon during rendering.

The ambient colors define how the material appears when not in direct light. This value will typically be the same as the diffuse values.

The diffuse colors determine how the material reflects light. Essentially it defines what color the polygon will be when hit by light.

The specular colors is used in combination with the shininess value to determine how much a material shines when hit by light. A metal such as chrome for example, has a much higher shininess value than copper.

To help you get started with materials, the table below describes some common materials. All the alpha values are equal to 1 for these materials.

MaterialAmbientDiffuseSpecularShininess
RedGreenBlueRedGreenBlueRedGreenBlue
Brass0.3294120.2235290.0274510.7803920.5686270.1137250.9921570.9411760.80784327.8974
Bronze0.21250.12750.0540.7140.42840.181440.3935480.2719060.16672125.6
Chrome0.250.250.250.40.40.40.7745970.7745970.77459776.8
Copper0.191250.07350.02250.70380.270480.08280.2567770.1376220.08601412.8
Emerald0.02150.17450.02150.075680.614240.075680.6330.7278110.63376.8
Gold0.247250.19950.07450.751640.606480.226480.6282810.5558020.36606551.2
Jade0.1350.22250.15750.540.890.630.3162280.3162280.31622812.8
Obsidian0.053750.050.066250.182750.170.225250.3327410.3286340.34643538.4
Pearl0.250.207250.2072510.8290.8290.2966480.2966480.29664811.264
Plastic (Black)0000.010.010.010.500.500.5032
Plastic (Cyan)00.10.0600.509803920.509803920.501960780.501960780.5019607832
Plastic (Green)0000.10.350.10.450.550.4532
Plastic (Red)0000.5000.70.60.632
Plastic (White)0000.550.550.550.70.70.732
Plastic (Yellow)0000.50.500.60.60.532
Rubber (Black)0.020.020.020.010.010.010.40.40.410
Rubber (Cyan)00.050.050.40.50.50.040.70.710
Rubber (Green)00.0500.40.50.40.040.70.0410
Rubber (Red)0.05000.50.40.40.70.040.0410
Rubber (White)0.050.050.050.50.50.50.70.70.710
Rubber (Yellow)0.050.0500.50.50.40.70.70.0410
Ruby0.17450.011750.011750.614240.041360.041360.7278110.6269590.62695976.8
Silver0.192250.192250.192250.507540.507540.507540.5082730.5082730.50827351.2
Turquoise0.10.187250.17450.3960.741510.691020.2972540.308290.30667812.8

Tutorial Steps

1. Create a new Xojo desktop project.
2. Save your project.
3. Import the X3Core module.
4. Import the X3Test module.
5. Configure the following controls:

Control Name Text Left Top Width Period
Window SurfaceWindow - - - - -
OpenGLSurface Surface - 251 0 - -
Label lblAmbient Ambient 20 14 - -
ScrollBar scrollAmbientRed   - 20 31 208 -
ScrollBar scrollAmbientGreen   - 20 52 208 -
ScrollBar scrollAmbientBlue   - 20 74 208 -
ScrollBar scrollAmbientAlpha   - 20 95 208 -
Label lblDiffuse Diffuse 20 116 - -
ScrollBar scrollDiffuseRed   - 20 136 208 -
ScrollBar scrollDiffuseGreen   - 20 158 208 -
ScrollBar scrollDiffuseBlue   - 20 180 208 -
ScrollBar scrollDiffuseAlpha   - 20 202 208 -
Label lblSpecular Specular 20 223 - -
ScrollBar scrollSpecularRed   - 20 247 208 -
ScrollBar scrollSpecularGreen   - 20 269 208 -
ScrollBar scrollSpecularBlue   - 20 291 208 -
ScrollBar scrollSpecularAlpha   - 20 313 208 -
Label lblShininess Shininess 20 339 - -
ScrollBar scrollShininess   - 20 363 208 -
Timer tmrRotate - - - - 100

6. Position and size Surface to fill the window, and set its locking to left, top, bottom and right.


7. Add the following code to the SurfaceWindow.Paint event handler:

Surface.Render

8. Add the following code to the SurfaceWindow.Open event handler:

Model = X3Test_MaterialCube()

GetMaterialSettings()

9. Add the following code to the Surface.Open event handler:

X3_Initialize

X3_EnableLight OpenGL.GL_LIGHT0, new X3Core.X3Light(0, 1, 1)

10. Add the following code to the Surface.Resized event handler:

X3_SetPerspective Surface

11. Add the following code to the Surface.Render event handler:

Dim i As Integer

OpenGL.glClearColor(1, 1, 1, 1)
OpenGL.glClear(OpenGL.GL_COLOR_BUFFER_BIT + OpenGL.GL_DEPTH_BUFFER_BIT)

OpenGL.glPushMatrix

OpenGL.glTranslatef 0, 0, -5

if Model <> nil then
  X3_RenderModel Model
end if

OpenGL.glPopMatrix

12. Add the following properties to SurfaceWindow:

Name Type
Loading Boolean
Model X3Core.X3Model

13. Add a new class named "X3Material" to module X3Core.
14. Add the following properties to X3Material:

Name Type
Ambient X3Core.X3Color
Diffuse X3Core.X3Color
Specular X3Core.X3Color
Shininess Double

15. Add the following method to X3Material:

Sub Constructor()
  Ambient = new X3Color(0.2, 0.2, 0.2)
  Diffuse = new X3Color(0.8, 0.8, 0.8)
  Specular = new X3Color(0, 0, 0)
  Shininess = 0
End Sub

16. Add the following method to X3Material:

Function Clone() As X3Core.X3Material
  Dim mat As new X3Core.X3Material

  mat.Ambient = Ambient.Clone
  mat.Diffuse = Diffuse.Clone
  mat.Shininess = Shininess
  mat.Specular = Specular.Clone

  return mat
End Function

17. Add the following method to X3Core:

Sub X3_SetMaterial(material As X3Core.X3Material)
  Dim matMB As MemoryBlock

  matMB = material.Ambient.GetMemoryBlock()
  OpenGL.glMaterialfv(OpenGL.GL_FRONT, OpenGL.GL_AMBIENT, matMB)

  matMB = material.Diffuse.GetMemoryBlock()
  OpenGL.glMaterialfv(OpenGL.GL_FRONT, OpenGL.GL_DIFFUSE, matMB)

  matMB = material.Specular.GetMemoryBlock()
  OpenGL.glMaterialfv(OpenGL.GL_FRONT, OpenGL.GL_SPECULAR, matMB)

  OpenGL.glMaterialf(OpenGL.GL_FRONT_AND_BACK, OpenGL.GL_SHININESS, material.Shininess)
End Sub

18. Add the following method to SurfaceWindow:

Sub GetMaterialSettings()
  Dim mat As X3Core.X3Material

  if Model <> nil then

    Loading = true

    mat = Model.Material(0)

    scrollAmbientRed.Value = Round(mat.Ambient.Red * 100)
    scrollAmbientGreen.Value = Round(mat.Ambient.Green * 100)
    scrollAmbientBlue.Value = Round(mat.Ambient.Blue * 100)
    scrollAmbientAlpha.Value = Round(mat.Ambient.Alpha * 100)

    scrollDiffuseRed.Value = Round(mat.Diffuse.Red * 100)
    scrollDiffuseGreen.Value = Round(mat.Diffuse.Green * 100)
    scrollDiffuseBlue.Value = Round(mat.Diffuse.Blue * 100)
    scrollDiffuseAlpha.Value = Round(mat.Diffuse.Alpha * 100)

    scrollSpecularRed.Value = Round(mat.Specular.Red * 100)
    scrollSpecularGreen.Value = Round(mat.Specular.Green * 100)
    scrollSpecularBlue.Value = Round(mat.Specular.Blue * 100)
    scrollSpecularAlpha.Value = Round(mat.Specular.Alpha * 100)

    scrollShininess.Value = Round(mat.Shininess)

    Loading = false

  end if
End Sub

19. Add the following method to SurfaceWindow:

Sub ApplyMaterialSettings()
  Dim mat As X3Core.X3Material

  if (Model <> nil) and not Loading then

    mat = Model.Material(0)

    mat.Ambient.Red = scrollAmbientRed.Value / 100
    mat.Ambient.Green = scrollAmbientGreen.Value / 100
    mat.Ambient.Blue = scrollAmbientBlue.Value / 100
    mat.Ambient.Alpha = scrollAmbientAlpha.Value / 100

    mat.Diffuse.Red = scrollDiffuseRed.Value / 100
    mat.Diffuse.Green = scrollDiffuseGreen.Value / 100
    mat.Diffuse.Blue = scrollDiffuseBlue.Value / 100
    mat.Diffuse.Alpha = scrollDiffuseAlpha.Value / 100

    mat.Specular.Red = scrollSpecularRed.Value / 100
    mat.Specular.Green = scrollSpecularGreen.Value / 100
    mat.Specular.Blue = scrollSpecularBlue.Value / 100
    mat.Specular.Alpha = scrollSpecularAlpha.Value / 100

    mat.Shininess = scrollShininess.Value

    Model.Invalidate = true

  end if
End Sub

20. Add the following line of code to ALL the ValueChanged events of ALL the scrollbars:

ApplyMaterialSettings

21. Add the following code to the tmrRotate.Action event handler:

if Model <> nil then
  Model.Rotation.Pitch(7)
  Model.Rotation.Yaw(14)
  Model.Rotation.Roll(7)
  Surface.Render
end if

22. Save and run your project.

Analysis

The new X3Material class represents a material that can be used for polygons.

X3Material.Constructor:

Sub Constructor()
  Ambient = new X3Color(0.2, 0.2, 0.2)
  Diffuse = new X3Color(0.8, 0.8, 0.8)
  Specular = new X3Color(0, 0, 0)
  Shininess = 0
End Sub
The constructor of the X3Material class instantiates the components of the material with default values. These values can be updated afterward with the correct values for the material.

The different materials used by a model is stored in the model's Material() array. Polygons are then linked to these materials by storing the index of a material in the Polygon.MIndex property. During the rendering of the polygon the material pointed to by MIndex is used to render the polygon.
X3Core.X3_SetMaterial:

Sub X3_SetMaterial(material As X3Core.X3Material)
  Dim matMB As MemoryBlock

  matMB = material.Ambient.GetMemoryBlock()
  OpenGL.glMaterialfv(OpenGL.GL_FRONT, OpenGL.GL_AMBIENT, matMB)

  matMB = material.Diffuse.GetMemoryBlock()
  OpenGL.glMaterialfv(OpenGL.GL_FRONT, OpenGL.GL_DIFFUSE, matMB)

  matMB = material.Specular.GetMemoryBlock()
  OpenGL.glMaterialfv(OpenGL.GL_FRONT, OpenGL.GL_SPECULAR, matMB)

  OpenGL.glMaterialf(OpenGL.GL_FRONT_AND_BACK, OpenGL.GL_SHININESS, material.Shininess)
End Sub
X3_SetMaterial is a helper method used to configure OpenGL with a selected material. The material object to configure is simply passed as a parameter to X3_SetMaterial.
     

   Xojo3D.com and X3 is a {Zoclee}™ initiative. All the content on Xojo3D.com, unless indicated otherwise, 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. Xojo3D.com is not associated with Xojo, Inc.