This is shade.c in view mode; [Download] [Up]
/* * shade.c * * Copyright (C) 1989, 1991, Craig E. Kolb * All rights reserved. * * This software may be freely copied, modified, and redistributed * provided that this copyright notice is preserved on all copies. * * You may not distribute this software, in whole or in part, as part of * any commercial product without the express consent of the authors. * * There is no warranty or other guarantee of fitness of this software * for any purpose. It is provided solely "as is". * * $Id$ * * $Log$ */ #include "rayshade.h" #include "libtext/texture.h" #include "libsurf/surface.h" #include "liblight/light.h" #include "libsurf/atmosphere.h" #include "options.h" #include "stats.h" Medium TopMedium; static void shade(), LightRay(), Lighting(); /* * Calculate color of ray. */ void ShadeRay(hitlist, ray, dist, back, color, contrib) HitList *hitlist; /* Information about point of intersection. */ Ray *ray; /* Direction and origin of ray. */ Float dist; /* Distance from origin of intersection. */ Color *back; /* "Background" color */ Color *color; /* Color to assign current ray. */ Float contrib; /* Contribution of this ray to final color */ { Vector norm, gnorm, pos; /* surface normal, point of intersection */ Surface surf; /* surface properties */ Medium *medium; /* medium through which ray is traveling */ int enter, smooth; /* entering ?, gnorm != snorm ?*/ /* * If ray medium isn't set, use default. */ if (ray->media) medium = ray->media; else medium = &TopMedium; if (hitlist->nodes == 0) { /* * No valid intersection. Set distance for atmospheric * effects and set color of ray to background. */ *color = *back; VecAddScaled(ray->pos, FAR_AWAY, ray->dir, &pos); if (medium->atmos) Atmospherics(medium->atmos, ray, FAR_AWAY, &pos, color); return; } /* * Compute normal, surface properties, etc. */ enter = ComputeSurfProps(hitlist, ray, &pos, &norm, &gnorm, &surf, &smooth); Stats.HitRays++; /* * Calculate ray color. */ shade(&pos, ray, &norm, &gnorm, smooth, enter, &surf, back, color, contrib); if (medium->atmos) Atmospherics(medium->atmos, ray, dist, &pos, color); } /* * Perform lighting calculations based on surface normal & other properties, * incident ray direction and position, and light source properties. * Spawn any necessary reflected and transmitted rays. */ static void shade(pos, ray, nrm, gnrm, smooth, enter, surf, back, color, contrib) Vector *pos, *nrm, *gnrm; /* hit pos, shade normal, geo normal */ int smooth; /* true if shading norm and geo norm differ */ int enter; /* TRUE if entering surface */ Ray *ray; /* indicent ray */ Surface *surf; /* properties of hit surface */ Color *back, *color; /* background color, computed color */ Float contrib; /* contribution to final pixel value */ { Float dist, k; /* hit distance, -ray . normal */ Color newcol; /* color of spawned rays. */ HitList hittmp; /* Object intersection record */ Ray NewRay; /* spawned ray */ Vector refl; /* reflected direction */ int total_int_refl; /* total internal reflection flag */ Float reflectivity; /* effective surface reflectivity */ Light *lp; /* current light source */ extern Light *Lights; /* list of defined sources */ /* * Ambient color is always included. */ *color = surf->amb; /* * Calculate direction of reflected ray. */ k = -dotp(&ray->dir, nrm); VecAddScaled(ray->dir, 2.*k, *nrm, &refl); /* * Calculate intensity contributed by each light source. */ for (lp = Lights; lp; lp = lp->next) LightRay(lp, pos, nrm, gnrm, smooth, &refl, surf, ray->depth, ray->sample, color); if (ray->depth >= Options.maxdepth) /* * Don't spawn any transmitted/reflected rays. */ return; /* * Specular transmission (refraction). */ reflectivity = surf->refl; total_int_refl = FALSE; if (surf->transp != 0. && contrib * surf->transp > Options.cutoff) { NewRay.pos = *pos; /* Origin == hit point */ NewRay.media = ray->media; /* Media == old media */ NewRay.sample = ray->sample; NewRay.depth = ray->depth + 1; if (enter) { /* * Entering surface. */ if (Refract(&NewRay.dir, NewRay.media ? NewRay.media->index : TopMedium.index, surf->kref, ray->dir, *nrm, k)) { total_int_refl = TRUE; } else { NewRay.media = MediumPush(surf->kref, surf->atmos, NewRay.media); } } else { /* * Exiting surface * Pop medium from stack. * Hmm, maybe should use * popped medium rather than surf's kref? */ if (NewRay.media != (Medium *)0) NewRay.media = NewRay.media->next; if (Refract(&NewRay.dir, surf->kref, NewRay.media ? NewRay.media->index : TopMedium.index, ray->dir, *nrm, k)) { total_int_refl = TRUE; } } if (total_int_refl) { reflectivity += surf->transp; } else { Stats.RefractRays++; hittmp.nodes = 0; dist = FAR_AWAY; (void)TraceRay(&NewRay, &hittmp, EPSILON, &dist); ShadeRay(&hittmp, &NewRay, dist, back, &newcol, contrib * surf->transp); ColorAddScaled(*color, surf->transp, newcol, color); /* Free pushed medium */ if (enter) free((voidstar)NewRay.media); } } /* * Specular reflection. */ if (reflectivity > 0. && contrib * reflectivity > Options.cutoff) { NewRay.pos = *pos; /* Origin == hit point */ NewRay.dir = refl; /* Direction == reflection */ NewRay.media = ray->media; /* Medium == old medium */ NewRay.sample = ray->sample; NewRay.depth = ray->depth + 1; Stats.ReflectRays++; hittmp.nodes = 0; dist = FAR_AWAY; (void)TraceRay(&NewRay, &hittmp, EPSILON, &dist); ShadeRay(&hittmp, &NewRay, dist, back, &newcol, contrib*reflectivity); ColorAddScaled(*color, reflectivity, newcol, color); } } /* * Lighting calculations */ static void LightRay(lp, pos, norm, gnorm, smooth, reflect, surf, depth, samp, color) Light *lp; /* Light source */ Vector *pos, *norm, *gnorm; /* hit pos, shade norm, geo norm */ int smooth; /* true if shade and geo norm differ */ Vector *reflect; /* reflection direction */ Surface *surf; /* surface characteristics */ int depth, samp; /* ray depth, sample # */ Color *color; /* resulting color */ { Color lcolor; Ray newray; Float costheta, cosalpha, dist; newray.pos = *pos; newray.depth = depth; newray.sample = samp; newray.media = (Medium *)NULL; LightDirection(lp, pos, &newray.dir, &dist); costheta = dotp(&newray.dir, norm); if (smooth) { cosalpha = dotp(&newray.dir, gnorm); /* * If shading normal indicates self-shadowing * and geom normal indicates no self-shadowing, * trust the geom normal. */ if (costheta <= 0. && cosalpha > 0.) costheta = cosalpha; /* * If geom normal indicates self-shadowing and * geom normal doesn't, then have to do something * clever ala Snyder & Barr. */ } if (costheta <= 0.) { /* * Light source is on opposite side of surface. */ if (surf->translucency <= 0.) return; if (!LightIntens(lp, &newray, dist, (int)surf->noshadow, &lcolor)) return; cosalpha = -dotp(reflect, &newray.dir); /* * attenuate the light source color by the translucency */ ColorScale(surf->translucency, lcolor, &lcolor); Lighting(-costheta, cosalpha, &lcolor, &surf->diff, &surf->spec, surf->stcoef, color); } else { if (!LightIntens(lp, &newray, dist, (int)surf->noshadow, &lcolor)) return; /* prim is in shadow w.r.t light source */ cosalpha = dotp(reflect, &newray.dir); Lighting(costheta, cosalpha, &lcolor, &surf->diff, &surf->spec, surf->coef, color); } } /* * Compute shading function (diffuse reflection and specular highlight) * * This function *adds* the computed color to "color". */ static void Lighting(costheta, cosalpha, lcolor, diff, spec, coef, color) Float costheta, cosalpha, coef; Color *diff, *spec, *color, *lcolor; { Float intens; /* * Diffuse reflection. * Falls off as the cosine of the angle between * the normal and the ray to the light (costheta). */ color->r += diff->r * costheta * lcolor->r; color->g += diff->g * costheta * lcolor->g; color->b += diff->b * costheta * lcolor->b; /* * Specularly reflected highlights. * Fall off as the cosine of the angle * between the reflected ray and the ray to the light source. */ if (coef < EPSILON || cosalpha <= 0.) return; /* * Specular highlight = cosine of the angle raised to the * appropriate power. */ intens = pow(cosalpha, coef); color->r += spec->r * intens * lcolor->r; color->g += spec->g * intens * lcolor->g; color->b += spec->b * intens * lcolor->b; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.