Dragon Following Motorcycle

Introduction

This page describes the development and functionality of a program for animating a flying dragon who follows a motorcycle riding along random terrain. The program was developed by Chris Dragon for CMP 161, "Visualization and Computer Animation", at the University of California, Santa Cruz.

The Program

The program uses FLTK for the user interface and OpenGL for rendering objects in 3D. Here is what you see when you run the program:

In order for the program to show everything correctly, you must have dragon.dat, cycle.dat, terrain.in, grass.ppm, scales.ppm, and wing.ppm in the same directory as the program.

Hold the left mouse button to rotate the camera. Shift-left or middle mouse button moves the camera up/down and left/right. Right mouse button lets you zoom in and out. You can choose different default cameras using the radio buttons in the lower right. By default, you are using the "Dragonback" camera. Notice that the camera follows the dragon, and also matches his pitch, roll, and yaw. Choose the "Dragon" camera, and the camera only follows the dragon's position, letting you see him from different angles as he turns. The same goes for the "Bike" camera, which follows the motorcycle. The "Bike Rider" camera is similar to "Dragonback" except the camera doesn't roll with the bike. Instead, it translates a little to make it appear you are in the seat on the motorcycle and keeping your head straight up:

The "Aerial" camera lets you see the scene from a fixed point high above. Zoom out a little to see the edges of the terrain. Notice that as the motorcycle moves too close to the edge of the terrain, a new strip of terrain is generated along the terrain edge closest to the cycle, while a strip is removed along the farthest edge. Because the camera is moving to keep the terrain centered, this makes the dragon and cycle appear to "jump" back towards the center of the terrain whenever the terrain shifts. I thought this was better than letting the terrain and everything slowly drift out of view of the camera. This is about as close as the motorcycle can get to the edge of the terrain:

The default piece of terrain is loaded from a data file, and actually represents height data for the UCSC College 8 campus. As the terrain shifts, new terrain strips are generated with random heights. The height difference of neighboring points is limited such that the terrain can never be too jagged. Normals for the new edge are generated, and the points along the old edge are recalculated to match the influence of the new edge's slopes.

Press "Pause" to freeze the animation. Use the "Speed:" slider to adjust the rendering speed. As you move it to the left, the number of frames per second (FPS) is lowered down to a minimum of 1. As you move to the right, FPS does not increase, but the dragon and cycle move farther in each frame.

You can choose between "Wire" and "Fill" rendering in the lower left. "Show Target" shows a green and red compass point at the point in space the dragon is chasing. The point hovers over the motorcycle, making it appear the dragon is generally chasing the cycle. "Show Helpers" displays normals on all objects in the scene, as well as other helper objects (useful in debugging) such as a yellow line representing the direction and magnitude of the motorocycle's velocity. Notice the normals on the dragon (especially on the wing in this picture) float in midair, showing the stationary frames that are morphed together to create his movement:

The dragon is saved on disk as only about 12 frames of animation. Vertices between the frames are morphed together using linear interpolation to create smooth movement. The dragon model itself is something I created in my spare time over a number of years. The scale texture is done by mapping a square of repeating scale texture to each square on the dragon, which can cause stretching on a few thin polygons but generally looks pretty good. Everything having to do with the dragon was done for the final project of a CS160 class about a year ago, while this project is an extension of that work.

The motorcycle is a public domain object which I converted to ASE format and edited out some of the more complex geometry to reduce polygon count. Getting the motorcycle tires to land on the terrain without penetrating it was the hardest part of the project. Here is an example of how close the tires get to the ground:

I pretty much invented my own method of collision detection using formulas from a powerpoint presentation from another 3D class (not a class I've taken). The following formula for calculating the intersection point of a ray with a plane was key:

In general my strategy was as follows:

The motorcycle turns randomly as it moves. It will only turn when both tires are known to be on the ground, which means whenever it jumps off a hill it will fly straight till it lands and then continue to turn. When not on the ground, gravity will cause the cycle to slowly accelerate downwards. As soon as it hits the ground, downwards velocity is reset, leaving only a default forward velocity in the direction the cycle is pointed. Gravity will continually try to pull the cycle into the ground, causing it to detect collision and move to the surface and reset the velocity in each frame until one of the tires leaves the ground again.

Challenges with the Program

The dragon and cycle were read in from ASE files exported from 3DS Max. To read the dragon ASE file I had taken many shortcuts and avoided a good parsing of the ASE file format. To read both the dragon and the motorcycle at the same time, I had to re-write a lot of the ASE file reading functionality to handle the file structure more robustly. Because the motorcycle uses multiple materials with multiple sub-materials and multiple objects, my original Mesh class turned into Mesh, Object, and Material classes. Because the motorcycle has sharp edges (unlike the dragon), I had to modify my code to support multiple normals per vertex. All of these changes took a lot more time than I would have anticipated.

The biggest time waste came due to a bug where parts of the motorcycle would flash from light to dark as the camera moved. I wasted an entire Saturday doing everything conceivable to fix that effect, simplifying the whole program down to rendering a single polygon that showed the same flashing. It turned out to be caused by the gl "shininess" material property being set too low. You only see the flashing when you render a triangle where the normals of each vertex are almost equal (all the flat pieces of the motorcycle). I had assumed shininess was scaled to a value between 0 and 1 like every other opengl parameter, so I never tested setting it to a high value like 50 which is what finally fixed the problem.

The other time consuming part was collision detection with the tires and ground. I didn't want to use an inexact standard technique like box collision, so experimenting and figuring out my own method based on tire radius was a long process, but pretty fun.

Demo Movie

For a short demo video which shows the dragon chasing the cycle, riding the cycle, and the cycle jumping off hills, click here. You will need the DivX 4 MPEG codec installed.

Questions or Comments?

Chris Dragon, cdragon@draconic.com