home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Graphics / graphics-16000.iso / msdos / raytrace / rayshade / src / shadow.c < prev    next >
Text File  |  1992-04-30  |  8KB  |  317 lines

  1. /*
  2.  * shadow.c
  3.  *
  4.  * Copyright (C) 1989, 1991, Craig E. Kolb
  5.  * All rights reserved.
  6.  *
  7.  * This software may be freely copied, modified, and redistributed
  8.  * provided that this copyright notice is preserved on all copies.
  9.  *
  10.  * You may not distribute this software, in whole or in part, as part of
  11.  * any commercial product without the express consent of the authors.
  12.  *
  13.  * There is no warranty or other guarantee of fitness of this software
  14.  * for any purpose.  It is provided solely "as is".
  15.  *
  16.  * $Id: shadow.c,v 4.0.1.1 91/09/29 15:40:57 cek Exp Locker: cek $
  17.  *
  18.  * $Log:    shadow.c,v $
  19.  * Revision 4.0.1.1  91/09/29  15:40:57  cek
  20.  * patch1: ShadowOptions was incorrectly externed.
  21.  * 
  22.  * Revision 4.0  91/07/17  14:35:34  kolb
  23.  * Initial version.
  24.  * 
  25.  */
  26. #include "geom.h"
  27. #include "surface.h"
  28. #include "light.h"
  29.  
  30. /*
  31.  * Shadow stats.
  32.  * External functions have read access via ShadowStats().
  33.  */
  34. static unsigned long    ShadowRays, ShadowHits, CacheMisses, CacheHits;
  35. /*
  36.  * Options controlling how shadowing information is determined.
  37.  * Set by external modules via ShadowSetOptions().
  38.  */
  39. static long        ShadowOptions;
  40.  
  41. void LightCacheHit();
  42.  
  43. /*
  44.  * Trace ray from point of intersection to a light.  If an intersection
  45.  * occurs at a distance less than "dist" (the distance to the
  46.  * light source), then the point is in shadow, and TRUE is returned.
  47.  * Otherwise, the brightness/color of the light is computed ('result'),
  48.  * and FALSE is returned.
  49.  */
  50. int
  51. Shadowed(result, color, cache, ray, dist, noshadow)
  52. Color *result, *color;    /* resultant intensity, light color */
  53. ShadowCache *cache;    /* shadow cache for light */
  54. Ray *ray;        /* ray, origin on surface, dir towards light */
  55. Float dist;        /* distance from pos to light source */
  56. int noshadow;        /* If TRUE, no shadow ray is cast. */
  57. {
  58.     int i, smooth, enter;
  59.     HitList hitlist;
  60.     Ray tmpray;
  61.     ShadowCache *cp;
  62.     Vector hitpos, norm, gnorm;
  63.     Surface surf, *sptr, *prevsurf;
  64.     Float s, totaldist, statten;
  65.     Color res;
  66.  
  67.     if (noshadow || NOSHADOWS(ShadowOptions)) {
  68.         *result = *color;
  69.         return FALSE;
  70.     }
  71.  
  72.     ShadowRays++;
  73.     s = dist;
  74.     cp = &cache[ray->depth];
  75.     /*
  76.      * Check shadow cache.  SHADOWCACHE() is implied.
  77.      */
  78.     if (cp->obj) {
  79.         /*
  80.          * Transform ray to the space of the cached primitive.
  81.          */
  82.         tmpray = *ray;
  83.         if (cp->dotrans)
  84.             s *= RayTransform(&tmpray, &cp->trans);
  85.         /*
  86.          * s = distance to light source in 'primitive space'.
  87.          * Intersect ray with cached object.
  88.          */
  89.         if (cp->obj->animtrans) {
  90.             /*
  91.              * Geom has animated transformation --
  92.              * call intersect so that the transformation
  93.              * is resolved properly.
  94.              */
  95.             if (intersect(cp->obj, &tmpray, &hitlist,
  96.                 SHADOW_EPSILON, &s)) {
  97.                 CacheHits++;
  98.                 return TRUE;
  99.             }
  100.         } else if (IsAggregate(cp->obj)) {
  101.             if ((*cp->obj->methods->intersect)(cp->obj->obj,
  102.                 &tmpray, &hitlist, SHADOW_EPSILON, &s)) {
  103.                 CacheHits++;
  104.                 return TRUE;
  105.             }
  106.         } else if ((*cp->obj->methods->intersect)(cp->obj->obj,
  107.                     &tmpray, SHADOW_EPSILON, &s)) {
  108.             /* Hit cached object. */
  109.             CacheHits++;
  110.             return TRUE;
  111.         }
  112.         /*
  113.          * Did not hit anything -- zero out the cache.
  114.          */
  115.         CacheMisses++;
  116.         /*
  117.          * Transformed -- reset s for use below.
  118.          */
  119.         s = dist;
  120.         cp->obj = (Geom *)NULL;
  121.         cp->dotrans = FALSE;
  122.     }
  123.  
  124.     hitlist.nodes = 0;
  125.     if (!TraceRay(ray, &hitlist, SHADOW_EPSILON, &s)) {
  126.         /* Shadow ray didn't hit anything. */
  127.         *result = *color;
  128.         return FALSE;
  129.     }
  130.  
  131.     /*
  132.      * Otherwise, we've hit something.
  133.      */
  134.     ShadowHits++;
  135.  
  136.     /*
  137.      * If we're not worrying about transparent objects...
  138.      * This is ugly due to the fact that we have to find
  139.      * the surface associated with the object that was hit.
  140.      * GetShadingSurf() will always return a non-null value.
  141.      *
  142.      * ***NOTE**
  143.      * The transparency of the surface is checked below without
  144.      * applying textures, if any, to it.  This means that if
  145.      * an object may be made trasparent by a texture, its
  146.      * surface should have non-zero transparency *before* texturing
  147.      * as well.
  148.      */
  149.     if (!SHADOWTRANSP(ShadowOptions)) {
  150.         if (SHADOWCACHE(ShadowOptions))
  151.             LightCacheHit(&hitlist, cp);
  152.         return TRUE;
  153.     }
  154.  
  155.     /*
  156.      * We've hit a transparent object.  Attenuate the color of the light
  157.      * source and continue the ray until we hit background or a
  158.      * non-transparent object.  Note that this is incorrect if DefIndex or
  159.      * any of the indices of refraction of the surfaces differ.
  160.      */
  161.  
  162.     totaldist = 0.;
  163.     prevsurf = (Surface *)NULL;
  164.     res = *color;
  165.  
  166.     do {
  167.         /*
  168.          * Get a pointer to the surface to be used
  169.          * for shading...
  170.          */
  171.         sptr = GetShadingSurf(&hitlist);
  172.         if (sptr->transp < EPSILON) {
  173.             if (SHADOWCACHE(ShadowOptions))
  174.                 LightCacheHit(&hitlist, cp);
  175.             return TRUE;
  176.         }
  177.         /*
  178.          * Take specular transmission attenuation from
  179.          * previous intersection into account.
  180.          */
  181.         if (prevsurf) {
  182.             if (prevsurf->statten != 1.) {
  183.                 statten = pow(prevsurf->statten, s - totaldist);
  184.                 ColorScale(statten, res, &res);
  185.             }
  186.         }
  187.         /*
  188.          * Perform texturing and the like in case surface
  189.          * transparency is modulated.
  190.          */
  191.         /* copy the surface to be used... */
  192.         surf = *sptr;
  193.         enter = ComputeSurfProps(&hitlist, ray, &hitpos,
  194.             &norm, &gnorm, &surf, &smooth);
  195.         if (enter)
  196.             prevsurf = &surf;
  197.         else
  198.             prevsurf = (Surface *)NULL;
  199.         /*
  200.          * Attenuate light source by body color of surface.
  201.          */
  202.         ColorScale(surf.transp, res, &res);
  203.         ColorMultiply(res, surf.body, &res);
  204.         /*
  205.          * Return if attenuation becomes large.
  206.          * In this case, the light was attenuated to nothing,
  207.          * so we can't cache anything...
  208.          */
  209.         if (res.r < EPSILON && res.g < EPSILON && res.b < EPSILON)
  210.             return TRUE;
  211.         /*
  212.          * Min distance is previous max.
  213.          */
  214.         totaldist = s + EPSILON;
  215.         /*
  216.          * Max distance is dist to light source
  217.          */
  218.         s = dist;
  219.         /*
  220.          * Trace ray starting at new origin and in the
  221.          * same direction.
  222.          */
  223.         hitlist.nodes = 0;
  224.     } while (TraceRay(ray, &hitlist, totaldist, &s));
  225.  
  226.     *result = res;
  227.     return FALSE;
  228. }
  229.  
  230. void
  231. ShadowStats(shadowrays, shadowhit, cachehit, cachemiss)
  232. unsigned long *shadowrays, *shadowhit, *cachehit, *cachemiss;
  233. {
  234.     *shadowrays = ShadowRays;
  235.     *shadowhit = ShadowHits;
  236.     *cachehit = CacheHits;
  237.     *cachemiss = CacheMisses;
  238. }
  239.  
  240. void
  241. ShadowSetOptions(options)
  242. long options;
  243. {
  244.     ShadowOptions = options;
  245. }
  246.  
  247. void
  248. LightCacheHit(hitlist, cache)
  249. HitList *hitlist;
  250. ShadowCache *cache;
  251. {
  252.     HitNode *np;
  253.     int i, n;
  254.     extern long ShadowOptions;
  255.  
  256.     i = 0;
  257.  
  258.     if (SHADOWCSG(ShadowOptions)) {
  259.         /*
  260.          * There's possibly a CSG object in the
  261.          * hitlist, so we can't simply cache the
  262.          * primitive that was hit.  Find the
  263.          * object lowest in hit that's not part
  264.          * of a CSG object, and cache it.
  265.          */
  266.         i = FirstCSGGeom(hitlist);
  267.     }
  268.  
  269.     if (SHADOWBLUR(ShadowOptions)) {
  270.         /*
  271.          * Something might be animated --
  272.          * gotta cache the puppy.
  273.          */
  274.         n = FirstAnimatedGeom(hitlist);
  275.         if (n > i)
  276.             i = n;
  277.     }
  278.  
  279.     /*
  280.      * Compute total world-->cached object
  281.      * transformation and store in cache->trans.
  282.      */
  283.     /*
  284.      * Find the first transformation...
  285.      */
  286.     np = &hitlist->data[i];
  287.     cache->obj = np->obj;
  288.     /*
  289.      * If the cached object is animated, then we don't
  290.      * want to include the object's transformation(s)
  291.      * in cache->trans (it's taken care of in shadowed()
  292.      * by calling intersect).
  293.      */
  294.     if (cache->obj->animtrans) {
  295.         i++;
  296.         np++;
  297.     }
  298.     cache->dotrans = FALSE;
  299.     while (i < hitlist->nodes -1) {
  300.         if (np->obj->trans) {
  301.             if (cache->dotrans) {
  302.                 MatrixMult(
  303.                     &np->obj->trans->itrans,
  304.                     &cache->trans,
  305.                     &cache->trans);
  306.             } else {
  307.                 MatrixCopy(
  308.                     &np->obj->trans->itrans,
  309.                     &cache->trans);
  310.                 cache->dotrans = TRUE;
  311.             }
  312.         }
  313.         i++;
  314.         np++;
  315.     }
  316. }
  317.