Super-enhanced raytracer CS348b, project 3, 6/08/98 Stanford University, Spring 1997-1998 Jeremy Ginsberg (jeremyg@cs) and Matt Ginzton (magi@cs) ============================================================================ Index to extensions: 1. Texture Mapping (for nearly all material properties) 2. CSG 3. Cylinder primitive 4. Adaptive stochastic supersampling (and subsampling) 5. Height field for bent playing cards 6. Distributed rays for soft shadows from area light sources followed by an index to the images we computed. ============================================================================ Texture Mapping- JJG -------------------- Objects could ask to be textured with the appropriate flag in their name. Valid mapping options were: difftex - diffuse color texture ambtex - ambient color texture spectex - specular color texture transmap - transparency texture (uses red color data only) shinymap - shininess texture (uses red color data only) (modulate only) bumpmap - bump gradient data (uses red color data only) (by Matt Ginzton) Textures were applied in decal mode by default; objects could request a modulation between object material properties and the texture data by adding an additional flag of the form difftexmode, ambtexmode, etc. "shinymap" textures are modulated by default and can not be applied via decal mode for practical purposes. Textures were cached during the initialization phase to speed loading when multiple objects request the same texture file. Matt implemented the bump mapping algorithm in the obvious way, using precomputed texture coordinate partial derivatives (stored with each triangle) from Tamara and Maple and not Mathematica. Texture coordinates were used to find the interpolated color data from the image file. Bilinear interpolation was used. Constructive Solid Geometry - JJG --------------------------------- We implemented CSG to assist in modelling the cards and dice. Three CSG operators were supported: + : combines two (possibly overlapping) volumes - : subtracts one volume from another & : returns the volume common to both operands Objects became CSG objects with the "useCSG" flag in their name strings. A corresponding .csg file was used to construct the hierarchies for a scene, using a prefix tree parser. Each CSG tree became a primitive object in the scene. Implementing these operators robustly proved to be quite a challenge. Many many different possible cases must be handled, and each operator needed fairly unique code to handle its behavior properly. CSG Primitives were treated like volumes to achieve the best results, and therefore only intersections that were actually on the surface of the constructed volume were returned (i.e. no intersections on the interior of volumes, only on the surface). Cards were modeled by applying '&' to a sphere and the corner triangle for each corner on the card. Worked very nicely. The die was painfully modelled by subtracting rectangular prisms from each edge of a cube, then adding cylinders to the edges, and spheres to the corners. It looked nice, though I wouldn't do it again for fun. Cylinder Primitive - JJG ------------------------ I added a cylinder primitive so that the dice would be nice. It used code from Graphics Gems, but took a while to implement correctly nonetheless. We could have used it to model poker chips if we had time. Adaptive stochastic supersampling -- magi ----------------------------------------- Actually, I did subsampling too, so that we could get a quick look at the overall layout of an image (as opposed to the normal raytracing output order, scan line by scan line). Greg Humphreys later pointed out to me that this could actually be seen as supersampling the living heck out of a 1 pixel by 1 pixel image (although not all the pixels get averaged together in the filter -- a discrete number are retained for the output image. But the sampling methodology is the same). For each area I'm considering sampling (which initially is the whole image, much larger than a pixel, when subsampling -- and finally, when supersampling, will be smaller than a pixel), I throw one sample anywhere in the area. If that sample diverges significantly from those in the surrounding areas (as measured by Mitchell's technique of comparing differences in contrast to predefined threshholds for each color component), I divide that area into four (evenly spaced 2x2 grid) and throw three more samples (keeping the first sample in whichever grid cell it belongs). If these four samples diverge, each gets supersampled by the same procedure. I used an area-weighted-average filter for reconstruction. Simple, but the results were visually sufficient even at a low level of supersampling. (By default, our raytracer throws one sample per pixel, then depending on the contrast differences between neighboring pixels, supersamples up to 64 samples per pixel. Both this maximum sampling rate and the minimum are tunable in the UI, so that you can, for example, force 4 samples at every pixel before the adaptive algorithm is applied.) Height field for bent playing cards -- magi ------------------------------------------- Flat cards look really, well, flat. The same way that computer-generated graphic scenes or music can be too regular to be compelling -- although it's a very subtle difference, the human perceptual system really seems to pick up on it. This was the first thing we noticed after getting the textures mapped onto the cards -- they still had no life. So I wrote an external program that takes a rectangle, tesselates it into an arbitrary number of triangles, and then perturbs the z values according to some formula. Then it calculates normals at every vertex (the average of the normal of each face sharing that vertex), and writes the result as an Inventor file. For all of our final scenes, the cards were divided into 25 strips horizontally and 30 strips vertically, for a total of 1500 triangles; the z value at each point was the sum of the distances from the lines x=.5 and x+y=1 (where x and y values both range from 0 to 1), scaled by .25 and .125, respectively. This slightly curves each side of the card up, and even more slightly raises the upper right and lower left corners. The cards look fairly convincingly like new but slightly played cards. Two more notes on this card generator: First, we also wanted rounded corners on the cards, so after Jeremy had CSG implemented, I changed the program to output the card mesh minus the triangle or two at each corner, then to separately output each corner with an attached sphere sized and positioned so that the AND of the sphere and corner triangles would yield a rounded corner. Second, the amount of z displacement at each point could be scaled globally for each card, and also have local noise added in. I used this to generate 50 images of the same card with a progressively greater warp, yielding our bendcard.mov animation. Before rendering, we also applied a texture map for each card both for the obvious diffuse color, and a bump map to capture the machine marks that are evident when you closely examine a real card -- mostly with low-angle lighting. Look for this in some of our scenes. Distributed rays for soft shadows from area light sources -- magi ----------------------------------------------------------------- We thought that a soft-shadow effect, however subtle (since our objects will be on a flat table and not casting large shadows) would add realism, so I implemented distribution ray tracing for shadow calculations. First I implemented an area light type, modelled as a plane with a special tag in its name in Inventor. Then, for shadow calculations, I send out an arbitrary number (with a default of 9) of rays to random locations on a regular (ie, 3x3) grid around the light. If all these 9 samples report the same degree of visibility, I assume that we're either completely in shadow or completely in light, and take that answer as good enough. If any of the samples differs at all from the others, I take that as a sign that the surface point is in penumbra, and to avoid noise in the shadows, send out another 4 times as many samples (sampling the light twice as densely in each dimension). This is over and above the general supersampling, and yielded nicely noise-free penumbrae as long as the area lights are not sadistically huge. Images ------ backlit-die.ppm -- A simple image of the die demonstrating the refraction effects you see (easily verified with a real die) when it's backlit. Look at the bright lines, inside the dark edges, inside the bright cube in the middle. This is one of my (Matt's) favorite effects. While this required no special handlng in our raytracer -- it's just refraction and reflection -- it does show that we modelled the die accurately. bigdiecards.ppm -- A closeup of the die, through which can be seen two cards -- neat refraction effects around the rounded edges of the die dieclose.ppm -- A closeup of the die alone, clearly showing the CSG pips, rounded edges and corners, smooth shading across CSG primitives, and multiple images of the back sides of the pips reflected around the inside of the die diegood.ppm -- Smaller version of dieclose.ppm houseofcards.ppm -- One of our two real compositions, showing seven cards piled atop each other. Being one of our real compositions, we actually paid attention to lighting, so you can see the machine marks on some of the cards. Have fun analyzing the scene trying to figure out where Jeremy placed lights and (off-camera) occluding planes to create the shadows you see. jack-die.ppm -- A could-be would-be royal flush in spades, with a die sitting handily nearby. spread.ppm -- Our other real composition, with several cards spread out in a semicircle; at the middle, laying on a facedown card, are two dice. The upper one is cunningly balanced by its corner in one of the pips of the lower one. Don't try this at home. twocards.ppm -- Just two cards, one over the other, but the machine marks and their effect on specularity are clearly visible bendcard.mov (submitted via ftp) -- an animation featuring a card bending and generally getting beat up over time Images also available in jpeg format at http://graphics.stanford.edu/~magi/cs348b/.