Home   Donators   Contact Us       

<< Previous Tutorial     Next Tutorial >>

Tutorial 7 - Putting a spin on things


Theory

As shown in the previous tutorial, Tutorial 6 - Make your move, 3D space has 3 primary axles, namely the x-axis, y-axis and z-axis.

If we had to draw a cube at the origin of our 3D space without any rotation applied, it will be rendered as shown in the diagram below.

The easiest way to apply rotation to our cube is to rotate the model around one of the three primary axes.

        
30° rotation around x-axis    30° rotation around y-axis    30° rotation around z-axis

Notice how rotation takes place in an anti-clockwise direction. If you wanted to reverse the direction to a clockwise direction, you simply use negative values. For example, to rotate 50° in a clockwise direction, you would use a value of -50°.

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 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.0
light_ambience.SingleValue(4) = 0.0
light_ambience.SingleValue(8) = 0.0
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 lightning

OpenGL.glEnable OpenGL.GL_LIGHTING

' enable overwriting of material properties with vertex colors

OpenGL.glEnable OpenGL.GL_COLOR_MATERIAL
10. 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, -7.0

' draw the cube

OpenGL.glPushMatrix ' save matrix before drawing cube

OpenGL.glColor3d 0, 0, 1 ' set color to blue

OpenGL.glTranslatef -2.5, 0, 0 // move cube to the left

OpenGL.glRotated 20, 1, 0, 0 // rotate cube 20 degrees around x-axis
OpenGL.glRotated RotAngle, 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

' draw the prism

OpenGL.glPushMatrix ' save matrix before drawing prism

OpenGL.glColor3d 0, 1, 0 ' set color to green

OpenGL.glTranslatef 2.5, 0, 0 // move prism to the right

OpenGL.glRotated 10, 0, 1, 0 // rotate prism 10 degrees around y-axis
OpenGL.glRotated RotAngle, 1, 0, 0 // rotate prism around x-axis

OpenGL.glNormal3d 0, 0, 1 ' front polygon normal
OpenGL.glBegin OpenGL.GL_POLYGON ' front polygon
OpenGL.glVertex3d 0, 1, 0
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 0, 1, 0
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 0, 1, 0
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 0, 1, 0
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 prism

OpenGL.glPopMatrix ' restore matrix
11. 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
12. 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
13. 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
14. Save and run the project.

Code Analysis

We added a property named RotAngle of type Double to Window1. Window1.RotAngle is used to store the angle of rotation that we will apply to our models.

The period of Timer1 is set to 200. This setting ensures that the code added to the Timer1.Action event, is executed every 200 milliseconds.

When looking at the code of the Timer1.Action event, you will notice that we increase the angle of rotation by 10 degrees every 200 milliseconds. We then check with an if statement if the angle of rotation is larger than 360°. The full rotation of a circle is 360°, so we need to reset the angle back to zero when we reach 360°. Once we've updated the angle of rotation, we call the OpenGLSurface1.Render method to redraw our objects with the new angle.

On line 20 of our render routine in the OpenGLSurface1.Render event, we first rotate the cube 20° around the x-axis. Directly after we applied the first rotation, we apply a second rotation, this time around the y-axis, using the value stored in the Window1.RotAngle property. You can imagine that because we increase the angle stored in Window1.RotAngle every 200 milliseconds, we will get a basic rotation animation effect.

Note that we first save the current "rotation settings" before we rotate the cube, by calling the glPushMatrix function on line 14. After we rotated and drew the cube, we restore the previous "rotation settings", by calling glPopMatrix on line 66. This is done to prevent the cube's rotation settings from interfering with the rotation settings of the prism.

On line 76 and 77 we follow the same process to rotate the prism. The only difference is that we first make a fixed rotation of 10° around the y-axis, and then the RotAngle rotation around the x-axis.

This tutorial provided a very basic overview on how to apply rotation to your models and objects, and we only saw the tip of the iceberg when it comes to 3D rotation techniques. See if you can change to code so that the models rotate in a clockwise direction instead of an anti-clockwise direction.

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.