|
Technical Details
4/4/05
I. Implement a Renderer
II. Motion Control Systems
III. Maya
I. Implement a Renderer
Assignment: Implement a polygonal renderer.
Course: Computer Graphics II, George Washington University.
Tools: Java, Swing.
The only Java drawing function I used was the 2D function Graphics.drawLine(). Everything else was built on top of that, including my own vector and matrix classes. The models were supplied to the students as text files specifying a list of polygonal vertex coordinates followed by a list of edges. I used Swing to construct the GUI.
1) Perspective Transformation and Camera Controls
The first step in my rendering pipeline is to read in an object model from a text file of vertices and edges, and display the model in wireframe mode using a perspective projection. For simplicity's sake, my renderer displays only one object at a time.
Every time the user selects a new model, the camera's center of attention and rotation pivot is set to the center of the object, and the camera's film plane is sized according to the object's bounding radius. It is nearly impossible to lose sight of the neatly framed object while adjusting the camera controls for rotating, panning, zooming, and film plane size. These sliders animate the wireframe display of the object in realtime.
Rotating a camera about a pivot centered on the object looks the same as rotating the object in front of a stationary camera. However, because it is the camera rather than the object that moves, my camera controls can be used further down the pipeline to precisely configure the placement of lights and textures.
2) Scanline Interpolation and Z-Buffer Hidden Surface Removal
I used an edge table node structure and the standard bilinear interpolation method of interpolating first between adjacent polygonal vertices, and then along scanlines, in order to calculate z-depth, light intensity (Gouraud shading), normal vectors (Phong shading), and texture uv coordinates for each polygon's pixels in image space. Only the pixels closest to the camera in the z-buffer get written to the image buffer and rendered.
3) Phong Illumination Model
I implemented directional and ambient lights using a variant of the Phong illumination model where the halfway vector H between the camera vector V and the light vector L is used to calculate the specular reflection. Both the light and the camera are assumed to be infinitely far away from the object. This simplifies the shading calculation, as H and L need only be calculated once.
4) Lighting and Shading Controls
My renderer supports constant, Gouraud, and Phong shading. Supersampling options include 1, 4, 9, and 16 samples per pixel.
I simplified my lighting controls by creating a shadow-casting key light that emits both diffuse and specular light, fill and rim lights that do not cast shadows and only emit diffuse light, and an ambient light.
The placement of all three directional lights can be configured via their respective "Look Through Light" buttons, which render the scene from the light's point of view and cause the camera controls to affect the light rather than the camera. Individual color pickers and sliders control the color, specular color, and intensity of the lights, and the color, ambient reflectivity, diffuse reflectivity, specular reflectivity, and specular cosine power of the object's surface.
5) Texture Mapping
I created three sets of controls for texture mapping: one for selecting the image file to be used for the projection, one for selecting the type of projection (spherical, cylindrical, or planar), and one for selecting whether to orient the projection along world or camera coordinate axes. Using this last feature, I can map the texture to the object at any angle, and then move the camera to view the textured object at a different angle. The texture gets mapped to the object the first time the object is drawn on the screen so the object does not "swim" through the texture.
6) Depth Map Shadows
I implemented a standard depth map shadow algorithm, where the scene is rendered twice, once from the light's point of view and once from the camera's point of view. Each camera pixel is then transformed to light space and compared with the light z-buffer to see if it's in shadow. To create soft shadows, I implemented percentage closer sampling.
My shadow controls include options for turning shadow casting on and off, changing the size of the depth map, changing the amount of blur, and viewing the shadow map itself.
II. Motion Control Systems
Assignment: Implement keyframe-based and dynamics-based motion control systems.
Course: Computer Animation, George Washington University.
Tools: C++, RenderMan Interface Procedural API, BMRT 2.6, Maya 5.
I did these labs using the BMRT 2.6 renderer, which was provided to the GWU students for educational use. The basic structure of all my animations is to read in models as .rib files exported from Maya, use my own C++ animation classes to set up rigid body transformations, call RiConcatTransfrom() to apply the transformations, and output the frames between RiFrameBegin() and RiFrameEnd() calls.
I did all my setup and parameter tweaking directly in the C++ code rather than through a GUI. My animation classes were designed to make this as flexible, intuitive, and painless as possible in order to produce attractive animations. One minor frustration was that BMRT 2.6 cannot do motion blur, so I had live with some amount of strobing for fast animations.
1) Spline Interpolation
The spline interpolation shown here is a Catmull-Rom spline using rotational and positional keyframes and Euler angle orientation representation. I also implemented B-Spline interpolation, linear interpolation, and quaternion orientation representation and interpolation.
2) Articulated Figure
To give this character even a minimal amount of weight, I had to implement a timeline, a system for keying the six degrees of freedom and rotate order of each joint, a system for specifying linear, spline, and broken tangents for the animation curves, and a grouping hierarchy that supports an arbitrary number of levels. The heart body is actually grouped with itself in order to accommodate a pivot centered at the pelvis.
Even so, setting the keys was like trying to draw with pencil and paper while wearing boxing gloves. Or working in Maya, but only using MEL and never touching the Graph Editor. The forward kinematic legs were another major hassle, but FK was easier to implement than IK.
3) Dynamics
For collisions between balls, I used an impulse force to take into account the mass and incoming velocity of the colliding objects, but I did not calculate rotational dynamics. For collisions between balls and walls, I simply reflected the velocity normal to the collision and multiplied it by the coefficient of restitution. All physics-based calculations are carried out using "real-world" units: 32 ft/sec2 for acceleration due to gravity, and an appropriately sized room and appropriately weighted balls such that the results look reasonable. These units are then converted to arbitrary RenderMan Interface units for rendering.
4) Particles
I implemented a particle system that supports multiple emitters and arbitrary fields. Emitters are parameterized according to emitter position, emitter orientation, emitter spread angle, spread distribution, particles per timestep, particle color, particle speed, amount of variation in particle speed, particle lifetime, and duration of particle emission. Particles are rendered as constant-shaded spheres.
III. Maya
I incorporated a rigid body dynamics simulation into a piece of anthropomorphic character animation I had originally done for a Maya I class at the Corcoran College of Art & Design. The animation shows a key and a heart-shaped keychain ornament breaking away from their keyclip and hopping away. The dynamics simulation enhances the motion of the heart's interconnected keyrings, which need to bounce and slide in a physically realistic manner as the heart gets up and starts hopping.
My original rig was constructed using nonlinear deformers, connected attributes, driven keys, a hierarchy of point, parent, and orient constraints, and a few MEL shelf buttons. For the dynamics simulation, I used a nail constraint parented to the hopping heart, a ground plane, a gravity field, and a few invisible keyframed "bumper" objects to direct the motion of the two interconnected keyrings.
My dynamics simulation begins at the point in time right after the heart finishes its pirouette, and right before it begins its hops. The motion of the key and the heart and the initial motion of the keyrings during the pirouette is entirely keyframed.
|