opengl animation

17
1 Week 6 Animation This week we move to animations. Hopefully, the objects we have created in our previous sessions can begin to come to life. Double Buffering and Frame rates In animation, the speed of our frames and how we buffer our signals are quite important. Buffering allows us to refresh with more accuracy and possibly less data loss. With OpenGL, double buffering is provided with this command: glutInitDisplayMode(GLUT_DOUBLE | GLUT_RBG); The first attribute (GLUT_DOUBLE) will be used in our code examples to provide the double buffering and make animation possible. Frame rates are essentially how many frames per second are available or processed. The higher the frame rate, the larger the amount of data captured and displayed. In particular, the higher the frame rate, the better the temporal resolution, or the ability to capture moving objects. The following videos on youtube shows several different frame rates for an indoor and outside parking lot surveillance camera. This video demonstrates how the details are impacted based on the frame rate. Frames per second can make a huge difference in security as well as in games. http://www.youtube.com/watch?v=XRaDV8YADiQ http://www.youtube.com/watch?v=e54Q1KXRmX0 Refresh Rates Your computer monitor probably has a 60Hz refresh rate. Refresh rates indicate how fast your monitor device redisplays or reconstructs the current screen image. Faster refresh rates should reduce flicker and make smoother motion and animation. While viewing a 30 frames per second media on a 60 Hz refresh TV or monitor, each frame is repeated 2 times every 30 th of a second. Example Refresh rate Calculation: Given a TV with a 120-Hz refresh rate, How many times will a 30 frames per second input signal be repeated in 1/30 of a second. N = Refresh rate/Frames per second = 120Hz/30fps = 4 Motion Specifications To simulate a ball bouncing a damped, rectified sine wave can be used. Rectified just means we are using all positive values since the ball will be hitting a surface and bouncing back. It is damped since each time the ball hits the surface it loses some of its momentum.

Upload: richard-mcdaniel

Post on 28-Sep-2015

54 views

Category:

Documents


9 download

DESCRIPTION

OpenGL

TRANSCRIPT

  • 1

    Week 6 Animation

    This week we move to animations. Hopefully, the objects we have created in our previous sessions can

    begin to come to life.

    Double Buffering and Frame rates

    In animation, the speed of our frames and how we buffer our signals are quite important. Buffering

    allows us to refresh with more accuracy and possibly less data loss. With OpenGL, double buffering is

    provided with this command:

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RBG);

    The first attribute (GLUT_DOUBLE) will be used in our code examples to provide the double buffering

    and make animation possible.

    Frame rates are essentially how many frames per second are available or processed. The higher the

    frame rate, the larger the amount of data captured and displayed. In particular, the higher the frame

    rate, the better the temporal resolution, or the ability to capture moving objects.

    The following videos on youtube shows several different frame rates for an indoor and outside parking

    lot surveillance camera. This video demonstrates how the details are impacted based on the frame rate.

    Frames per second can make a huge difference in security as well as in games.

    http://www.youtube.com/watch?v=XRaDV8YADiQ

    http://www.youtube.com/watch?v=e54Q1KXRmX0

    Refresh Rates

    Your computer monitor probably has a 60Hz refresh rate. Refresh rates indicate how fast your monitor

    device redisplays or reconstructs the current screen image. Faster refresh rates should reduce flicker

    and make smoother motion and animation. While viewing a 30 frames per second media on a 60 Hz

    refresh TV or monitor, each frame is repeated 2 times every 30th of a second.

    Example Refresh rate Calculation:

    Given a TV with a 120-Hz refresh rate, How many times will a 30 frames per second input signal be

    repeated in 1/30 of a second.

    N = Refresh rate/Frames per second = 120Hz/30fps = 4

    Motion Specifications

    To simulate a ball bouncing a damped, rectified sine wave can be used. Rectified just means we are

    using all positive values since the ball will be hitting a surface and bouncing back. It is damped since each

    time the ball hits the surface it loses some of its momentum.

  • 2

    The equation to model this action when assuming a phase angle of radians is shown below:

    Y(t) = abs(A sin(t + ) e-kt);

    A is the starting amplitude, k is the damping factor (a value between 0 and 1, where large values more

    quickly decrease the amplitude) and is the angular frequency (2f0). fo is the Sine wave frequency The

    angular frequency is determined the sampling frequency and the sine wave frequency. So if we have a

    sampling frequency (fs) of 32 Hertz we are taking snap shots once every 0.03125 (1/32 Hz) seconds. If

    our sine wave is has a period of 1 Hz then becomes 2* * 0.03125* 1Hz = 0.196349.

    Now the resulting amplitude after each time step (t) can be plotted for varying values of k. In the

    following plot, the time step is 1/32 Hz = 0.03125 seconds and the fo = 1 Hz. Values for no damping (k=0)

    and k=0.4 and 0.8 are displayed for a signal with initial amplitude of 1. Notice you increment the time

    step setting t = timestep * .03125 for each iteration. As a sense check, you can create the data

    calculations in excel to confirm your math is correct before you move into your OpenGL programming

    environment to code.

    As k increases, the damping is stronger resulting in less amplitude for the original signal. If we increase

    the Sine save frequency (fo) to 2 Hz, we double the number of oscillations in the same period as shown

    below.

    0

    0.2

    0.4

    0.6

    0.8

    1

    1.2

    abs(sin(x))

    damped k=0.4

    damped k=0.8

  • 3

    OpenGL Raster Operation Bouncing Object Code

    We can use the OpenGL Raster operations to display the x, y positions of a bouncing object that follows

    a damped sine wave. In the following displayFcn() code, notice the use of the glRecti() to create 2

    rectangles. The initial positions xpos, ypos, xpos2 and ypos2 define the locations on the screen. The

    glutSwapBuffers() call is needed to provide buffering for a smooth display.

    // Generate the Graphics void displayFcn(void) { // Clear display window. glClear(GL_COLOR_BUFFER_BIT); // Set graphic objects color to Red or change for your choice glColor3f(0.0, 1.0, 0.0); // Your graphics code here // Create a rectangle to move about glRecti(xpos, ypos, xpos+10, ypos+10); // Set color to Blue glColor3f(0.0, 0.0, 1.0); // Create a rectangle to move about glRecti(xpos2, ypos2, xpos2 + 10, ypos2 + 10); // Call the SwapBuffers glutSwapBuffers(); // Execute OpenGL functions glFlush(); }

    Additionally, mouse and Keyboard functions can be used to start and stop the animation. You should

    experiment with this code by changing the sin wave frequency and damping constants as well as other

    shapes and the keyboard and mouse functions. The animation function is called within the glutIdleFunc()

    0

    0.2

    0.4

    0.6

    0.8

    1

    1.2

    abs(sin(x))

    damped k=0.4

    damped k=0.8

  • 4

    call. In this case, the animation is controlled using the rotateHex function. When designing your own

    animation, be sure to call the glutIdleFunc() when starting your animation. Setting the parameter to null

    will stop the animation.

    // Left mouse starts the animation // Right mouse stops the animation void mouseFcn(GLint button, GLint action, GLint x, GLint y) { switch (button) { case GLUT_LEFT_BUTTON: // Start the animation. if (action == GLUT_DOWN) glutIdleFunc(rotateHex); break; case GLUT_RIGHT_BUTTON: // Stop the animation. if (action == GLUT_DOWN) glutIdleFunc(NULL); break; default: break; } } // Clicking 1 starts the animation // Clicking 2 stops the animation void keyboard(unsigned char key, int x, int y) { switch (key) { case '1': /* 1 key starts the animation */ glutIdleFunc(rotateHex); break; case '2': /* 2 key stops the animation */ glutIdleFunc(NULL); break; default: break; } }

    The rotateHex() function controls the animation results by updating the x and y positions after a short

    sleep cycle. Since we have 2 rectangles, we are calculating 2 different sets of coordinates.

    // Controls the x and y positions using damped sin wave

    void rotateHex(void)

    { Sleep(SLEEPMS); // xpos xpos += 1; ypos = fabs(AMP*sin(2*M_PI*F0*TS*xpos)*exp(-1.0*TS*xpos)); // Resent if get out of window position if (xpos > WIDTH) { xpos = 1; }

  • 5

    // xpos2 xpos2 += 1; ypos2 = fabs(AMP*sin(2*M_PI*F0*TS*xpos2)*exp(-1.0*TS*xpos2)); // Reset if get out of window position if (xpos2 > WIDTH) { xpos2 = 1; } glutPostRedisplay(); }

    The final code segment needed to successfully run an animation in OpenGL is the main() function.

    Although similar to our previous main functions, notice the glutInitDisplayMode() is set to

    GLUT_DOUBLE | GLUT_RGB. Without the GLUT_DOUBLE parameter double buffering and hence

    animation would not occur.

    void main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); // Set initial Window position glutInitWindowPosition(100, 100); // Set Window Size glutInitWindowSize(WIDTH, HEIGHT); // Set Window Title glutCreateWindow("CMSC405 Week 6_1"); // Initialize init(); // Display function call glutDisplayFunc(displayFcn); // Window reshape call glutReshapeFunc(winReshapeFcn); // Mouse and Keboard functions calls glutMouseFunc(mouseFcn); glutKeyboardFunc(keyboard); glutMainLoop(); }

    The complete source code listing is found in CMSC405Week6_1.cpp. A snap shot of running this

    animation is shown below. You can start and stop the animation by using the left and right mouse

    buttons or by clicking the 1 or 2 keys.

  • 6

    We can begin to bundle additional OpenGL functions into our code to increase functionality and reduce

    the amount of code that needs to be written from scratch. For example, we can use glScalef(), and

    glRotatef() functions to scale and rotate the objects we previously created.

    In the following code, additional rectangles have been created and OpenGL functionality has been

    added to make a different animation. First, a white rectangle is created and positioned at the initial x

    and y positions. If this was the only object, the animation would look similar to the previous one as the

    object positions are changed based on the damped sin wave.

    A yellow square is added next but within its own push and pop sequence where the square is rotated by

    an specified angle about the z-axis. The object is then scaled and finally positions are determined by the

    damped Sin wave equation. The red square rotates about the z-axis in a clockwise direction. The green

    square rotates about the z-axis in a counter clockwise rotation. Finally, a smaller blue square pulsates in

    the center having as the rotation for all axis is set to 0 for the glRotatef() call. Setting these values to 0

    has the net results of reducing the object in size until it disappears and then reappears.

    // Generate the Graphics void displayFcn(void) { // Clear display window. glClear(GL_COLOR_BUFFER_BIT); // Set the graphic objects color glColor3f(1.0, 1.0, 1.0); // Your graphics code here // Create one rectangle only impacted by xpos/ypos glRectf(xpos, ypos, xpos+20.0, ypos+20.0); // Yellow square glColor3f(1.0, 1.0, 0.0); glPushMatrix();

  • 7

    glRotatef(angle, 0.0, 0.0, 1.0); glScalef(xscale, yscale, 1.0f); // Adding the Damped Sin wave in addition to scale and rotate glRectf(xpos, ypos, xpos+100, ypos+100); glPopMatrix(); // Red Square rotating clockwise about z-axis glColor3f(1.0, 0.0, 0.0); glPushMatrix(); glRotatef(angle, 0.0, 0.0, -1.0); glRectf(-20.0, -20.0, 20.0, 20.0); glPopMatrix(); // Green square rotating counter-clockwise about z-axis glColor3f(0.0, 1.0, 0.0); glPushMatrix(); glRotatef(angle, 0.0, 0.0, 1.0); glRectf(-15.0, -15.0, 15.0, 15.0); glPopMatrix(); // Blue square rotating glPushMatrix(); // Setting all components to 0 simulates reduction in object size glRotatef(angle, 0.0, 0.0, 0.0); glColor3f(0.0, 0.0, 1.0); glRectf(-10.0, -10.0, 10.0, 10.0); glPopMatrix(); // Call the SwapBuffers glutSwapBuffers(); // Execute OpenGL functions glFlush(); }

    The angle, scale and positions are controlled in the rotateHex() method. Note in the code

    below the values to increment as well as method to reset values are provided for the

    angle, scale and positions. The resets are needed to keep the display within the window

    position constraints and within reasonable angle and scale constraints.

    // Controls the scale, angel and positions void rotateHex(void) { Sleep(SLEEPMS); // Set the scale increments and resets xscale -= 0.01; yscale -= 0.01; if (xscale

  • 8

    angle += 10; if (angle >= 360) { angle = 0; } // Set the position and resets xpos += 1; ypos = fabs(AMP*sin(2 * M_PI*F0*TS*xpos)*exp(-1.0*TS*xpos)); if (xpos > WIDTH) { xpos = 1; } glutPostRedisplay(); }

    The code found in CMSC405Week6_2.cpp when run will display the following graphic. Animation is

    controlled using the left mouse button, right mouse button and the 1 and 2 keyboard keys. Once

    again, you should analyze the code, modify it and experiment with it to understand the possibilities

    available within this small amount of code.

    3D animation

    Using the same process as shown in the 2D animations, 3D shapes can come to life. In the following

    displayFnc() call a wireframe Sphere is initially placed in the center of the screen. When the animation

    starts, parameters to control the x and y positions, scale, rotation and RGB colors are changed. After

    each iteration the parameters are slightly different causing the sphere to move around the screen,

    resize, rotate and change colors. Notice the glRotatef() call specifies rotation about both the x and z axis.

    Also, in the example, the scale is uniform for x, y and z coordinates.

  • 9

    // Display Function void displayfcn() { // Clear color and depth buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Model view matrix mode glMatrixMode(GL_MODELVIEW); // Reset the model-view matrix // This is done each time you need to clear the matrix operations // This is similar to glPopMatrix() glLoadIdentity(); // Colors controlled by tranform function glColor3f(R, G, B); // Since we are in ModelView we need to move to World coordinates // xpos, ypos controlled by tranform function glTranslatef(xpos, ypos, -7.0f); // Scale controlled by tranform function glScalef(scale, scale, scale); // Rotate as dictated by angle parameter glRotatef(angle, 1.0f, 0.0f, 1.0f); // Add a wireSpere mesh with 1.5 radius and 15x15 gridline glutWireSphere(1.5, 15, 15); // Double buffering glutSwapBuffers(); }

    The transform() function is used to set and reset as needed each of the parameters used to control the

    animation. Notice the rotation angle adjusts by 5 degrees and resets once it is greater than or equal to

    360 degrees. The scale adjusts by 0.01 and resets once the value approaches 0. The x and y positions

    change by 0.1 each iteration and reset once the values get close to absolute of 3. This value was selected

    for this perspective as the sphere begins to move off of the projection screen near this value. Depending

    upon your z position and your gluPerspective() parameters, this value may be different for your

    applications. The RGB components are adjusted by 0.01, 0.02 and 0.03, respectively. Each is reset when

    the approaches 0.

    void transform(void) { Sleep(100); angle += 5.0f; // Resent if get out of window position if (angle >=360.0) { angle = 0.0f; } // scale factor scale -= 0.01f; if (scale

  • 10

    if (xpos >= 3.0f) xpos = -3.0f; // ypos ypos -= 0.1f; if (ypos

  • 11

    // This is the camera view and objects align with view frustum gluPerspective(45.0f, aspect, 0.1f, 100.0f); }

    A snapshot of running the code found in CMSC405Week6_3.cpp is shown below:

    Adding an on screen menu text for directions is fairly straight forward. You have to first define the

    coordinates and content of the text. The following code will provide directions for running a sphere

    animation.

    void displayDirections(void){ // Directions glColor3f(1.0f,1.0f,0.0f); renderBitmapString(-0.8, 2.7, (void *)font, "Sphere Animation v1.0"); renderBitmapString(-0.8, 2.55, (void *)font, "press r to Rotate"); renderBitmapString(-0.8, 2.4, (void *)font, "press s to Scale"); renderBitmapString(-0.8, 2.25, (void *)font, "press t to Translate"); renderBitmapString(-0.8, 2.1, (void *)font, "press c to Change Colors"); renderBitmapString(-0.8, 1.95, (void *)font, "press a for All"); renderBitmapString(-0.8, 1.8, (void *)font, "press n to stop"); }

    To gain individual control of each of the scale, translate, rotate and color functions, we can separate the

    parameter control into multiple functions.

    void rotate(void){ Sleep(SLEEPMS);

  • 12

    angle += 5.0f; // Resent if get out of window position if (angle >= 360.0) { angle = 0.0f; } glutPostRedisplay(); } void translate(void){ Sleep(SLEEPMS); // xpos xpos += 0.1f; if (xpos >= 3.0f) xpos = -3.0f; // ypos ypos -= 0.1f; if (ypos

  • 13

    xpos += 0.1f; if (xpos >= 3.0f) xpos = -3.0f; // ypos ypos -= 0.1f; if (ypos

  • 14

    glutIdleFunc(doAll); break; case 'n': // stop all glutIdleFunc(NULL); break; default: break; } }

    Running the code found in CMSC405Week6_4.cpp results in the following graphic display. Following the

    menu options allows a user to have more fine-tuned control over the sphere animation properties.

    Finally, we can additional shapes to the scene to make it more interesting. When doing this, we can use

    push/pop events glLoadIdentity() calls to control the animation on each shape. Adding additional 3D

    shapes to resemble a drilling device is possible with the following code. After a wire sphere is added,

    three additional 3D shapes using the glutWireCube(1.0) calls are added. Notice the matrix is reloaded prior to adding the shapes to reset the matrix operations. Appropriate

    translate, scale and rotate functions are used to create the appropriate placement and

    subsequent animations. When building these scenes, graph paper will assist; however; some

    trial and error for those fine tune adjustments might be needed.

  • 15

    // Display Function void displayfcn() { // Clear color and depth buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Model view matrix mode glMatrixMode(GL_MODELVIEW); // Reset the model-view matrix // This is done each time you need to clear the matrix operations // This is similar to glPopMatrix() glLoadIdentity(); // Call Display Directions function displayDirections(); // Colors controlled by tranform function glColor3f(R, G, B); // Since we are in ModelView we need to move to World coordinates // xpos, ypos controlled by tranform function glTranslatef(xpos, ypos, -7.0f); // Scale controlled by tranform function glScalef(scale, scale, scale); // Rotate as dictated by angle parameter glRotatef(sangle, 1.0f, 0.0f, 1.0f); // Add a wireSpere mesh with 1.5 radius and 15x15 gridline glutWireSphere(0.75, 15, 15); // Add a wire cube // Create a Left Wing glLoadIdentity(); glTranslatef(-1.3, 0.0, -7.0); glScalef(1.0, 0.2, 0.7); glRotatef(langle, 1.0f, 0.0f, 0.0f); glutWireCube(1.0); // Create a Right Wing glLoadIdentity(); glTranslatef(1.3, 0.0, -7.0); glScalef(1.0, 0.2, 0.7); glRotatef(angle, 1.0f, 0.0f, 0.0f); glutWireCube(1.0); // Create a Rudder glLoadIdentity(); glTranslatef(1.3, 0.0, -7.0); glScalef(0.1, 2.2, 0.7); glRotatef(rangle, 0.0f, 0.0f, 1.0f); glutWireCube(1.0); // Double buffering glutSwapBuffers(); }

  • 16

    Individual functions to control the rotation of each of the drill components is implemented with this

    code:

    void leftRotate(void){ Sleep(SLEEPMS); langle += 5.0f; // Resent if get out of window position if (langle >= 360.0) { langle = 0.0f; } glutPostRedisplay(); } void sphereRotate(void){ Sleep(SLEEPMS); sangle += 5.0f; // Resent if get out of window position if (sangle >= 360.0) { sangle = 0.0f; } glutPostRedisplay(); } // Rudder angle void rudderRotate(void){ Sleep(SLEEPMS); rangle += 5.0f; // Resent if get out of window position if (rangle >= 360.0) { rangle = 0.0f; } glutPostRedisplay(); }

    Similar to the previous example, keyboard control is implemented using this function:

    void keyboard(unsigned char key, int x, int y) { switch (key) { case 's': // Rotate glutIdleFunc(sphereRotate); break; case 'r': // Translate glutIdleFunc(rudderRotate); break; case 'l': // Translate glutIdleFunc(leftRotate); break; case 'c': // Change colors glutIdleFunc(changeColors); break;

  • 17

    case 'a': // Do all glutIdleFunc(doAll); break; case 'n': // stop all glutIdleFunc(NULL); break; default: break; } }

    Running the code found in the file CMSC405Week6_5.cpp will result in the following graphic results:

    You are encouraged to continue to experiment with the code, creating your own unique 3D animations.

    It takes some to master the both the placement of the objects and the animation sequences. But with

    time, you will be to create some impressive 3D animations.