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.