CS 4451 Group Projects, Fall 2004


Marlena Frank & Charles Whittington


Project 1-E:

Biker Bob moves along a Subdivided Curve


Questions? Comments? Please email Marlena Frank or Charles Whittinton


Instructions for Camera Operation:
B = move "Biker Bob" along each point

I = move camera up

K = move camera down

J = move camera left

L = move camera right

N = calculate the normal

0 (zero) = move camera to original position


Instructions for Subdivision Operation:

Q = Subdivide with Quadratic B-Spline

C = Subdivide with Cubic B-Spline

F = Subdivide with Four Point

A = Subdivide with Jarek's Method


See Biker Bob travelling into the curve

1. Subdivide the object as desired with Q, C, F, A

2. Manipulate the camera to aid in viewing the biker

3. Press N to calculate the Normals

4. Press B to move Bob the Biker along the vertices

5. Please note that there is a maximum of 200 available vertices. After this, the biker may not travel along the curve correctly.


The Biker without leaning into curves
The biker can be seen travelling vertically along the curve in the following screenshots:


Calculating the normal of each vertex
To calculate the normal at each vertex, we used the scheme posted on Dr. Rossignac's webpage of the following:
B=P(s);

A:=B.previous;

C:=B.next;

V:=AC/2 ;

N:=AC.unit.left ;

r(s) := V*V / (2BC*N);

Please note that we assumed that whenever you come to the line of: r(s) := V*V / (2BC*N), we assumed that whenever you divide by zero, that this would make the tilt 0. Therefore Bob would be displayed vertically.

In order to limit the size of the normal, we scaled it down. The scaling that we used can be seen under the #define DIV_R_CONST at the header of the file.

r=DIV_R_CONST/r;

We found that r was such a small number that we needed to scale it to make it larger in some way to show the curving of the biker.


Calculating the tilt and direction
To calculate the Biker leaning into the curve, we had to calculate the tilt of the biker and then render him accordingly.

To tilt the biker, we first had to calculate the distance between the vertex that the biker was at to the normal. Then based upon the magnitude of this distance, we calculated a ratio from 0 to 180 that would determine how much the biker leaned.

We understand that there is some inaccuracy in the fact that we convert our values in the calculations for the tilt from a float to an integer. We've also found that there is some noise in this calculation, but even after Whit spent an hour and a half with the TA, they were still unable to find the cause for this.

Although, we've found this scheme to work, we think that we could find a better scheme to use that would yield more appropriate results. To determine the direction of the lean, we had the biker lean into the same direction as the curve, simulating the lean that the biker would use in real-life were he presented with a similar curve.

Please note that the To see where we're calculating the curvature in the file, please see the calcNorm() function. To see the normals drawn, go to the #define DRAW_NORMALS at the top of the file and set it to 1.

In order to calculate the direction of the biker, we needed to calculate the tangent to that vertex. To do this, we used the following:

A = current vertex

B = next vertex

angle = atan2((B.y - A.y), (B.x - A.x))

angle = angle * (180/PI)

This found the angle between the current and next vertices. Then, since atan2 returns a value in radians, we needed to convert this value to degrees with the second calculation.


Transformations and the Matrix Stack
After calculating the angles that we wanted the biker to tilt and the direction for him to aim, we needed to draw him by adding onto the Matrix Stack. To do so, we used the following:
glPushMatrix(); //Adds a frame to the matrix stack

/** The following are the transformation functions used on the entire object **/

glTranslatef(vertices[k].x, vertices[k].y, 0);

/** The following is calulating the direction of the biker. The rotation has to be made on the z-axis, which points from the ground up through the biker's head **/

glRotatef(angle, 0, 0, 1);

/** This then tilts the biker according to the curve from the second angle calculated **/

glRotate(angle2, 1, 0, 0);

/** Draws the green body of the man **/

draw_pyramid();


From here, we needed to add another frame to the matrix stack in order to add the wheels and head

/* Drawing the first wheel */

glPushMatrix();

glColor3f(1.0, 0.0, 0.0);

glTranslatef(-((MAN_WIDTH)/2), 0.0, MAN_FLOAT);

glutSolidSphere(WHEEL_RADIUS, 50.0, 50.0);

glPopMatrix();


/* Drawing the second wheel */

glPushMatrix();

glColor3f(1.0, 0.0, 0.0);

glTranslatef(((MAN_WIDTH)/2), 0.0, MAN_FLOAT);

glutSolidSphere(WHEEL_RADIUS, 50.0, 50.0);

glPopMatrix();


/* Drawing the biker's head */

glPushMatrix();

glColor3f(0.0, 0.0, 1.0);

glTranslatef(0.0, 0.0, (MAN_HEIGHT));

glutSolidSphere(HEAD_RADIUS, 50.0, 50.0);

glPopMatrix();


glPopMatrix();

We first had to add a frame to the matrix stack and then translate to the location that we wanted to draw the biker (ie. the current vertex). From there we first rotated the biker in accordance with the direction, and then for the tilt with the curve.

One problem we found in this case was that whenever we attempted to rotate the object first and then translate, the object was not placed in the expected location. One reason for this was brought up by a colleague in class - that OpenGL only allows rotations to occur around the origin, which would explain the strange location that occured whenever we attempted this out of order.

Here we drew the pyramid (the green body of the biker), and then added another frame onto the matrix stack (in essence adding another layer onto the image to allow us to use this as our current set of axes. For each wheel we changed its color, and then translated either half the width of the man forward or backwards on the x-axis to add each wheel, and then we drew the sphere for the wheels. At this point we had to pop the frame off the matrix stack to return to our previous set of positions.

At this point we added a final frame onto the matrix stack and changed the color for the biker's head. We then translated up to the man's height and drew the solid sphere for his head. We then popped this frame from the matrix stack and then popped this frame as well to draw the entire image after the subsequent translations and rotations.

Original


Jarek's Subdivision


Four-Point Subdivision


Cubic B-Spline Subdivision


Quadratic B-Spline Subdivision


Discussion:

Of all of the subdivision techniques, the smoothest subdivision techniques are the Cubic B-Spline and Jarek's Method. This is evidenced by the fact that the biker leans more regularly with these subdivision techniques rather than with the others. The biker's positions in our code is not entirely realistic because we have no control over whether he tilts underground or not, but he does tilt in accordance with the curvature of the object, unless our calculations or incorrect. In the future, we would not only change this, but also the limitations on the number of subdivisions allowed, giving a clean error instead of a simple print statement.