Project 4: Animation

Bogdan Gevko - gevkob@oregonstate.edu

Recorded Video

HTML Report

Project Details


As in prior projects, I started with a sketch in Blender. I read somewhere that a classic exercise for all beginner animators is to start with a bouncing ball, so that’s what I did! I tried to incorporate a few animation principles such as squash, stretch, and even a bit of anticipation. Here’s how the animation sketch turned out:

Blender animation sketch

The next challenge was figuring out how to get the same effect with the Keytimes helper function. I ran into a few problems:

Actually, that was the main problem. There’s 12 keyframes in each cycle, and I needed to figure out how to fit that neatly into 10 seconds. I ended up slowing down the animation quite a lot (to 2 seconds). The above version is that 2 second version. I also realized that perhaps it was a bit too fast anyways, so the result turned out okay.

Then, it was just a matter of creating a single 2 second cycle in C++, and then copying it over 5 times to fit the 10 second window. I did this by looking at each frame in Blender, and then dividing the current frame by 30 (the FPS value I used), which gave me the exact time value for each keyframe.

I used the same technique for the platform to make it seem as if it’s reacting to the weight of the ball.

After that, I added a few more elements inside C++ to meet the rest of the assignment requirements, and here’s the final result:

OpenGL Bounce

Timetables


	// Animate ball
	Ypos1.Init();
	Ypos1.AddTimeValue( 0.000, 0.0 );
	Ypos1.AddTimeValue( 0.133, -0.05 );
	Ypos1.AddTimeValue( 0.500, -0.08 );
	Ypos1.AddTimeValue( 0.700, -0.07 );
	Ypos1.AddTimeValue( 0.833, 0.0 );
	Ypos1.AddTimeValue( 1.000, 1.0 );
	Ypos1.AddTimeValue( 1.200, 2.0 );
	Ypos1.AddTimeValue( 1.433, 2.1 );
	Ypos1.AddTimeValue( 1.633, 2.2 );
	Ypos1.AddTimeValue( 1.733, 2.1 );
	Ypos1.AddTimeValue( 1.933, 1.0 );
	Ypos1.AddTimeValue( 2.000, 0.0 );

	Ypos1.AddTimeValue( 2.000, 0.0 );
	Ypos1.AddTimeValue( 2.133, -0.05 );
	Ypos1.AddTimeValue( 2.500, -0.08 );
	Ypos1.AddTimeValue( 2.700, -0.07 );
	Ypos1.AddTimeValue( 2.833, 0.0 );
	Ypos1.AddTimeValue( 3.000, 1.0 );
	Ypos1.AddTimeValue( 3.200, 2.0 );
	Ypos1.AddTimeValue( 3.433, 2.1 );
	Ypos1.AddTimeValue( 3.633, 2.2 );
	Ypos1.AddTimeValue( 3.733, 2.1 );
	Ypos1.AddTimeValue( 3.933, 1.0 );
	Ypos1.AddTimeValue( 4.000, 0.0 );

	Ypos1.AddTimeValue( 4.000, 0.0 );
	Ypos1.AddTimeValue( 4.133, -0.05 );
	Ypos1.AddTimeValue( 4.500, -0.08 );
	Ypos1.AddTimeValue( 4.700, -0.07 );
	Ypos1.AddTimeValue( 4.833, 0.0 );
	Ypos1.AddTimeValue( 5.000, 1.0 );
	Ypos1.AddTimeValue( 5.200, 2.0 );
	Ypos1.AddTimeValue( 5.433, 2.1 );
	Ypos1.AddTimeValue( 5.633, 2.2 );
	Ypos1.AddTimeValue( 5.733, 2.1 );
	Ypos1.AddTimeValue( 5.933, 1.0 );
	Ypos1.AddTimeValue( 6.000, 0.0 );

	Ypos1.AddTimeValue( 6.000, 0.0 );
	Ypos1.AddTimeValue( 6.133, -0.05 );
	Ypos1.AddTimeValue( 6.500, -0.08 );
	Ypos1.AddTimeValue( 6.700, -0.07 );
	Ypos1.AddTimeValue( 6.833, 0.0 );
	Ypos1.AddTimeValue( 7.000, 1.0 );
	Ypos1.AddTimeValue( 7.200, 2.0 );
	Ypos1.AddTimeValue( 7.433, 2.1 );
	Ypos1.AddTimeValue( 7.633, 2.2 );
	Ypos1.AddTimeValue( 7.733, 2.1 );
	Ypos1.AddTimeValue( 7.933, 1.0 );
	Ypos1.AddTimeValue( 8.000, 0.0 );

	Ypos1.AddTimeValue( 8.000, 0.0 );
	Ypos1.AddTimeValue( 8.133, -0.05 );
	Ypos1.AddTimeValue( 8.500, -0.08 );
	Ypos1.AddTimeValue( 8.700, -0.07 );
	Ypos1.AddTimeValue( 8.833, 0.0 );
	Ypos1.AddTimeValue( 9.000, 1.0 );
	Ypos1.AddTimeValue( 9.200, 2.0 );
	Ypos1.AddTimeValue( 9.433, 2.1 );
	Ypos1.AddTimeValue( 9.633, 2.2 );
	Ypos1.AddTimeValue( 9.733, 2.1 );
	Ypos1.AddTimeValue( 9.933, 1.0 );
	Ypos1.AddTimeValue( 10.000, 0.0 );

	ScaleXZ.Init();
	ScaleXZ.AddTimeValue( 0.000, 0.409 );
	ScaleXZ.AddTimeValue( 0.133, 0.479 );
	ScaleXZ.AddTimeValue( 0.500, 0.641 );
	ScaleXZ.AddTimeValue( 0.700, 0.479 );
	ScaleXZ.AddTimeValue( 0.833, 0.409 );
	ScaleXZ.AddTimeValue( 1.000, 0.130 );
	ScaleXZ.AddTimeValue( 1.200, 0.409 );
	ScaleXZ.AddTimeValue( 1.433, 0.409 );
	ScaleXZ.AddTimeValue( 1.633, 0.409 );
	ScaleXZ.AddTimeValue( 1.733, 0.409 );
	ScaleXZ.AddTimeValue( 1.933, 0.130 );
	ScaleXZ.AddTimeValue( 2.000, 0.409 );

	ScaleXZ.AddTimeValue( 2.000, 0.409 );
	ScaleXZ.AddTimeValue( 2.133, 0.479 );
	ScaleXZ.AddTimeValue( 2.500, 0.641 );
	ScaleXZ.AddTimeValue( 2.700, 0.479 );
	ScaleXZ.AddTimeValue( 2.833, 0.409 );
	ScaleXZ.AddTimeValue( 3.000, 0.130 );
	ScaleXZ.AddTimeValue( 3.200, 0.409 );
	ScaleXZ.AddTimeValue( 3.433, 0.409 );
	ScaleXZ.AddTimeValue( 3.633, 0.409 );
	ScaleXZ.AddTimeValue( 3.733, 0.409 );
	ScaleXZ.AddTimeValue( 3.933, 0.130 );
	ScaleXZ.AddTimeValue( 4.000, 0.409 );

	ScaleXZ.AddTimeValue( 4.000, 0.409 );
	ScaleXZ.AddTimeValue( 4.133, 0.479 );
	ScaleXZ.AddTimeValue( 4.500, 0.641 );
	ScaleXZ.AddTimeValue( 4.700, 0.479 );
	ScaleXZ.AddTimeValue( 4.833, 0.409 );
	ScaleXZ.AddTimeValue( 5.000, 0.130 );
	ScaleXZ.AddTimeValue( 5.200, 0.409 );
	ScaleXZ.AddTimeValue( 5.433, 0.409 );
	ScaleXZ.AddTimeValue( 5.633, 0.409 );
	ScaleXZ.AddTimeValue( 5.733, 0.409 );
	ScaleXZ.AddTimeValue( 5.933, 0.130 );
	ScaleXZ.AddTimeValue( 6.000, 0.409 );

	ScaleXZ.AddTimeValue( 6.000, 0.409 );
	ScaleXZ.AddTimeValue( 6.133, 0.479 );
	ScaleXZ.AddTimeValue( 6.500, 0.641 );
	ScaleXZ.AddTimeValue( 6.700, 0.479 );
	ScaleXZ.AddTimeValue( 6.833, 0.409 );
	ScaleXZ.AddTimeValue( 7.000, 0.130 );
	ScaleXZ.AddTimeValue( 7.200, 0.409 );
	ScaleXZ.AddTimeValue( 7.433, 0.409 );
	ScaleXZ.AddTimeValue( 7.633, 0.409 );
	ScaleXZ.AddTimeValue( 7.733, 0.409 );
	ScaleXZ.AddTimeValue( 7.933, 0.130 );
	ScaleXZ.AddTimeValue( 8.000, 0.409 );

	ScaleXZ.AddTimeValue( 8.000, 0.409 );
	ScaleXZ.AddTimeValue( 8.133, 0.479 );
	ScaleXZ.AddTimeValue( 8.500, 0.641 );
	ScaleXZ.AddTimeValue( 8.700, 0.479 );
	ScaleXZ.AddTimeValue( 8.833, 0.409 );
	ScaleXZ.AddTimeValue( 9.000, 0.130 );
	ScaleXZ.AddTimeValue( 9.200, 0.409 );
	ScaleXZ.AddTimeValue( 9.433, 0.409 );
	ScaleXZ.AddTimeValue( 9.633, 0.409 );
	ScaleXZ.AddTimeValue( 9.733, 0.409 );
	ScaleXZ.AddTimeValue( 9.933, 0.130 );
	ScaleXZ.AddTimeValue( 10.00, 0.409 );

	ScaleY.Init();
	ScaleY.AddTimeValue( 0.000, 0.409 );
	ScaleY.AddTimeValue( 0.133, 0.206 );
	ScaleY.AddTimeValue( 0.500, 0.121 );
	ScaleY.AddTimeValue( 0.700, 0.206 );
	ScaleY.AddTimeValue( 0.833, 0.409 );
	ScaleY.AddTimeValue( 1.000, 0.459 );
	ScaleY.AddTimeValue( 1.200, 0.409 );
	ScaleY.AddTimeValue( 1.433, 0.409 );
	ScaleY.AddTimeValue( 1.633, 0.409 );
	ScaleY.AddTimeValue( 1.733, 0.409 );
	ScaleY.AddTimeValue( 1.933, 0.459 );
	ScaleY.AddTimeValue( 2.000, 0.409 );

	ScaleY.AddTimeValue( 2.000, 0.409 );
	ScaleY.AddTimeValue( 2.133, 0.206 );
	ScaleY.AddTimeValue( 2.500, 0.121 );
	ScaleY.AddTimeValue( 2.700, 0.206 );
	ScaleY.AddTimeValue( 2.833, 0.409 );
	ScaleY.AddTimeValue( 3.000, 0.459 );
	ScaleY.AddTimeValue( 3.200, 0.409 );
	ScaleY.AddTimeValue( 3.433, 0.409 );
	ScaleY.AddTimeValue( 3.633, 0.409 );
	ScaleY.AddTimeValue( 3.733, 0.409 );
	ScaleY.AddTimeValue( 3.933, 0.459 );
	ScaleY.AddTimeValue( 4.000, 0.409 );

	ScaleY.AddTimeValue( 4.000, 0.409 );
	ScaleY.AddTimeValue( 4.133, 0.206 );
	ScaleY.AddTimeValue( 4.500, 0.121 );
	ScaleY.AddTimeValue( 4.700, 0.206 );
	ScaleY.AddTimeValue( 4.833, 0.409 );
	ScaleY.AddTimeValue( 5.000, 0.459 );
	ScaleY.AddTimeValue( 5.200, 0.409 );
	ScaleY.AddTimeValue( 5.433, 0.409 );
	ScaleY.AddTimeValue( 5.633, 0.409 );
	ScaleY.AddTimeValue( 5.733, 0.409 );
	ScaleY.AddTimeValue( 5.933, 0.459 );
	ScaleY.AddTimeValue( 6.000, 0.409 );

	ScaleY.AddTimeValue( 6.000, 0.409 );
	ScaleY.AddTimeValue( 6.133, 0.206 );
	ScaleY.AddTimeValue( 6.500, 0.121 );
	ScaleY.AddTimeValue( 6.700, 0.206 );
	ScaleY.AddTimeValue( 6.833, 0.409 );
	ScaleY.AddTimeValue( 7.000, 0.459 );
	ScaleY.AddTimeValue( 7.200, 0.409 );
	ScaleY.AddTimeValue( 7.433, 0.409 );
	ScaleY.AddTimeValue( 7.633, 0.409 );
	ScaleY.AddTimeValue( 7.733, 0.409 );
	ScaleY.AddTimeValue( 7.933, 0.459 );
	ScaleY.AddTimeValue( 8.000, 0.409 );

	ScaleY.AddTimeValue( 8.000, 0.409 );
	ScaleY.AddTimeValue( 8.133, 0.206 );
	ScaleY.AddTimeValue( 8.500, 0.121 );
	ScaleY.AddTimeValue( 8.700, 0.206 );
	ScaleY.AddTimeValue( 8.833, 0.409 );
	ScaleY.AddTimeValue( 9.000, 0.459 );
	ScaleY.AddTimeValue( 9.200, 0.409 );
	ScaleY.AddTimeValue( 9.433, 0.409 );
	ScaleY.AddTimeValue( 9.633, 0.409 );
	ScaleY.AddTimeValue( 9.733, 0.409 );
	ScaleY.AddTimeValue( 9.933, 0.459 );
	ScaleY.AddTimeValue( 10.00, 0.409 );

	// Animate platform
	PlatformY.Init();
	PlatformY.AddTimeValue( 0.000, 0.0 );
	PlatformY.AddTimeValue( 0.133, -0.05 );
	PlatformY.AddTimeValue( 0.500, -0.08 );
	PlatformY.AddTimeValue( 0.700, -0.07 );
	PlatformY.AddTimeValue( 0.833, -0.1 );
	PlatformY.AddTimeValue( 1.000, 0.0 );
	PlatformY.AddTimeValue( 1.200, -0.02 );
	PlatformY.AddTimeValue( 1.333, 0.0 );
	PlatformY.AddTimeValue( 1.433, -0.01 );
	PlatformY.AddTimeValue( 1.566, 0.0 );
	PlatformY.AddTimeValue( 2.000, 0.0 );

	PlatformY.AddTimeValue( 2.000, 0.0 );
	PlatformY.AddTimeValue( 2.133, -0.05 );
	PlatformY.AddTimeValue( 2.500, -0.08 );
	PlatformY.AddTimeValue( 2.700, -0.07 );
	PlatformY.AddTimeValue( 2.833, -0.1 );
	PlatformY.AddTimeValue( 3.000, 0.0 );
	PlatformY.AddTimeValue( 3.200, -0.02 );
	PlatformY.AddTimeValue( 3.333, 0.0 );
	PlatformY.AddTimeValue( 3.433, -0.01 );
	PlatformY.AddTimeValue( 3.566, 0.0 );
	PlatformY.AddTimeValue( 4.000, 0.0 );

	PlatformY.AddTimeValue( 4.000, 0.0 );
	PlatformY.AddTimeValue( 4.133, -0.05 );
	PlatformY.AddTimeValue( 4.500, -0.08 );
	PlatformY.AddTimeValue( 4.700, -0.07 );
	PlatformY.AddTimeValue( 4.833, -0.1 );
	PlatformY.AddTimeValue( 5.000, 0.0 );
	PlatformY.AddTimeValue( 5.200, -0.02 );
	PlatformY.AddTimeValue( 5.333, 0.0 );
	PlatformY.AddTimeValue( 5.433, -0.01 );
	PlatformY.AddTimeValue( 5.566, 0.0 );
	PlatformY.AddTimeValue( 6.000, 0.0 );

	PlatformY.AddTimeValue( 6.000, 0.0 );
	PlatformY.AddTimeValue( 6.133, -0.05 );
	PlatformY.AddTimeValue( 6.500, -0.08 );
	PlatformY.AddTimeValue( 6.700, -0.07 );
	PlatformY.AddTimeValue( 6.833, -0.1 );
	PlatformY.AddTimeValue( 7.000, 0.0 );
	PlatformY.AddTimeValue( 7.200, -0.02 );
	PlatformY.AddTimeValue( 7.333, 0.0 );
	PlatformY.AddTimeValue( 7.433, -0.01 );
	PlatformY.AddTimeValue( 7.566, 0.0 );
	PlatformY.AddTimeValue( 8.000, 0.0 );

	PlatformY.AddTimeValue( 8.000, 0.0 );
	PlatformY.AddTimeValue( 8.133, -0.05 );
	PlatformY.AddTimeValue( 8.500, -0.08 );
	PlatformY.AddTimeValue( 8.700, -0.07 );
	PlatformY.AddTimeValue( 8.833, -0.1 );
	PlatformY.AddTimeValue( 9.000, 0.0 );
	PlatformY.AddTimeValue( 9.200, -0.02 );
	PlatformY.AddTimeValue( 9.333, 0.0 );
	PlatformY.AddTimeValue( 9.433, -0.01 );
	PlatformY.AddTimeValue( 9.566, 0.0 );
	PlatformY.AddTimeValue( 10.00, 0.0 );

	Ypos1.AddTimeValue( 0.000, 0.0 );
	Ypos1.AddTimeValue( 0.133, -0.05 );
	Ypos1.AddTimeValue( 0.500, -0.08 );
	Ypos1.AddTimeValue( 0.700, -0.07 );
	Ypos1.AddTimeValue( 0.833, 0.0 );
	Ypos1.AddTimeValue( 1.000, 1.0 );
	Ypos1.AddTimeValue( 1.200, 2.0 );
	Ypos1.AddTimeValue( 1.433, 2.1 );
	Ypos1.AddTimeValue( 1.633, 2.2 );
	Ypos1.AddTimeValue( 1.733, 2.1 );
	Ypos1.AddTimeValue( 1.933, 1.0 );
	Ypos1.AddTimeValue( 2.000, 0.0 );

	// Animate cam
	Cam.Init();
	Cam.AddTimeValue( 0.00, 0.0 );
	Cam.AddTimeValue( 1.200, 0.1 );
	Cam.AddTimeValue( 2.000, 0.0 );
	Cam.AddTimeValue( 2.00, 0.0 );
	Cam.AddTimeValue( 3.200, 0.1 );
	Cam.AddTimeValue( 4.000, 0.0 );
	Cam.AddTimeValue( 4.00, 0.0 );
	Cam.AddTimeValue( 5.200, 0.1 );
	Cam.AddTimeValue( 6.000, 0.0 );
	Cam.AddTimeValue( 6.00, 0.0 );
	Cam.AddTimeValue( 7.200, 0.1 );
	Cam.AddTimeValue( 8.000, 0.0 );
	Cam.AddTimeValue( 8.00, 0.0 );
	Cam.AddTimeValue( 9.200, 0.1 );
	Cam.AddTimeValue( 10.0, 0.0 );

	Red.Init();
	Red.AddTimeValue( 0.00, 1.0 );
	Red.AddTimeValue( 1.00, 0.64 );
	Red.AddTimeValue( 2.00, 0.1 );
	Red.AddTimeValue( 2.50, 0.0 );
	Red.AddTimeValue( 3.00, 0.1 );
	Red.AddTimeValue( 4.00, 0.64 );
	Red.AddTimeValue( 5.00, 1.0 );
	Red.AddTimeValue( 6.00, 0.64 );
	Red.AddTimeValue( 7.00, 0.1 );
	Red.AddTimeValue( 7.50, 0.0 );
	Red.AddTimeValue( 8.00, 0.1 );
	Red.AddTimeValue( 9.00, 0.64 );
	Red.AddTimeValue( 10.0, 1.0 );

	Green.Init();
	Green.AddTimeValue( 0.00, 0.0 );
	Green.AddTimeValue( 0.00, 0.1 );
	Green.AddTimeValue( 2.00, 0.64 );
	Green.AddTimeValue( 2.50, 1.0 );
	Green.AddTimeValue( 3.00, 0.64 );
	Green.AddTimeValue( 4.00, 0.1 );
	Green.AddTimeValue( 5.00, 0.0 );
	Green.AddTimeValue( 6.00, 0.1 );
	Green.AddTimeValue( 7.00, 0.64 );
	Green.AddTimeValue( 7.50, 1.0 );
	Green.AddTimeValue( 8.00, 0.64 );
	Green.AddTimeValue( 9.00, 0.1 );
	Green.AddTimeValue( 10.00, 0.0 );

	Blue.Init();
	Blue.AddTimeValue( 0.00, 0.0 );
	Blue.AddTimeValue( 1.00, 1.0 );
	Blue.AddTimeValue( 2.00, 0.0 );
	Blue.AddTimeValue( 3.00, 1.0 );
	Blue.AddTimeValue( 4.00, 0.0 );
	Blue.AddTimeValue( 5.00, 1.0 );
	Blue.AddTimeValue( 6.00, 0.0 );
	Blue.AddTimeValue( 7.00, 1.0 );
	Blue.AddTimeValue( 8.00, 0.0 );
	Blue.AddTimeValue( 9.00, 1.0 );
	Blue.AddTimeValue( 10.00, 0.0 );
	```

That’s it! Thanks for reading!