Home   Donators   Contact Us       

<< Previous Tutorial     Next Tutorial >>

Tutorial 16 - The key in frames



Theory

Keyframes give you the ability to store the current state of a 3D scene or model, using the minimal amount of memory. The keyframe of a model contains information such as the model's position, orientation, scale and bone structure.

   

The images above illustrate three different keyframes applied to a hand model. We differentiate between two types of keyframes, namely a scene keyframe and a model keyframe.

A model keyframe stores the model's position, orientation, scale and bone structure information for the frame, but not the geometric data (e.g. vertices, polygons, etc). Excluding the geometric information reduces the memory footprint used by a model's keyframe.

A scene keyframe simply stores an array that holds all the keyframes of the models used in the scene.

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 height of the form, but leave enough space on the right side of the form for a listbox.
6. Tick the LockRight and LockBottom properties of OpenGLSurface1.
7. Add a Timer control to Window1.
8. Change the Period property of Timer1 from 1000 to 50.
9. Add a PushButton control to Window1.
10. Rename the PushButton to "cmdSaveKeyframe" and position it at the top right of the form. Make sure that the button does not overlap with the OpenGLSurface control.
11. Set the caption of cmdSaveKeyframe to "Save Keyframe".
11. Change the Position settings of cmdSaveKeyframe to LockTop and LockRight (LockLeft and LockBottom should not be ticked).
12. Add a ListBox control to Window1.
13. Rename the ListBox to "lstKeyframes" and position it to fill the rest of the open space on the form.
14. Change the Position settings of lstKeyframes to LockTop, LockRight and LockBottom (Only LockLeft should not be ticked).

Your form should now look as follow:



15. Save your project.
16. Download the following file and extract the content next to your project file:
17. Import the classes and modules contained in the archive file into your new project file. (Select File > Import... from the main menu)
18. Download the following file and extract the content next to your project file:
19. Import the bitmap textures into your new project file and rename the images as follow:
  • finger.png: imgFinger
  • print.png: imgPrint
  • cube1.png: imgCube1
  • cube2.png: imgCube2
20. Add a property named "MousePrevX" of type Integer to Window1.
21. Add a property named "MousePrevY" of type Integer to Window1.
22. Add a property named "Scene" of type R3Scene to Window1.
23. Add a property array named "Keyframe()" of type R3SceneKeyframe to Window1.
24. Add a method named "DisplayKeyframes" to Window1
25. Add the following code to Window1.DisplayKeyframes:
Dim i As Integer ' loop variable

lstKeyframes.DeleteAllRows ' remove all rows from keyframe listbox

' loop through all keyframes

for i = 0 to Keyframe.Ubound
  lstKeyframes.AddRow "Keyframe " + Str(i + 1)
next i
26. Add the following code to the Open event of Window1:
Dim model As R3Model ' temporary model object
Dim cube As R3Model ' temporary cube model
Dim i As Integer
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(1, 1, 1) ' white background

' load textures used in scene

Scene.Texture.Append new R3Texture(imgFinger)
Scene.Texture.Append new R3Texture(imgPrint)
Scene.Texture.Append new R3Texture(imgCube1)
Scene.Texture.Append new R3Texture(imgCube2)

' add front light source

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

' add camera

cam = new R3Camera
cam.DollyOut 30 ' 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 hand model

model = R3_Tut00016Hand

' add the model to our scene

Scene.AppendModel model

' add cubes

for i = 0 to 2
  cube = R3_Tut00016Cube
  Scene.AppendModel cube
next i

' starting status of all fingers are erected

FingerErected.Append true  ' pinky
FingerErected.Append true  ' index finger
FingerErected.Append true  ' middle finger
FingerErected.Append true  ' ring finger
FingerErected.Append true  ' thumb


' disable animation timer for now

Timer1.Enabled = false

FingerIndex = -1 ' no finger selected

OpenGLSurface1.Render ' refresh OpenGL surface
27. Add the following code to the Paint event of Window1:
OpenGLSurface1.Render ' refresh the OpenGL surface
28. Add the following code to the Close event of Window1:
Scene = nil ' remove the scene object from memory
29. Add the following code to the Action event of Timer1:
R3_Tut00016AnimateFinger
30. Add the following code to the Open event of OpenGLSurface1:
R3_OGLInitialize ' initalize OpenGL environment
31. 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
32. 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
33. Add the following code to the MouseDown event of OpenGLSurface1:
Dim model As R3Model

model = R3_OGLPickModel(Scene, x, OpenGLSurface1.Height - y) ' pick the model at mouse coordinate (x, y)

' did the user click on a model?

if model <> nil then

  ' yes, so did the user click on the hand model?
  if model.Index = 0 then
  
    R3_Tut00016SelectFinger(x, y) ' select the finger at position (x, y) on the screen
  
  else
  
    ' no, so the user clicked on a cube model
  
    ' let's rotate the selected cube
  
    model.Rotation.Rotate(15, 15, 0)
  
    OpenGLSurface1.Render ' refresh OpenGL surface
  
  end if

else

  ' save the mouse position 

  MousePrevX = x
  MousePrevY = y

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

end if
34. 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
35. Add the following code to the Action event of cmdSaveKeyframe:
' get and store a keyframe of the current scene

Keyframe.Append Scene.GetKeyframe()

' update the listbox

DisplayKeyframes
36. Add the following code to the Change event of lstKeyframes:
' do we have a keyframe selected
if lstKeyframes.ListIndex >= 0 then

  ' yes, so display the keyframe
  Scene.SetKeyframe Keyframe(lstKeyframes.ListIndex)

  OpenGLSurface1.Render ' refresh the OpenGL surface

end if
37. Save and run the project.
  • Click and drag on the white background to rotate the hand.
  • Click on any finger to open or close the finger.
  • Click on any cube to give it a partial rotation.
  • To save the scene's current keyframe, click the "Save Keyframe" button.
  • Set up a couple of keyframes, then click on any of the keyframes shown in the listbox to revert back to a previous keyframe.
Code Analysis

In this tutorial we made a minor change in how the R3Texture class is used. All textures are now pre-loaded into an array stored in the R3Scene class. The R3Polygon class now only stores an Integer pointer, that points to a texture in this array, instead of storing an instance of a R3Texture object. This approach makes it much easier to use the same texture for multiple polygons, and reduces the amount of memory required.

Two methods of the R3Scene class provides keyframe management capabilities, namely GetKeyframe that returns a R3SceneKeyframe object and SetKeyframe that takes a R3SceneKeyframe object as an argument.

To take a snapshot of the current scene you simply call R3Scene.GetKeyframe and store the returned R3SceneKeyframe object. On line 3 in the cmdSaveKeyframe.Action event we do exactly this.

You can now restore the scene to a previous state by calling R3Scene.SetKeyframe and passing the R3SceneKeyframe that you stored earlier as a parameter. Line 5 of the lstKeyframes.Change event shows how we use the R3Scene.SetKeyframe method.

The R3Scene.GetKeyframe and R3Scene.SetKeyframe methods captures keyframes of all the models in the scene. If you only want to capture or restore the keyframe of a single model you can use the GetKeyframe and SetKeyframe methods of the R3Model class. These two methods operate in exactly the same fashion than the methods of the R3Scene class, with the only difference being that the methods of the R3Model class returns and accepts R3ModelKeyframe objects instead of R3SceneKeyframe objects.

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.