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.
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 i26. 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 surface27. Add the following code to the Paint event of Window1:
OpenGLSurface1.Render ' refresh the OpenGL surface28. Add the following code to the Close event of Window1:
Scene = nil ' remove the scene object from memory29. Add the following code to the Action event of Timer1:
R3_Tut00016AnimateFinger30. Add the following code to the Open event of OpenGLSurface1:
R3_OGLInitialize ' initalize OpenGL environment31. 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 if32. 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.glLoadIdentity33. 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 if34. 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 = y35. 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 DisplayKeyframes36. 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 if37. Save and run the project.
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.