#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'Doc/Guide/surfaces.tex' <<'END_OF_FILE' X\chapter{Surfaces and Atmospheric Effects} X XSurfaces are used to control the interaction between light sources and Xobjects. A surface specification consists of information Xabout how the light interacts with both the exterior and Xinterior of an object . XFor non-closed objects, such as polygons, Xthe ``interior'' of an object is the ``other side'' of the object's surface Xrelative to the origin of a ray. X X{\Rayshade} usually ensures that a primitive's surface normal is pointing Xtowards the origin of the incident ray when performing shading Xcalculations. Exceptions to this rule are transparent primitives, for Xwhich {\rayshade} uses the direction of the surface normal to determine if Xthe incident ray is entering or exiting the object. XAll non-transparent primitives will, in effect, be double-sided. X X\section{Surface Description} X XA surface definition consists of a number of component keywords, each Xof which is usually followed by either a single number or a red-green-blue Xcolor triple. Each of the values in the color triple are normalized, Xwith zero indicating zero intensity, and one indicating full intensity. X XIf any surface component is left unspecified, its value defaults to zero, Xwith the exception of the index of refraction, which is assigned the Xdefault index of refraction (normally 1.0). X XSurface descriptions are used in {\rayshade} to compute the color of a ray Xthat strikes the surface at a point \evec{P}. The normal to the surface Xat \evec{P}, \evec{N}, is also computed. X X\begin{defkey}{ambient}{\evec{color}} X Use the given {\em color} to approximate those surface-surface X interactions (e.g., diffuse interreflection) not modeled by the X ray tracing process. X\end{defkey} XA surface's ambient color is always applied to a ray. The color Xapplied is computed by multiplying the ambient color by the intensity Xof the ambient light source. X XIf \evec{P} is in shadow with respect to a given light source, Xthat light source makes no contribution to the shading of \evec{P}. X X\begin{defkey}{diffuse}{\evec{color}} X Specifies the diffuse color. X\end{defkey} XThe diffuse contribution from each non-shadowed light source at \evec{P} Xis equal to the diffuse color of the surface scaled by the cosine of Xthe angle between \evec{N} Xand the vector from \evec{P} to the light source. X X\begin{defkey}{specular}{\evec{color}} X Specifies the base color of specular reflections. X\end{defkey} X X\begin{defkey}{specpow}{{\em exponent}} X Controls the size of the specular highlight. The larger X the {\em exponent}, the smoother the apparent finish. X\end{defkey} XThe intensity of specular highlights from light sources are Xscaled by the specular color of the surface. X X\begin{defkey}{reflect}{{\em reflectivity}} X Specifies the specular reflectivity of the surface. If non-zero, X reflected rays will be spawned. X\end{defkey} XThe intensity of specularly reflected rays will be proportional to Xthe specular color of the surface scaled by the reflectivity. X X\begin{defkey}{transp}{{\em transparency}} X Specifies the specular transmissivity of the surface. If X non-zero, X transmitted (refracted) rays will be spawned. X\end{defkey} X X\begin{defkey}{body}{\evec{color}} X Specifies the body color of the object. The body color X affects the color of rays that are transmitted through the X object. X\end{defkey} X X\begin{defkey}{extinct}{{\em coefficient}} X Specifies the extinction coefficient of the interior X of the object. X\end{defkey} XThe extinction coefficient is raised to a power equal to the distance Xthe transmitted ray travels through the object. XThe overall intensity of specularly transmitted rays will be proportional to Xthis factor multiplied by the surface's body color Xmultiplied by the transparency of the object. X X\begin{defkey}{index}{{\em N}} X Specifies the index of refraction. The default value is equal X to the index of refraction of the atmosphere surrounding the eye. X\end{defkey} X X\begin{defkey}{translucency}{{\em translu} \evec{color} {\em stexp}} X Specifies the translucency, diffusely transmitted color, X and Phong exponent for transmitted specular highlights. X\end{defkey} XIf a light source illuminates a translucent surface from the side opposite Xthat from which a ray approaches, illumination computations are performed, Xusing the given color as the surface's diffuse color, and the given Xexponent as the Phong highlight exponent. The resulting color is then Xscaled by the surface's translucency. X X\section{Atmospheric Effects} X XAny number of atmospheric effects may be associated with the default Xmedium (``air''). X X\begin{defkey}{fog}{\evec{color} \evec{thinness}} XAdd exponential fog with the specified {\em thinness} and {\em color}. X\end{defkey} XFog is simulated by blending the color of the fog with the color of Xeach ray. The amount of fog color blended into a ray color is an exponential Xfunction of the distance from the ray origin to the point of intersection Xdivided by the specified {\em thinness} for each color channel. XIf the distance is equal to {\em thinness}, Xa ray's new color will be half of the fog color plus half its Xoriginal color. X X\begin{defkey}{mist}{\evec{color} \evec{thinness} {\em zero scale}} XAdd global low-altitude mist of the specified color. The color of Xa ray is modulated by a fog with density that varies linearly with Xthe difference in $z$ coordinate\footnote{This all but assumes that Xthe default up vector (0, 0, 1) is being used.} Xbetween the ray origin and Xthe point of intersection. The thinness values specify the transmissivity Xof the fog for each color channel. XThe base altitude of the Xmist is given by {\em zero}, and the apparent height of the mist can Xbe modulated using {\em scale}, which scales the difference in Xaltitude used to compute the fog. X\end{defkey} X X\begin{defkey}{fogdeck}{{\em altitude} {\em offset} \evec{scale} {\em chaoscale} X \evec{color} \evec{thinness}} XAdd low-altitude fog, with transmissivity modulated by Xa chaotic function. X\end{defkey} X X\section {The Default Medium} X XThe default medium is the medium which surrounds and encompasses Xall of the objects in the scene; it is the ``air'' through which eye Xrays usually travel before hitting an object. The properties of Xthe default medium may be modified through the use of the {\tt atmosphere} Xkeyword. X X\begin{defkey}{atmosphere}{[{\em N\/}] [{\em atmospheric effects}]} XIf given, {\em N} specifies the index of refraction of the default Xmedium. The default is 1.0. Any atmospheric effects listed are applied Xto rays that are exterior to every object in the scene (e.g., rays Xemanating from the camera). X\end{defkey} X X\begin{verbatim} X /* X * Red sphere on a grey plane, with fog. X */ X eyep 0. -10. 2. X atmosphere fog .8 .8 .8 14. 14. 14. X plane 0 0 0 0 0 1 X sphere diffuse 0.8 0 0 1.5 0 0 1.5 X\end{verbatim} X X\section {Surface Specification} X X{\Rayshade} provides a number of ways to define surfaces and to Xbind these surfaces to objects. The most straight-forward method Xof surface specification is to simply list the surface properties to Xbe used. XAlternatively, one may associate a name with a given surface. XThis name may subsequently be used to refer to that surface. X X\begin{defkey}{surface}{{\em name\/} $<${\em Surface Definition}$>$} X Associate the given collection of surface attributes with the X given name. X\end{defkey} X XThe binding of a collection of surface properties to a given object Xis accomplished in a bottom-up manner; the surface that ``closest'' Xin the modeling tree to the primitive being rendered is the one that Xis used to give the primitive its appearance. X XAn object that has no surface bound to it is assigned a default surface Xthat gives the appearance of white plastic. X XThe Xmost direct way to bind a surface to a primitive Xis to specify the surface when the Xthe primitive instantiated. XThis is accomplished Xby inserting a list of surface attributes or a surface name after Xthe primitive's type keyword and before the actual primitive data. X X\begin{verbatim} X /* X * A red 'mud' colored sphere reseting on a X * white sphere. To the right is a sphere with X * default surface attributes. X */ X surface mud ambient .03 0. 0. diffuse .7 .3 0. X sphere ambient .05 .05 .05 diffuse .7 .7 .7 1. 0 0 0 X sphere mud 1. 0 0 2 X sphere 1. 1.5 0 0 X\end{verbatim} X XHere, we define a red surface named ``mud''. We then instantiate Xa sphere, which has a diffuse white surface bound to it. The Xnext line instantiates a sphere with the defined ``mud'' surface bound Xto it. The last line instantiates a sphere with no surface bound to it; Xit is assigned the default surface by {\rayshade}. X XThe {\tt applysurf} keyword may be used to set the default surface Xcharacteristics for the aggregate object currently being defined. X X\begin{defkey}{applysurf}{$<${\em Surface Specification}$>$} XThe specified surface is applied to all following Xinstantiated objects that do not have surfaces associated with them. XThe scope of this keyword is limited to the aggregate currently Xbeing defined. X\end{defkey} X X\begin{verbatim} X /* X * Mirrored ball and cylinder sitting on 'default' plane. X */ X surface mirror ambient .01 .01 .01 X diffuse .05 .05 .05 X specular .8 .8 .8 specpow 20 reflect 0.95 X plane 0 0 0 0 0 1 X applysurf mirror X sphere 1 0 0 0 X cylinder 1 3 0 0 3 0 3 X\end{verbatim} X XFor convenience, the name {\tt cursurf} may be used to refer to the Xcurrent default surface. X XThe utility of bottom-up binding of surfaces lies in the fact that Xone may be as adamant or as noncommittal about Xsurface binding as one sees fit when defining objects. For example, Xone could define a king chess piece consisting of triangles that have no Xsurface bound to them, save for the cross on top, which has Xa gold-colored surface associated with it. One may then instantiate Xthe king twice, once applying a black surface, and once applying Xa white surface. The result: a black king and a white king, each Xadorned with a golden cross. X X\begin{verbatim} X surface white ... X surface black ... X surface gold ... X ... X define cross X box x y z x y z X ... X defend X define king X triangle x y z x y z x y z X ... X object gold cross X defend X X object white king translate 1. 0 0 X object black king X\end{verbatim} END_OF_FILE if test 10369 -ne `wc -c <'Doc/Guide/surfaces.tex'`; then echo shar: \"'Doc/Guide/surfaces.tex'\" unpacked with wrong size! fi # end of 'Doc/Guide/surfaces.tex' fi if test -f 'Doc/quickref.txt' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Doc/quickref.txt'\" else echo shar: Extracting \"'Doc/quickref.txt'\" \(9718 characters\) sed "s/^X//" >'Doc/quickref.txt' <<'END_OF_FILE' X Rayshade Quick Reference X X------------------------------------------------------------------------------- XKey: X[thing] Optional item Production XThing Number or String (thing) Default value(s) Xthing Keyword X------------------------------------------------------------------------------- X XReals and integers may be written in exponential notation, with or without a Xdecimal point. Reals are truncated to integers when need be. Numbers may also Xbe written as expressions surrounded by a matched pair of parentheses. XSubexpressions may be parenthesized to control order of evaluation. Variables Xmay be defined and used in parenthesized expressions. Predefined variables Xinclude time (current time) and frame (current frame number, 0 - frames-1), pi, Xdtor (pi/180), rotd (180/pi). Available operators are '+' (addition), X'-' (subtraction and negation), '*' (multiplication), '/' (division), X'%' (remainder), '^' (exponentiation). Functions include sin, cos, tan, asin, Xacos, atan, sqrt, hypot. X XStrings are written as non-quoted strings that may include include the Xspecial characters '/' ("slash"), '-' ("dash"), '_' ("underscore), and '.' X("period"), in addition to upper and lowercase letters and non-leading digits. X X------------------------------------------------------------------------------- XCommand-line options (override options set in input file): X X-A frame First frame to render X-a Toggle alpha channel -C cutoff Adaptive tree cutoff X-c Continued rendering -D depth Maximum ray tree depth. X-E eye_sep Eye separation -e Exponential RLE output X-F freq Report frequency -f Flip triangle normals X-G gamma Gamma exponent -g Use gaussian filter X-h Help -j Toggle jittered sampling X-l Render left eye view -m Produce sample map X-N frames Total frames to render -n No shadows X-O outfile Output file name -o Toggle opaque shadows X-P cpp-args Arguments for cpp -p Preview-quality X-q Run quietly -R xres yres Resolution X-r Right eye view -S samples Use Samples^2 samples X-s Toggle shadow caching -T r g b Contrast threshold X-u Toggle use of cpp -V filename Verbose file output X-v Verbose output -W lx hx ly hy Render subwindow X-X l r b t Crop window X------------------------------------------------------------------------------- X XFile: /* Input file consists of...*/ X [ ... ] X XItem: X X X X X X X XObjItem: /* Items used in object definition blocks */ X X X X X XViewing: X eyep Xpos Ypos Zpos /* Eye position (0 -10 0) */ X lookp Xpos Ypos Zpos /* Look position (0 0 0) */ X up Xup Yup Zup /* "up" vector (0 0 1) */ X fov Hfov [Vfov] /* Field of view in degrees (horiontal=45) */ X aperture Width /* Aperture width (0) */ X focaldist Distance /* focal distance (|eyep - lookp|) */ X shutter Speed /* Shutter speed (0 --> no blur) */ X framelength Length /* Length of a singelf frame (1) */ X screen Xsize Ysize /* Screen size */ X window Xmin Xmax Ymin Ymax /* Window (0 xsize-1 0 ysize-1) */ X crop left right bot top /* Crop window (0 1 0 1) */ X eyesep Separation /* eye separation (0) */ X XSurfDef: /* Give a name to a set of surface attributes. */ X surface Name [ ...] X XSurface: /* Surface specification */ X /* Use gven attributes */ X Surfname [ ...] /* Use named surface w/ optional mods. */ X cursurf [ ...] /* Use cur. surface w/mods - see ApplySurf */ X XSurfSpec: /* Surface attribute specification */ X ambient R G B /* Ambient contribution */ X diffuse R G B /* Diffuse color */ X specular R G B /* Specular color */ X specpow Exponent /* Phong exponent */ X body R G B /* Body color */ X extinct Coef /* Extinction coefficient */ X transp Ktr /* Transparency */ X reflect Kr /* Reflectivity */ X index N /* Index of refraction */ X translu Ktl R G B Stpow /* Translucency, transmit diffuse, spec exp */ X noshadow /* No shadows cast on this surface */ X XEffect: /* Atmospheric Effects */ X mist R G B Rtrans Gtrans Btrans Zero Scale X fog R G B Rtrans Gtrans Btrans X XAtmosphere: /* Global atmosphere */ X atmosphere [Index] [...] /* Global index, effects */ X XApplySurf: X applysurf /* apply surf to all following objs w/o surface */ X XInstance: /* Instance of an object */ X [] [] X XObject: X Primitive /* Primitive object */ X Aggregate /* Named aggregate */ X XObjDef: /* define a named object */ X name Objname X XPrimitive: /* Primitive object */ X plane [] Xpos Ypos Zpos Xnorm Ynorm Znorm X disc [] Radius Xpos Ypos Zpos Xnorm Ynorm Znorm X sphere [] Radius Xpos Ypos Zpos X triangle [] Xv1 Yv1 Zv1 X Xv2 Yv2 Zv2 Xv3 Yv3 Zv3/* flat-shaded triangle */ X triangle [] Xv1 Yv1 Zv1 Xn1 Yn1 Zn1 X Xv2 Yv2 Zv2 Xn2 Yn2 Zn2 X Xv3 Yv3 Zv3 Xn3 Yn3 Zn3/* Phong-shaded triangle */ X polygon [] Xv1 Yv1 Zv1 X Xv2 Yv2 Zv2 Xv3 Yv3 Zv3 [Xv3 Yv4 Zv4 ...] X box [] Xlow Ylow Zlow X Xhi Yhi Zhi X cylinder [] Radius Xbase Ybase Zbase Xapex Yapex Zapex X cone [] Rbase Xbase Ybase Zbase Rapex Xapex Yapex Zapex X torus [] Rswept Rtube Xpos Ypos Zpos Xnorm Ynorm Znorm X blob [] Thresh Stren Rad Xpos Ypos Zpos X [Stren Rad X Y Z ...] X heightfield [] Filename X XAggregate: X Grid X List X Csg X XGrid: X grid X Y Z [ ...] end X XList: X list [ ...] end X XCsg: X union [ ...] end X intersect [ ...] end X difference [ ...] end X X /* CSG will only work properly when applied to closed objects, e.g.: X * sphere, box, torus, blob, closed Aggregate, other Csg object X */ X XTransforms: /* Transformations */ X translate Xtrans Ytrans Ztrans X scale Xscale Yscale Zscale X rotate Xaxis Yaxis Zaxis Degrees X transform A B C X D E F X G H I X [Xt Yt Zt] X XTextures: X texture [Transforms] [ [Transforms] ...] X XTexture: X checker X blotch Scale X bump Bumpscale X marble [Colormapname] X fbm Offset Scale H Lambda Octaves Thresh [Colormapname] X fbmbump Offset Scale H Lambda Octaves X wood X gloss Glossiness X cloud Offset Scale H Lambda Octaves Cthresh Lthresh Transcale X sky Scale H Lambda Octaves Cthresh Lthresh X stripe Width Bumpscale X image Imagefile [ [ ...]] X XImageTextOption: X component X range Lo Hi X smooth X textsurf X tile U V X X XSurfComp: X ambient X diffuse X reflect X transp X specular X specpow X XMapping: X map uv X map cylindrical [Xorigin Yorigin Zorigin Xup Yup Zup Xu Yu Zu] X map planar [Xorigin Yorigin Zorigin Xv Yv Zv Xu Yu Zu] X map spherical [Xorigin Yorigin Zorigin Xup Yup Zup Xu Yu Zu] X XLight: X light R G B [noshadow] X light Intensity [noshadow] X XLightType: X ambient X point Xpos Ypos Zpos X directional Xdir Ydir Zdir X extended Radius Xpos Ypos Zpos X spot Xpos Ypos Zpos Xat Yat Zat Coef Thetain Thetaout X area Xorigin Yorigin Zorigin Xu Yu Zu Usamples Xv Yv Zv Vsamples X XRenderOption: X samples Nsamp [jitter | nojitter] X /* Use Nsamp^2 pixel samples (3^2 jittered) */ X background R G B /* Background color (0 0 0) */ X outfile Filename /* Output file name (written to stdout) */ X frames Nframes /* Number of frames to render (1) */ X starttime Time /* Time corresponding to start of frame 0 */ X contrast R G B /* Maximum contrast w/o supersampling */ X maxdepth Depth /* Maximum ray tree depth (5) */ X cutoff Factor /* Minium spawned ray contribution (.001) */ X report [verbose] [quiet] [Freq] [Statfile] X /* Reporting mode (false false 10 stderr) */ X shadowtransp /* Toggle object opacity affects shadows */ X XDefinition: /* Variable definition */ X define Name Expr /* Assign value for Name */ END_OF_FILE if test 9718 -ne `wc -c <'Doc/quickref.txt'`; then echo shar: \"'Doc/quickref.txt'\" unpacked with wrong size! fi # end of 'Doc/quickref.txt' fi if test -f 'libray/libobj/geom.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libray/libobj/geom.c'\" else echo shar: Extracting \"'libray/libobj/geom.c'\" \(9408 characters\) sed "s/^X//" >'libray/libobj/geom.c' <<'END_OF_FILE' X/* X * object.c X * X * Copyright (C) 1989, 1991, Craig E. Kolb X * All rights reserved. X * X * This software may be freely copied, modified, and redistributed X * provided that this copyright notice is preserved on all copies. X * X * You may not distribute this software, in whole or in part, as part of X * any commercial product without the express consent of the authors. X * X * There is no warranty or other guarantee of fitness of this software X * for any purpose. It is provided solely "as is". X * X * $Id: geom.c,v 4.0.1.1 91/09/29 15:43:15 cek Exp Locker: cek $ X * X * $Log: geom.c,v $ X * Revision 4.0.1.1 91/09/29 15:43:15 cek X * patch1: GeomBounds now inflates bounds by EPSILON. X * X * Revision 4.0 91/07/17 14:37:47 kolb X * Initial version. X * X */ X#include "geom.h" X#include "list.h" X#include "libcommon/sampling.h" X Xstatic void GeomBounds(), GeomBoundsAnimated(); Xvoid GeomResolveAssoc(); /* probably static */ X XGeom * XGeomCreate(objptr, methods) XGeomRef objptr; XMethods *methods; X{ X Geom *obj; X X if (objptr == (GeomRef)NULL) X return (Geom *)NULL; X X obj = (Geom *)share_calloc(1, sizeof(Geom)); X obj->obj = objptr; X obj->methods = methods; X obj->animtrans = FALSE; X obj->trans = obj->transtail = (Trans *) NULL; X obj->frame = -1; /* impossible value */ X BoundsInit(obj->bounds); X#ifdef SHAREDMEM X /* X * If the counter is in shared memory, processes will X * be modifying it left-and-right. So, we cheat and X * make counter a pointer to a non-shared location and X * store the value there. X */ X new->counter = (unsigned long *)Malloc(sizeof(unsigned long)); X *new->counter = 0; X#endif X return obj; X} X X/* X * Return a copy of the given object. X * Note that surface, texturing, and transformation information X * is copied by reference. X */ XGeom * XGeomCopy(obj) XGeom *obj; X{ X Geom *new; X X new = GeomCreate(obj->obj, obj->methods); X /* Share texturing, name, #prims, surface info */ X new->name = obj->name; X new->texture = obj->texture; X new->surf = obj->surf; X new->prims = obj->prims; X new->trans = obj->trans; X new->animtrans = obj->animtrans; X new->transtail = obj->transtail; X /* copy bounds */ X BoundsCopy(obj->bounds, new->bounds); X return new; X} X X/* X * Report bounding box and number of primitives in object. X */ Xvoid XAggregatePrintInfo(obj, fp) XGeom *obj; XFILE *fp; X{ X if (fp) { X if (obj->name && obj->name[0]) X fprintf(fp,"%s \"%s\":\n", GeomName(obj), obj->name); X else X fprintf(fp,"%s:\n", GeomName(obj)); X if (!UNBOUNDED(obj)) X BoundsPrint(obj->bounds, fp); X fprintf(fp,"\t%lu primitive%c\n",obj->prims, X obj->prims == 1 ? ' ' : 's'); X } X} X X/* X * Convert the given object from a linked list of objects to X * the desired aggregate type. X */ Xint XAggregateConvert(obj, objlist) XGeom *obj, *objlist; X{ X if (!IsAggregate(obj)) { X RLerror(RL_ABORT, "A %s isn't an aggregate.\n", X GeomName(obj)); X return 0; X } X X return (*obj->methods->convert)(obj->obj, objlist); X} X X/* X * This should really be called X * GeomInitialize X * or something. X */ Xvoid XGeomComputeBounds(obj) XGeom *obj; X{ X if (obj->frame == Sampling.framenum) X return; X X if (!obj->animtrans) { X /* X * If it isn't animated, X * just compute bbox directly X */ X GeomBounds(obj, obj->bounds); X } else { X /* X * Animated things are gonna get a bbox X * which is large enough to enclose all X * the places where the object goes. X */ X GeomBoundsAnimated(obj); X } X /* X * Enlarge by EPSILON in each direction just to X * be on the safe side. X */ X obj->bounds[LOW][X] -= EPSILON; X obj->bounds[HIGH][X] += EPSILON; X obj->bounds[LOW][Y] -= EPSILON; X obj->bounds[HIGH][Y] += EPSILON; X obj->bounds[LOW][Z] -= EPSILON; X obj->bounds[HIGH][Z] += EPSILON; X /* X * Mark the fact that that the obj is initialized X * for this frame. X */ X obj->frame = Sampling.framenum; X obj->counter = 0; X} X Xstatic void XGeomBoundsAnimated(obj) XGeom *obj; X{ X int i, m; X Float newbounds[2][3]; X Float window, subwindow, jitter, subjitter; X X /* X * For each possible screen sample, X * choose TIME_SUB_SAMPLES times and recompute the X * bounds of obj at that time, X * expanding the computed bounding box appropriately. X */ X BoundsInit(obj->bounds); X jitter = Sampling.shutter / Sampling.totsamples; X subjitter = jitter / (Float)TIME_SUB_SAMPLES; X window = Sampling.starttime; X for (i = 0; i < Sampling.totsamples; i++, window += jitter) { X subwindow = window; X for (m = 0; m < TIME_SUB_SAMPLES; m++, subwindow += subjitter) { X /* X * Set the current time. X */ X TimeSet(subwindow + subjitter*nrand()); X /* X * Resolve the objects geometric associations X */ X GeomResolveAssoc(obj); X /* X * Compute bounds and expand current bounds. X */ X GeomBounds(obj, newbounds); X BoundsEnlarge(obj->bounds, newbounds); X } X } X /* X * Also sample at time extremes, as for many X * movements, extremes occur at beginning/end times. X */ X TimeSet(Sampling.starttime); X GeomResolveAssoc(obj); X GeomBounds(obj, newbounds); X BoundsEnlarge(obj->bounds, newbounds); X X TimeSet(Sampling.starttime + Sampling.shutter); X GeomResolveAssoc(obj); X GeomBounds(obj, newbounds); X BoundsEnlarge(obj->bounds, newbounds); X} X Xvoid XGeomResolveAssoc(obj) XGeom *obj; X{ X /* X * PrimResolveAssoc(obj); X */ X TransResolveAssoc(obj->trans); X} X X/* X * Set "bounds" of object to be the extent of the primitive. X */ Xstatic void XGeomBounds(obj, bounds) XGeom *obj; XFloat bounds[2][3]; X{ X Trans *trans; X X if (!obj || !obj->methods->bounds) X RLerror(RL_ABORT, "Can't compute bounds of \"%s\".\n", X GeomName(obj)); X (*obj->methods->bounds) (obj->obj, bounds); X bounds[LOW][X] -= EPSILON; X bounds[LOW][Y] -= EPSILON; X bounds[LOW][Z] -= EPSILON; X bounds[HIGH][X] += EPSILON; X bounds[HIGH][Y] += EPSILON; X bounds[HIGH][Z] += EPSILON; X if (obj->trans) { X for (trans = obj->trans; trans; trans = trans->next) X BoundsTransform(&trans->trans, bounds); X } X} X Xchar * XGeomName(obj) XGeom *obj; X{ X if (obj->methods->name) X return (*obj->methods->name)(); X X return "unknown"; X} X Xvoid XGeomStats(obj, tests, hits) XGeom *obj; Xunsigned long *tests, *hits; X{ X if (obj && obj->methods->stats) X (*obj->methods->stats)(tests, hits); X else { X *tests = *hits = 0; X } X} X X/* X * Push an object onto the head of the given stack, returning X * the new head. X */ XGeomList * XGeomStackPush(obj, list) XGeom *obj; XGeomList *list; X{ X GeomList *new; X /* X * Pretty simple. X * Make new element point to old head and return new head. X */ X new = (GeomList *)Malloc(sizeof(GeomList)); X new->obj = obj; X new->next = list; X return new; X} X X/* X * Pop the topmost object off of the given stack, returning the new head. X * The old head is freed, but the object it points to is not. X */ XGeomList * XGeomStackPop(list) XGeomList *list; X{ X GeomList *ltmp; X X ltmp = list->next; /* Save new head. */ X free((voidstar)list); /* Free old head. */ X return ltmp; /* Return new head. */ X} X XMethods * XMethodsCreate() X{ X return (Methods *)share_calloc(1, sizeof(Methods)); X} X X/* X * Call appropriate routine to compute UV and, if non-null, X * dpdu and dpdv at given point on the given primitive. The X * normal is used to facilitate computation of u, v, and the X * partial derivatives. X */ Xvoid XPrimUV(prim, pos, norm, uv, dpdu, dpdv) XGeom *prim; XVector *pos, *norm, *dpdu, *dpdv; XVec2d *uv; X{ X /* X * Call appropriate inverse mapping routine X */ X if (prim->methods->uv == NULL) { X uv->u = uv->v = 0.; X if (dpdu) { X dpdu->y = dpdu->z = 0.; X dpdu->x = 1.; X } X if (dpdv) { X dpdv->x = dpdv->z = 0.; X dpdv->y = 1.; X } X } else X (*prim->methods->uv)(prim->obj,pos,norm,uv,dpdu,dpdv); X} X Xint XPrimNormal(prim, pos, norm, gnorm) XGeom *prim; XVector *pos, *norm, *gnorm; X{ X /* X * Call appropriate normal routine X */ X return (*prim->methods->normal) (prim->obj, pos, norm, gnorm); X} X Xint XPrimEnter(obj, ray, mind, hitd) XGeom *obj; XRay *ray; XFloat mind, hitd; X{ X /* X * Call appropriate enter/leave routine X */ X if (obj->methods->enter == NULL) { X Vector pos, nrm, gnrm; X /* X * Sleazy method: Use hit point, find normal X * and take dot prod with ray X */ X VecAddScaled(ray->pos, hitd, ray->dir, &pos); X PrimNormal(obj, &pos, &nrm, &gnrm); X X return dotp(&ray->dir, &gnrm) < 0.0; X } X else X return (*obj->methods->enter) (obj->obj, ray, mind, hitd); X} X X/* X * Walk through a linked-list of objects. If the object is unbounded, X * unlink it it from the list and add it to the 'unbounded' list. X * If the object is bounded, enlarge the given bounding box if X * necessary. Return pointer to unbounded list. X */ XGeom * XGeomComputeAggregateBounds(bounded, unbounded, bounds) XGeom **bounded, *unbounded; XFloat bounds[2][3]; X{ X Geom *ltmp, *prev, *nextobj; X X BoundsInit(bounds); X X prev = (Geom *)0; X X for (ltmp = *bounded; ltmp; ltmp = nextobj) { X nextobj = ltmp->next; X GeomComputeBounds(ltmp); X if (UNBOUNDED(ltmp)) { X /* X * Geom is unbounded -- unlink it... X */ X if (prev) X prev->next = ltmp->next; X else X *bounded = ltmp->next; X /* X * And add it to unbounded object list. X */ X ltmp->next = unbounded; X unbounded = ltmp; X } else { X /* X * Geom is bounded. X */ X BoundsEnlarge(bounds, ltmp->bounds); X prev = ltmp; X } X } X return unbounded; X} X X/* X * Find 'highest' animated object on the hitlist. X */ Xint XFirstAnimatedGeom(hitlist) XHitList *hitlist; X{ X int i; X X for (i = hitlist->nodes -1; i; i--) X /* X * If object itself is animated, have X * to check other flag, too... X */ X if (hitlist->data[i].obj->animtrans) X return i; X return 0; X} END_OF_FILE if test 9408 -ne `wc -c <'libray/libobj/geom.c'`; then echo shar: \"'libray/libobj/geom.c'\" unpacked with wrong size! fi # end of 'libray/libobj/geom.c' fi if test -f 'libshade/shade.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libshade/shade.c'\" else echo shar: Extracting \"'libshade/shade.c'\" \(10451 characters\) sed "s/^X//" >'libshade/shade.c' <<'END_OF_FILE' X/* X * shade.c X * X * Copyright (C) 1989, 1991, Craig E. Kolb X * All rights reserved. X * X * This software may be freely copied, modified, and redistributed X * provided that this copyright notice is preserved on all copies. X * X * You may not distribute this software, in whole or in part, as part of X * any commercial product without the express consent of the authors. X * X * There is no warranty or other guarantee of fitness of this software X * for any purpose. It is provided solely "as is". X * X * $Id: shade.c,v 4.0 91/07/17 14:47:36 kolb Exp Locker: kolb $ X * X * $Log: shade.c,v $ X * Revision 4.0 91/07/17 14:47:36 kolb X * Initial version. X * X */ X#include "rayshade.h" X#include "libtext/texture.h" X#include "libsurf/surface.h" X#include "liblight/light.h" X#include "libsurf/atmosphere.h" X#include "options.h" X#include "stats.h" X XMedium TopMedium; XAtmosphere *AtmosEffects; X Xstatic void shade(), LightRay(), Lighting(), ReflectRay(); Xstatic int TransmitRay(); X X/* X * Calculate color of ray. X */ Xvoid XShadeRay(hitlist, ray, dist, back, color, contrib) XHitList *hitlist; /* Information about point of intersection. */ XRay *ray; /* Direction and origin of ray. */ XFloat dist; /* Distance from origin of intersection. */ XColor *back, /* "Background" color */ X *color, /* Color to assign current ray. */ X *contrib; /* Contribution of this ray to final color */ X{ X Vector norm, gnorm, pos; /* surface normal, point of intersection */ X Surface surf, *stmp; /* surface properties */ X int enter, smooth; /* entering ?, gnorm != snorm ?*/ X X if (hitlist->nodes == 0) { X /* X * No valid intersection. Set distance for atmospheric X * effects and set color of ray to background. X */ X *color = *back; X VecAddScaled(ray->pos, FAR_AWAY, ray->dir, &pos); X if (!ray->media && AtmosEffects) X Atmospherics(AtmosEffects, ray, FAR_AWAY, &pos, color); X return; X } X X /* X * Compute normal, surface properties, etc. X */ X stmp = GetShadingSurf(hitlist); X surf = *stmp; X enter = ComputeSurfProps(hitlist, ray, &pos, &norm, &gnorm, &surf, X &smooth); X Stats.HitRays++; X X /* X * Calculate ray color. X */ X shade(&pos, ray, &norm, &gnorm, smooth, enter, &surf, back, color, X contrib); X if (!ray->media && AtmosEffects) X Atmospherics(AtmosEffects, ray, dist, &pos, color); X} X X/* X * Perform lighting calculations based on surface normal & other properties, X * incident ray direction and position, and light source properties. X * Spawn any necessary reflected and transmitted rays. X */ Xstatic void Xshade(pos, ray, nrm, gnrm, smooth, enter, surf, back, color, contrib) XVector *pos, *nrm, *gnrm; /* hit pos, shade normal, geo normal */ Xint smooth; /* true if shading norm and geo norm differ */ Xint enter; /* TRUE if entering surface */ XRay *ray; /* indicent ray */ XSurface *surf; /* properties of hit surface */ XColor *back, *color; /* background color, computed color */ XColor *contrib; /* contribution to final pixel value */ X{ X Float k; /* -ray . normal */ X Color newcontrib; X Vector refl; /* reflected direction */ X Color reflectivity, /* effective surface reflectivity */ X intens; /* reflected/transmitted intensity */ X Light *lp; /* current light source */ X extern Light *Lights; /* list of defined sources */ X X /* X * Ambient color is always included. X */ X ColorMultiply(surf->amb, Options.ambient, color); X X /* X * Calculate direction of reflected ray. X */ X k = -dotp(&ray->dir, nrm); X VecAddScaled(ray->dir, 2.*k, *nrm, &refl); X X /* X * Calculate intensity contributed by each light source. X */ X for (lp = Lights; lp; lp = lp->next) X LightRay(lp, pos, nrm, gnrm, smooth, &refl, surf, X ray->depth, ray->sample, ray->time, color); X X if (ray->depth >= Options.maxdepth) X /* X * Don't spawn any transmitted/reflected rays. X */ X return; X /* X * Specular transmission (refraction). X */ X ColorScale(surf->reflect, surf->spec, &reflectivity); X X if (surf->transp > EPSILON) { X ColorScale(surf->transp, surf->body, &intens); X ColorMultiply(intens, *contrib, &newcontrib); X if (newcontrib.r > Options.cutoff.r || X newcontrib.g > Options.cutoff.g || X newcontrib.b > Options.cutoff.b) X /* X * Transmit ray. If TIR occurs, add transmitted X * component to reflected component. Kinda strange, but... X */ X if (TransmitRay(ray, pos, nrm, k, surf->index, X surf->statten, enter, back, &newcontrib, &intens, color)) X ColorAdd(reflectivity, intens, &reflectivity); X } X X if (reflectivity.r > EPSILON || X reflectivity.g > EPSILON || X reflectivity.b > EPSILON) { X ColorMultiply(reflectivity, *contrib, &newcontrib); X if (newcontrib.r > Options.cutoff.r || X newcontrib.g > Options.cutoff.g || X newcontrib.b > Options.cutoff.b) X ReflectRay(ray, pos, &refl, back, &reflectivity, X &newcontrib, color); X } X} X X/* X * Lighting calculations X */ Xstatic void XLightRay(lp, pos, norm, gnorm, smooth, reflect, surf, depth, samp, time, color) XLight *lp; /* Light source */ XVector *pos, *norm, *gnorm; /* hit pos, shade norm, geo norm */ Xint smooth; /* true if shade and geo norm differ */ XVector *reflect; /* reflection direction */ XSurface *surf; /* surface characteristics */ Xint depth, samp; /* ray depth, sample # */ XFloat time; XColor *color; /* resulting color */ X{ X Color lcolor; X Ray newray; X Float costheta, cosalpha, dist; X X newray.pos = *pos; X newray.depth = depth; X newray.sample = samp; X newray.time = time; X newray.media = (Medium *)NULL; X X LightDirection(lp, pos, &newray.dir, &dist); X X costheta = dotp(&newray.dir, norm); X X if (smooth) { X cosalpha = dotp(&newray.dir, gnorm); X /* X * If shading normal indicates self-shadowing X * and geom normal indicates no self-shadowing, X * trust the geom normal. X */ X if (costheta <= 0. && cosalpha > 0.) X costheta = cosalpha; X /* X * If geom normal indicates self-shadowing and X * geom normal doesn't, then have to do something X * clever ala Snyder & Barr. X */ X } X X if (costheta <= 0.) { X /* X * Light source is on opposite side of surface, X * hence light must be transmitted through... X */ X if (surf->translucency < EPSILON) X return; X if (!LightIntens(lp, &newray, dist, X (int)surf->noshadow, &lcolor)) X return; X cosalpha = -dotp(reflect, &newray.dir); X Lighting(-costheta, cosalpha, &lcolor, &surf->translu, X &surf->body, surf->stexp, color); X ColorScale(surf->translucency, *color, color); X } else { X if (!LightIntens(lp, &newray, dist, X (int)surf->noshadow, &lcolor)) X return; /* prim is in shadow w.r.t light source */ X X cosalpha = dotp(reflect, &newray.dir); X Lighting(costheta, cosalpha, &lcolor, &surf->diff, X &surf->spec, surf->srexp, color); X } X} X X/* X * Compute shading function (diffuse reflection and specular highlight) X * X * This function *adds* the computed color to "color". X */ Xstatic void XLighting(costheta, cosalpha, lcolor, diff, spec, coef, color) XFloat costheta, cosalpha, coef; XColor *diff, *spec, *color, *lcolor; X{ X Float intens; X X /* X * Diffuse reflection. X * Falls off as the cosine of the angle between X * the normal and the ray to the light (costheta). X */ X color->r += diff->r * costheta * lcolor->r; X color->g += diff->g * costheta * lcolor->g; X color->b += diff->b * costheta * lcolor->b; X /* X * Specularly reflected highlights. X * Fall off as the cosine of the angle X * between the reflected ray and the ray to the light source. X */ X if (coef < EPSILON || cosalpha <= 0.) X return; X /* X * Specular highlight = cosine of the angle raised to the X * appropriate power. X */ X intens = pow(cosalpha, coef); X color->r += spec->r * intens * lcolor->r; X color->g += spec->g * intens * lcolor->g; X color->b += spec->b * intens * lcolor->b; X} X X/* X * Spawn a transmitted ray. Returns TRUE if total internal reflection X * occurs, FALSE otherwise. X */ Xstatic int XTransmitRay(ray, pos, norm, k, index, statten, enter, back, contrib, intens, color) XRay *ray; XVector *pos, *norm; XFloat k, index, statten; Xint enter; XColor *back, *contrib, *intens, *color; X{ X int total_int_refl = FALSE; X Ray NewRay; X Float dist; X Color newcol; X HitList hittmp; /* Geom intersection record */ X X NewRay.pos = *pos; /* Origin == hit point */ X NewRay.media = ray->media; /* Media == old media */ X NewRay.sample = ray->sample; X NewRay.time = ray->time; X NewRay.depth = ray->depth + 1; X X if (enter) { X /* X * Entering surface. X */ X if (Refract(&NewRay.dir, X NewRay.media ? NewRay.media->index : X TopMedium.index, index, &ray->dir, norm, k)) { X total_int_refl = TRUE; X } else { X /* X * Push information for new medium. X */ X NewRay.media = MediumPush(index, statten, NewRay.media); X } X } else { X /* X * Exiting surface X * Pop medium from stack. X */ X if (NewRay.media != (Medium *)0) X NewRay.media = NewRay.media->next; X if (Refract(&NewRay.dir, index, X NewRay.media ? NewRay.media->index : X TopMedium.index, &ray->dir, norm, k)) { X total_int_refl = TRUE; X } X } X X /* X * At this point, NewRay.media is the medium into which X * the new ray is entering. X */ X X if (!total_int_refl) { X Stats.RefractRays++; X hittmp.nodes = 0; X dist = FAR_AWAY; X TraceRay(&NewRay, &hittmp, EPSILON, &dist); X ShadeRay(&hittmp, &NewRay, dist, back, &newcol, contrib); X ColorMultiply(newcol, *intens, &newcol); X /* X * Attenuate transmitted color. Note that X * if the transmitted ray hit nothing, we still X * perform this computation, as it's possible X * that 'air' has a non-unit statten. X */ X statten = NewRay.media ? NewRay.media->statten : X TopMedium.statten; X if (statten != 1.0) { X statten = pow(statten, dist); X ColorScale(statten, newcol, &newcol); X } X ColorAdd(*color, newcol, color); X /* Free pushed medium */ X if (enter) X free((voidstar)NewRay.media); X } X X return total_int_refl; X} X Xstatic void XReflectRay(ray, pos, dir, back, intens, contrib, color) XRay *ray; XVector *pos, *dir; XColor *back, *intens, *contrib, *color; X{ X Ray NewRay; X HitList hittmp; /* Geom intersection record */ X Color newcol; X Float dist; X X NewRay.pos = *pos; /* Origin == hit point */ X NewRay.dir = *dir; /* Direction == reflection */ X NewRay.media = ray->media; /* Medium == old medium */ X NewRay.sample = ray->sample; X NewRay.time = ray->time; X NewRay.depth = ray->depth + 1; X Stats.ReflectRays++; X hittmp.nodes = 0; X dist = FAR_AWAY; X (void)TraceRay(&NewRay, &hittmp, EPSILON, &dist); X ShadeRay(&hittmp, &NewRay, dist, back, &newcol, contrib); X ColorMultiply(newcol, *intens, &newcol); X ColorAdd(*color, newcol, color); X} END_OF_FILE if test 10451 -ne `wc -c <'libshade/shade.c'`; then echo shar: \"'libshade/shade.c'\" unpacked with wrong size! fi # end of 'libshade/shade.c' fi echo shar: End of archive 13 \(of 19\). cp /dev/null ark13isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 19 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0